From 6f3a2b709fbfcfdf7dc077b80b12f02463cc07b1 Mon Sep 17 00:00:00 2001 From: Italo Mandara Date: Tue, 4 Apr 2023 10:28:41 +0100 Subject: [PATCH 01/74] Allow to disable Explicit LOD Workaround --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 +- MoltenVK/MoltenVK/Utility/MVKEnvironment.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 3494740e7..f08070bd3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1645,7 +1645,7 @@ break; case kAppleVendorId: // TODO: Other GPUs? - _metalFeatures.needsSampleDrefLodArrayWorkaround = true; + MVK_SET_FROM_ENV_OR_BUILD_BOOL(_metalFeatures.needsSampleDrefLodArrayWorkaround, MVK_ENABLE_EXPLICIT_LOD_WORKAROUND); // fallthrough case kIntelVendorId: case kNVVendorId: diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h index cec1740e7..417a86f8b 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h @@ -294,3 +294,8 @@ void mvkSetConfig(const MVKConfiguration& mvkConfig); #ifndef MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM # define MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM MVK_CONFIG_COMPRESSION_ALGORITHM_NONE #endif + +/** Enables Explicit LOD workaround defaults to true. */ +#ifndef MVK_ENABLE_EXPLICIT_LOD_WORKAROUND +# define MVK_ENABLE_EXPLICIT_LOD_WORKAROUND 1 +#endif From 518385696b1f9fffdec60810c65757e87ae8dfd9 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 11 Apr 2023 20:41:59 -0400 Subject: [PATCH 02/74] Several simple maintenance fixes. - Fix memory leak when waiting on timeline semaphores. - For correctness, set VkPhysicalDeviceLimits::lineWidthGranularity to 1. - Update MoltenVK to version 1.2.4. - Update Whats_New.md document with recent changes. --- Docs/Whats_New.md | 15 +++++++++++++++ MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKSync.h | 2 ++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index ef3d3eb3d..33253589a 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -13,6 +13,21 @@ Copyright (c) 2015-2023 [The Brenwill Workshop Ltd.](http://www.brenwill.com) +MoltenVK 1.2.4 +-------------- + +Released TBD + +- Add support for extensions: + - `VK_KHR_map_memory2` +- Fix memory leak when waiting on timeline semaphores. +- Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively + disable recent fixes to handling LOD for arrayed depth images in shaders, + on Apple Silicon, when those fixes cause regression in rendering behavior. +- For correctness, set `VkPhysicalDeviceLimits::lineWidthGranularity` to `1`. + + + MoltenVK 1.2.3 -------------- diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index 44a5be5a4..6897f8434 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -51,7 +51,7 @@ typedef unsigned long MTLArgumentBuffersTier; */ #define MVK_VERSION_MAJOR 1 #define MVK_VERSION_MINOR 2 -#define MVK_VERSION_PATCH 3 +#define MVK_VERSION_PATCH 4 #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) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index f08070bd3..53a39d404 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2547,7 +2547,7 @@ _properties.limits.pointSizeGranularity = 1; _properties.limits.lineWidthRange[0] = 1; _properties.limits.lineWidthRange[1] = 1; - _properties.limits.lineWidthGranularity = 0; + _properties.limits.lineWidthGranularity = 1; _properties.limits.standardSampleLocations = VK_TRUE; _properties.limits.strictLines = _properties.vendorID == kIntelVendorId || _properties.vendorID == kNVVendorId; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h index c8d9da452..5dfe1d29c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h @@ -459,6 +459,8 @@ class MVKFenceSitter : public MVKBaseObject { MVKFenceSitter(bool waitAll) : _blocker(waitAll, 0) {} + ~MVKFenceSitter() override { [_listener release]; } + private: friend class MVKFence; friend class MVKTimelineSemaphoreMTLEvent; From 50923302730841fbb47ecd8a5dcb90968b1c9a66 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 12 Apr 2023 11:50:09 -0400 Subject: [PATCH 03/74] Support BC compression on iOS/tvOS, where available. - Add MVK_XCODE_14_3 macro to compile for iOS/tvOS 16.4 and above. - Add support for BC compression on iOS/tvOS 16.4 and above where supported. - Consolidate MVKPixelFormats::modifyMTLFormatCapabilities(mtlDev) and centralize querying MTLDevice format methods for all platforms. --- Common/MVKCommonEnvironment.h | 14 +- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 15 +-- .../MoltenVK/GPUObjects/MVKPixelFormats.mm | 122 +++++++++--------- 4 files changed, 74 insertions(+), 78 deletions(-) diff --git a/Common/MVKCommonEnvironment.h b/Common/MVKCommonEnvironment.h index ca6fe5239..c95992236 100644 --- a/Common/MVKCommonEnvironment.h +++ b/Common/MVKCommonEnvironment.h @@ -87,18 +87,22 @@ extern "C" { # define MVK_MACOS_APPLE_SILICON (MVK_MACOS && MVK_APPLE_SILICON) #endif -/** Building with Xcode versions. */ +/** Building with Xcode versions. iOS version also covers tvOS. */ +#ifndef MVK_XCODE_14_3 +# define MVK_XCODE_14_3 ((__MAC_OS_X_VERSION_MAX_ALLOWED >= 130300) || \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 160400)) +#endif #ifndef MVK_XCODE_14 # define MVK_XCODE_14 ((__MAC_OS_X_VERSION_MAX_ALLOWED >= 130000) || \ - (__IPHONE_OS_VERSION_MAX_ALLOWED >= 160000)) // Also covers tvOS + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 160000)) #endif #ifndef MVK_XCODE_13 # define MVK_XCODE_13 ((__MAC_OS_X_VERSION_MAX_ALLOWED >= 120000) || \ - (__IPHONE_OS_VERSION_MAX_ALLOWED >= 150000)) // Also covers tvOS + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 150000)) #endif #ifndef MVK_XCODE_12 -# define MVK_XCODE_12 ((__MAC_OS_X_VERSION_MAX_ALLOWED >= 101600) || \ - (__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000)) // Also covers tvOS +# define MVK_XCODE_12 ((__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000) || \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000)) #endif /** Directive to identify public symbols. */ diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 33253589a..01d6be494 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -20,6 +20,7 @@ Released TBD - Add support for extensions: - `VK_KHR_map_memory2` +- Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). - Fix memory leak when waiting on timeline semaphores. - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively disable recent fixes to handling LOD for arrayed depth images in shaders, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 53a39d404..794804e9d 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -4763,20 +4763,13 @@ uint64_t mvkGetRegistryID(id mtlDevice) { return [mtlDevice respondsToSelector: @selector(registryID)] ? mtlDevice.registryID : 0; } -// Since MacCatalyst does not support supportsBCTextureCompression, it is not possible -// for Apple Silicon to indicate a lack of support for BCn when running MacCatalyst. -// Therefore, assume for now that this means MacCatalyst does not actually support BCn. -// Further evidence may change this approach. +// If the supportsBCTextureCompression query is available, use it. +// Otherwise only macOS supports BC compression. bool mvkSupportsBCTextureCompression(id mtlDevice) { -#if MVK_IOS || MVK_TVOS || MVK_MACCAT - return false; -#endif -#if MVK_MACOS && !MVK_MACCAT -#if MVK_XCODE_12 +#if MVK_XCODE_14_3 || (MVK_XCODE_12 && MVK_MACOS && !MVK_MACCAT) if ([mtlDevice respondsToSelector: @selector(supportsBCTextureCompression)]) { return mtlDevice.supportsBCTextureCompression; } #endif - return true; -#endif + return MVK_MACOS && !MVK_MACCAT; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index 39a2ad8f0..a4e0313c7 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -109,24 +109,26 @@ #endif #if MVK_IOS_OR_TVOS -# define MTLPixelFormatDepth24Unorm_Stencil8 MTLPixelFormatInvalid -# define MTLPixelFormatX24_Stencil8 MTLPixelFormatInvalid -# define MTLPixelFormatBC1_RGBA MTLPixelFormatInvalid -# define MTLPixelFormatBC1_RGBA_sRGB MTLPixelFormatInvalid -# define MTLPixelFormatBC2_RGBA MTLPixelFormatInvalid -# define MTLPixelFormatBC2_RGBA_sRGB MTLPixelFormatInvalid -# define MTLPixelFormatBC3_RGBA MTLPixelFormatInvalid -# define MTLPixelFormatBC3_RGBA_sRGB MTLPixelFormatInvalid -# define MTLPixelFormatBC4_RUnorm MTLPixelFormatInvalid -# define MTLPixelFormatBC4_RSnorm MTLPixelFormatInvalid -# define MTLPixelFormatBC5_RGUnorm MTLPixelFormatInvalid -# define MTLPixelFormatBC5_RGSnorm MTLPixelFormatInvalid -# define MTLPixelFormatBC6H_RGBUfloat MTLPixelFormatInvalid -# define MTLPixelFormatBC6H_RGBFloat MTLPixelFormatInvalid -# define MTLPixelFormatBC7_RGBAUnorm MTLPixelFormatInvalid -# define MTLPixelFormatBC7_RGBAUnorm_sRGB MTLPixelFormatInvalid +# if !MVK_XCODE_14_3 // iOS/tvOS 16.4 +# define MTLPixelFormatBC1_RGBA MTLPixelFormatInvalid +# define MTLPixelFormatBC1_RGBA_sRGB MTLPixelFormatInvalid +# define MTLPixelFormatBC2_RGBA MTLPixelFormatInvalid +# define MTLPixelFormatBC2_RGBA_sRGB MTLPixelFormatInvalid +# define MTLPixelFormatBC3_RGBA MTLPixelFormatInvalid +# define MTLPixelFormatBC3_RGBA_sRGB MTLPixelFormatInvalid +# define MTLPixelFormatBC4_RUnorm MTLPixelFormatInvalid +# define MTLPixelFormatBC4_RSnorm MTLPixelFormatInvalid +# define MTLPixelFormatBC5_RGUnorm MTLPixelFormatInvalid +# define MTLPixelFormatBC5_RGSnorm MTLPixelFormatInvalid +# define MTLPixelFormatBC6H_RGBUfloat MTLPixelFormatInvalid +# define MTLPixelFormatBC6H_RGBFloat MTLPixelFormatInvalid +# define MTLPixelFormatBC7_RGBAUnorm MTLPixelFormatInvalid +# define MTLPixelFormatBC7_RGBAUnorm_sRGB MTLPixelFormatInvalid +# endif # define MTLPixelFormatDepth16Unorm_Stencil8 MTLPixelFormatDepth32Float_Stencil8 +# define MTLPixelFormatDepth24Unorm_Stencil8 MTLPixelFormatInvalid +# define MTLPixelFormatX24_Stencil8 MTLPixelFormatInvalid #endif #if MVK_TVOS @@ -1217,20 +1219,20 @@ addMTLPixelFormatDescSRGB( ASTC_12x12_sRGB, ASTC_12x12, None, None, ASTC_12x12_LDR ); addMTLPixelFormatDesc ( ASTC_12x12_HDR, ASTC_12x12, None, None ); - addMTLPixelFormatDesc ( BC1_RGBA, BC1_RGBA, None, RF ); - addMTLPixelFormatDescSRGB( BC1_RGBA_sRGB, BC1_RGBA, None, RF, BC1_RGBA ); - addMTLPixelFormatDesc ( BC2_RGBA, BC2_RGBA, None, RF ); - addMTLPixelFormatDescSRGB( BC2_RGBA_sRGB, BC2_RGBA, None, RF, BC2_RGBA ); - addMTLPixelFormatDesc ( BC3_RGBA, BC3_RGBA, None, RF ); - addMTLPixelFormatDescSRGB( BC3_RGBA_sRGB, BC3_RGBA, None, RF, BC3_RGBA ); - addMTLPixelFormatDesc ( BC4_RUnorm, BC4_R, None, RF ); - addMTLPixelFormatDesc ( BC4_RSnorm, BC4_R, None, RF ); - addMTLPixelFormatDesc ( BC5_RGUnorm, BC5_RG, None, RF ); - addMTLPixelFormatDesc ( BC5_RGSnorm, BC5_RG, None, RF ); - addMTLPixelFormatDesc ( BC6H_RGBUfloat, BC6H_RGB, None, RF ); - addMTLPixelFormatDesc ( BC6H_RGBFloat, BC6H_RGB, None, RF ); - addMTLPixelFormatDesc ( BC7_RGBAUnorm, BC7_RGBA, None, RF ); - addMTLPixelFormatDescSRGB( BC7_RGBAUnorm_sRGB, BC7_RGBA, None, RF, BC7_RGBAUnorm ); + addMTLPixelFormatDesc ( BC1_RGBA, BC1_RGBA, RF, RF ); + addMTLPixelFormatDescSRGB( BC1_RGBA_sRGB, BC1_RGBA, RF, RF, BC1_RGBA ); + addMTLPixelFormatDesc ( BC2_RGBA, BC2_RGBA, RF, RF ); + addMTLPixelFormatDescSRGB( BC2_RGBA_sRGB, BC2_RGBA, RF, RF, BC2_RGBA ); + addMTLPixelFormatDesc ( BC3_RGBA, BC3_RGBA, RF, RF ); + addMTLPixelFormatDescSRGB( BC3_RGBA_sRGB, BC3_RGBA, RF, RF, BC3_RGBA ); + addMTLPixelFormatDesc ( BC4_RUnorm, BC4_R, RF, RF ); + addMTLPixelFormatDesc ( BC4_RSnorm, BC4_R, RF, RF ); + addMTLPixelFormatDesc ( BC5_RGUnorm, BC5_RG, RF, RF ); + addMTLPixelFormatDesc ( BC5_RGSnorm, BC5_RG, RF, RF ); + addMTLPixelFormatDesc ( BC6H_RGBUfloat, BC6H_RGB, RF, RF ); + addMTLPixelFormatDesc ( BC6H_RGBFloat, BC6H_RGB, RF, RF ); + addMTLPixelFormatDesc ( BC7_RGBAUnorm, BC7_RGBA, RF, RF ); + addMTLPixelFormatDescSRGB( BC7_RGBAUnorm_sRGB, BC7_RGBA, RF, RF, BC7_RGBAUnorm ); // YUV pixel formats addMTLPixelFormatDesc ( GBGR422, None, RF, RF ); @@ -1477,20 +1479,23 @@ addMTLVertexFormatCapabilities(mtlDevice, MTLGPUFamily ##GPU_FAM, OS_VER, MTLVertexFormat ##MTL_FMT, kMVKMTLFmtCaps ##CAPS) // Modifies the format capability tables based on the capabilities of the specific MTLDevice -#if MVK_MACOS void MVKPixelFormats::modifyMTLFormatCapabilities(id mtlDevice) { - - addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v1, R32Uint, Atomic ); - addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v1, R32Sint, Atomic ); - - if (mtlDevice.isDepth24Stencil8PixelFormatSupported) { - addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v1, Depth24Unorm_Stencil8, DRFMR ); + if ( !mvkSupportsBCTextureCompression(mtlDevice) ) { + disableAllMTLPixFmtCaps( BC1_RGBA ); + disableAllMTLPixFmtCaps( BC1_RGBA_sRGB ); + disableAllMTLPixFmtCaps( BC2_RGBA ); + disableAllMTLPixFmtCaps( BC2_RGBA_sRGB ); + disableAllMTLPixFmtCaps( BC3_RGBA ); + disableAllMTLPixFmtCaps( BC3_RGBA_sRGB ); + disableAllMTLPixFmtCaps( BC4_RUnorm ); + disableAllMTLPixFmtCaps( BC4_RSnorm ); + disableAllMTLPixFmtCaps( BC5_RGUnorm ); + disableAllMTLPixFmtCaps( BC5_RGSnorm ); + disableAllMTLPixFmtCaps( BC6H_RGBUfloat ); + disableAllMTLPixFmtCaps( BC6H_RGBFloat ); + disableAllMTLPixFmtCaps( BC7_RGBAUnorm ); + disableAllMTLPixFmtCaps( BC7_RGBAUnorm_sRGB ); } - - addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v2, Depth16Unorm, DRFMR ); - - addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v3, BGR10A2Unorm, RFCMRB ); - #if MVK_XCODE_12 if ([mtlDevice respondsToSelector: @selector(supports32BitMSAA)] && !mtlDevice.supports32BitMSAA) { @@ -1522,24 +1527,21 @@ disableMTLPixFmtCaps( RG32Float, Filter ); disableMTLPixFmtCaps( RGBA32Float, Filter ); } +#endif - if ( !mvkSupportsBCTextureCompression(mtlDevice) ) { - disableAllMTLPixFmtCaps( BC1_RGBA ); - disableAllMTLPixFmtCaps( BC1_RGBA_sRGB ); - disableAllMTLPixFmtCaps( BC2_RGBA ); - disableAllMTLPixFmtCaps( BC2_RGBA_sRGB ); - disableAllMTLPixFmtCaps( BC3_RGBA ); - disableAllMTLPixFmtCaps( BC3_RGBA_sRGB ); - disableAllMTLPixFmtCaps( BC4_RUnorm ); - disableAllMTLPixFmtCaps( BC4_RSnorm ); - disableAllMTLPixFmtCaps( BC5_RGUnorm ); - disableAllMTLPixFmtCaps( BC5_RGSnorm ); - disableAllMTLPixFmtCaps( BC6H_RGBUfloat ); - disableAllMTLPixFmtCaps( BC6H_RGBFloat ); - disableAllMTLPixFmtCaps( BC7_RGBAUnorm ); - disableAllMTLPixFmtCaps( BC7_RGBAUnorm_sRGB ); +#if MVK_MACOS + addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v1, R32Uint, Atomic ); + addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v1, R32Sint, Atomic ); + + if (mtlDevice.isDepth24Stencil8PixelFormatSupported) { + addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v1, Depth24Unorm_Stencil8, DRFMR ); } + addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v2, Depth16Unorm, DRFMR ); + + addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v3, BGR10A2Unorm, RFCMRB ); + +#if MVK_XCODE_12 addGPUOSMTLPixFmtCaps( Apple5, 10.16, R8Unorm_sRGB, All ); addGPUOSMTLPixFmtCaps( Apple5, 10.16, RG8Unorm_sRGB, All ); @@ -1632,11 +1634,9 @@ addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, Short, Vertex ); addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, Half, Vertex ); addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, UChar4Normalized_BGRA, Vertex ); -} #endif #if MVK_TVOS -void MVKPixelFormats::modifyMTLFormatCapabilities(id mtlDevice) { addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v2, R8Unorm_sRGB, All ); addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, R8Unorm_sRGB, All ); @@ -1774,11 +1774,9 @@ disableMTLPixFmtCaps(ASTC_12x12_sRGB, Write); } #endif -} #endif #if MVK_IOS -void MVKPixelFormats::modifyMTLFormatCapabilities(id mtlDevice) { addFeatSetMTLPixFmtCaps( iOS_GPUFamily2_v3, R8Unorm_sRGB, All ); addFeatSetMTLPixFmtCaps( iOS_GPUFamily3_v1, R8Unorm_sRGB, All ); @@ -1933,8 +1931,8 @@ disableMTLPixFmtCaps(ASTC_12x12_sRGB, Write); } #endif -} #endif +} #undef addFeatSetMTLPixFmtCaps #undef addGPUOSMTLPixFmtCaps From b0e6df67761cc15484cea52fc789d60877896f6a Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 12 Apr 2023 12:05:38 -0400 Subject: [PATCH 04/74] Replace references to macOS 10.16 with 11.0, and standardize use of whitespace in MVKPixelFormats::modifyMTLFormatCapabilities(). --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 +- .../MoltenVK/GPUObjects/MVKPixelFormats.mm | 372 +++++++++--------- 2 files changed, 187 insertions(+), 187 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 794804e9d..6f2dbe789 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2093,7 +2093,7 @@ // and a wider combination of GPU's on older macOS versions is under way. #if MVK_MACOS _metalFeatures.descriptorSetArgumentBuffers = (_metalFeatures.argumentBuffers && - (mvkOSVersionIsAtLeast(10.16) || + (mvkOSVersionIsAtLeast(11.0) || _properties.vendorID == kIntelVendorId)); #endif // Currently, if we don't support descriptor set argument buffers, we can't support argument buffers. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index a4e0313c7..79f1dffa9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -1452,10 +1452,10 @@ // Mac Catalyst does not support feature sets, so we redefine them to GPU families in MVKDevice.h. #if MVK_MACCAT #define addFeatSetMTLPixFmtCaps(FEAT_SET, MTL_FMT, CAPS) \ - addMTLPixelFormatCapabilities(mtlDevice, MTLFeatureSet_ ##FEAT_SET, 10.16, MTLPixelFormat ##MTL_FMT, kMVKMTLFmtCaps ##CAPS) + addMTLPixelFormatCapabilities(mtlDevice, MTLFeatureSet_ ##FEAT_SET, 11.0, MTLPixelFormat ##MTL_FMT, kMVKMTLFmtCaps ##CAPS) #define addFeatSetMTLVtxFmtCaps(FEAT_SET, MTL_FMT, CAPS) \ - addMTLVertexFormatCapabilities(mtlDevice, MTLFeatureSet_ ##FEAT_SET, 10.16, MTLVertexFormat ##MTL_FMT, kMVKMTLFmtCaps ##CAPS) + addMTLVertexFormatCapabilities(mtlDevice, MTLFeatureSet_ ##FEAT_SET, 11.0, MTLVertexFormat ##MTL_FMT, kMVKMTLFmtCaps ##CAPS) #else #define addFeatSetMTLPixFmtCaps(FEAT_SET, MTL_FMT, CAPS) \ @@ -1542,86 +1542,86 @@ addFeatSetMTLPixFmtCaps( macOS_GPUFamily1_v3, BGR10A2Unorm, RFCMRB ); #if MVK_XCODE_12 - addGPUOSMTLPixFmtCaps( Apple5, 10.16, R8Unorm_sRGB, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, R8Unorm_sRGB, All ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, RG8Unorm_sRGB, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, RG8Unorm_sRGB, All ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, B5G6R5Unorm, RFCMRB ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, A1BGR5Unorm, RFCMRB ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ABGR4Unorm, RFCMRB ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, BGR5A1Unorm, RFCMRB ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, B5G6R5Unorm, RFCMRB ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, A1BGR5Unorm, RFCMRB ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ABGR4Unorm, RFCMRB ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, BGR5A1Unorm, RFCMRB ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, RGBA8Unorm_sRGB, All ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, BGRA8Unorm_sRGB, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, RGBA8Unorm_sRGB, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, BGRA8Unorm_sRGB, All ); // Blending is actually supported for this format, but format channels cannot be individually write-enabled during blending. // Disabling blending is the least-intrusive way to handle this in a Vulkan-friendly way. - addGPUOSMTLPixFmtCaps( Apple5, 10.16, RGB9E5Float, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, RGB9E5Float, All ); disableMTLPixFmtCaps ( RGB9E5Float, Blend); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, PVRTC_RGBA_2BPP, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, PVRTC_RGBA_2BPP_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, PVRTC_RGBA_4BPP, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, PVRTC_RGBA_4BPP_sRGB, RF ); - - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ETC2_RGB8, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ETC2_RGB8_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ETC2_RGB8A1, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ETC2_RGB8A1_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, EAC_RGBA8, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, EAC_RGBA8_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, EAC_R11Unorm, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, EAC_R11Snorm, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, EAC_RG11Unorm, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, EAC_RG11Snorm, RF ); - - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_4x4_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_4x4_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_4x4_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_5x4_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_5x4_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_5x4_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_5x5_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_5x5_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_5x5_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_6x5_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_6x5_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_6x5_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_6x6_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_6x6_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_6x6_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_8x5_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_8x5_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_8x5_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_8x6_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_8x6_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_8x6_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_8x8_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_8x8_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_8x8_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_10x5_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_10x5_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_10x5_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_10x6_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_10x6_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_10x6_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_10x8_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_10x8_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_10x8_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_10x10_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_10x10_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_10x10_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_12x10_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_12x10_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_12x10_HDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_12x12_LDR, RF ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, ASTC_12x12_sRGB, RF ); - addGPUOSMTLPixFmtCaps( Apple6, 10.16, ASTC_12x12_HDR, RF ); - - addGPUOSMTLPixFmtCaps( Apple5, 10.16, BGRA10_XR, All ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, BGRA10_XR_sRGB, All ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, BGR10_XR, All ); - addGPUOSMTLPixFmtCaps( Apple5, 10.16, BGR10_XR_sRGB, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, PVRTC_RGBA_2BPP, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, PVRTC_RGBA_2BPP_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, PVRTC_RGBA_4BPP, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, PVRTC_RGBA_4BPP_sRGB, RF ); + + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ETC2_RGB8, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ETC2_RGB8_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ETC2_RGB8A1, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ETC2_RGB8A1_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, EAC_RGBA8, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, EAC_RGBA8_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, EAC_R11Unorm, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, EAC_R11Snorm, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, EAC_RG11Unorm, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, EAC_RG11Snorm, RF ); + + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_4x4_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_4x4_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_4x4_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_5x4_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_5x4_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_5x4_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_5x5_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_5x5_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_5x5_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_6x5_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_6x5_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_6x5_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_6x6_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_6x6_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_6x6_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_8x5_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_8x5_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_8x5_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_8x6_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_8x6_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_8x6_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_8x8_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_8x8_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_8x8_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_10x5_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_10x5_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_10x5_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_10x6_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_10x6_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_10x6_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_10x8_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_10x8_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_10x8_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_10x10_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_10x10_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_10x10_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_12x10_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_12x10_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_12x10_HDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_12x12_LDR, RF ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, ASTC_12x12_sRGB, RF ); + addGPUOSMTLPixFmtCaps( Apple6, 11.0, ASTC_12x12_HDR, RF ); + + addGPUOSMTLPixFmtCaps( Apple5, 11.0, BGRA10_XR, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, BGRA10_XR_sRGB, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, BGR10_XR, All ); + addGPUOSMTLPixFmtCaps( Apple5, 11.0, BGR10_XR_sRGB, All ); #endif addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, UCharNormalized, Vertex ); @@ -1675,43 +1675,43 @@ addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, RGBA32Sint, RWC ); addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, RGBA32Float, RWC ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_4x4_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_4x4_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_5x4_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_5x4_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_5x5_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_5x5_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_6x5_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_6x5_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_6x6_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_6x6_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_8x5_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_8x5_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_8x6_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_8x6_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_8x8_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_8x8_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_10x5_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_10x5_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_10x6_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_10x6_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_10x8_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_10x8_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_10x10_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_10x10_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_12x10_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_12x10_sRGB, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_12x12_LDR, RF ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily1_v1, ASTC_12x12_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_4x4_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_4x4_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_5x4_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_5x4_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_5x5_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_5x5_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_6x5_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_6x5_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_6x6_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_6x6_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_8x5_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_8x5_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_8x6_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_8x6_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_8x8_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_8x8_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_10x5_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_10x5_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_10x6_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_10x6_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_10x8_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_10x8_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_10x10_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_10x10_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_12x10_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_12x10_sRGB, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_12x12_LDR, RF ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily1_v1, ASTC_12x12_sRGB, RF ); addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, Depth32Float, DRMR ); addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, Depth32Float_Stencil8, DRMR ); addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, Stencil8, DRMR ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily2_v1, BGRA10_XR, All ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily2_v1, BGRA10_XR_sRGB, All ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily2_v1, BGR10_XR, All ); - addFeatSetMTLPixFmtCaps(tvOS_GPUFamily2_v1, BGR10_XR_sRGB, All ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, BGRA10_XR, All ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, BGRA10_XR_sRGB, All ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, BGR10_XR, All ); + addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, BGR10_XR_sRGB, All ); addGPUOSMTLPixFmtCaps( Apple1, 13.0, Depth16Unorm, DRFM ); addGPUOSMTLPixFmtCaps( Apple3, 13.0, Depth16Unorm, DRFMR ); @@ -1732,46 +1732,46 @@ #if MVK_OS_SIMULATOR if (!([mtlDevice respondsToSelector: @selector(supportsFamily:)] && [mtlDevice supportsFamily: MTLGPUFamilyApple5])) { - disableAllMTLPixFmtCaps(R8Unorm_sRGB); - disableAllMTLPixFmtCaps(RG8Unorm_sRGB); - disableAllMTLPixFmtCaps(B5G6R5Unorm); - disableAllMTLPixFmtCaps(A1BGR5Unorm); - disableAllMTLPixFmtCaps(ABGR4Unorm); - disableAllMTLPixFmtCaps(BGR5A1Unorm); - - disableAllMTLPixFmtCaps(BGRA10_XR); - disableAllMTLPixFmtCaps(BGRA10_XR_sRGB); - disableAllMTLPixFmtCaps(BGR10_XR); - disableAllMTLPixFmtCaps(BGR10_XR_sRGB); - - disableAllMTLPixFmtCaps(GBGR422); - disableAllMTLPixFmtCaps(BGRG422); - - disableMTLPixFmtCaps(RGB9E5Float, ColorAtt); - - disableMTLPixFmtCaps(R8Unorm_sRGB, Write); - disableMTLPixFmtCaps(RG8Unorm_sRGB, Write); - disableMTLPixFmtCaps(RGBA8Unorm_sRGB, Write); - disableMTLPixFmtCaps(BGRA8Unorm_sRGB, Write); - disableMTLPixFmtCaps(PVRTC_RGBA_2BPP_sRGB, Write); - disableMTLPixFmtCaps(PVRTC_RGBA_4BPP_sRGB, Write); - disableMTLPixFmtCaps(ETC2_RGB8_sRGB, Write); - disableMTLPixFmtCaps(ETC2_RGB8A1_sRGB, Write); - disableMTLPixFmtCaps(EAC_RGBA8_sRGB, Write); - disableMTLPixFmtCaps(ASTC_4x4_sRGB, Write); - disableMTLPixFmtCaps(ASTC_5x4_sRGB, Write); - disableMTLPixFmtCaps(ASTC_5x5_sRGB, Write); - disableMTLPixFmtCaps(ASTC_6x5_sRGB, Write); - disableMTLPixFmtCaps(ASTC_6x6_sRGB, Write); - disableMTLPixFmtCaps(ASTC_8x5_sRGB, Write); - disableMTLPixFmtCaps(ASTC_8x6_sRGB, Write); - disableMTLPixFmtCaps(ASTC_8x8_sRGB, Write); - disableMTLPixFmtCaps(ASTC_10x5_sRGB, Write); - disableMTLPixFmtCaps(ASTC_10x6_sRGB, Write); - disableMTLPixFmtCaps(ASTC_10x8_sRGB, Write); - disableMTLPixFmtCaps(ASTC_10x10_sRGB, Write); - disableMTLPixFmtCaps(ASTC_12x10_sRGB, Write); - disableMTLPixFmtCaps(ASTC_12x12_sRGB, Write); + disableAllMTLPixFmtCaps( R8Unorm_sRGB ); + disableAllMTLPixFmtCaps( RG8Unorm_sRGB ); + disableAllMTLPixFmtCaps( B5G6R5Unorm ); + disableAllMTLPixFmtCaps( A1BGR5Unorm ); + disableAllMTLPixFmtCaps( ABGR4Unorm ); + disableAllMTLPixFmtCaps( BGR5A1Unorm ); + + disableAllMTLPixFmtCaps( BGRA10_XR ); + disableAllMTLPixFmtCaps( BGRA10_XR_sRGB ); + disableAllMTLPixFmtCaps( BGR10_XR ); + disableAllMTLPixFmtCaps( BGR10_XR_sRGB ); + + disableAllMTLPixFmtCaps( GBGR422 ); + disableAllMTLPixFmtCaps( BGRG422 ); + + disableMTLPixFmtCaps( RGB9E5Float, ColorAtt ); + + disableMTLPixFmtCaps( R8Unorm_sRGB, Write ); + disableMTLPixFmtCaps( RG8Unorm_sRGB, Write ); + disableMTLPixFmtCaps( RGBA8Unorm_sRGB, Write ); + disableMTLPixFmtCaps( BGRA8Unorm_sRGB, Write ); + disableMTLPixFmtCaps( PVRTC_RGBA_2BPP_sRGB, Write ); + disableMTLPixFmtCaps( PVRTC_RGBA_4BPP_sRGB, Write ); + disableMTLPixFmtCaps( ETC2_RGB8_sRGB, Write ); + disableMTLPixFmtCaps( ETC2_RGB8A1_sRGB, Write ); + disableMTLPixFmtCaps( EAC_RGBA8_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_4x4_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_5x4_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_5x5_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_6x5_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_6x6_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_8x5_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_8x6_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_8x8_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_10x5_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_10x6_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_10x8_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_10x10_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_12x10_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_12x12_sRGB, Write ); } #endif #endif @@ -1889,46 +1889,46 @@ #if MVK_OS_SIMULATOR if (!([mtlDevice respondsToSelector: @selector(supportsFamily:)] && [mtlDevice supportsFamily: MTLGPUFamilyApple5])) { - disableAllMTLPixFmtCaps(R8Unorm_sRGB); - disableAllMTLPixFmtCaps(RG8Unorm_sRGB); - disableAllMTLPixFmtCaps(B5G6R5Unorm); - disableAllMTLPixFmtCaps(A1BGR5Unorm); - disableAllMTLPixFmtCaps(ABGR4Unorm); - disableAllMTLPixFmtCaps(BGR5A1Unorm); - - disableAllMTLPixFmtCaps(BGRA10_XR); - disableAllMTLPixFmtCaps(BGRA10_XR_sRGB); - disableAllMTLPixFmtCaps(BGR10_XR); - disableAllMTLPixFmtCaps(BGR10_XR_sRGB); - - disableAllMTLPixFmtCaps(GBGR422); - disableAllMTLPixFmtCaps(BGRG422); - - disableMTLPixFmtCaps(RGB9E5Float, ColorAtt); - - disableMTLPixFmtCaps(R8Unorm_sRGB, Write); - disableMTLPixFmtCaps(RG8Unorm_sRGB, Write); - disableMTLPixFmtCaps(RGBA8Unorm_sRGB, Write); - disableMTLPixFmtCaps(BGRA8Unorm_sRGB, Write); - disableMTLPixFmtCaps(PVRTC_RGBA_2BPP_sRGB, Write); - disableMTLPixFmtCaps(PVRTC_RGBA_4BPP_sRGB, Write); - disableMTLPixFmtCaps(ETC2_RGB8_sRGB, Write); - disableMTLPixFmtCaps(ETC2_RGB8A1_sRGB, Write); - disableMTLPixFmtCaps(EAC_RGBA8_sRGB, Write); - disableMTLPixFmtCaps(ASTC_4x4_sRGB, Write); - disableMTLPixFmtCaps(ASTC_5x4_sRGB, Write); - disableMTLPixFmtCaps(ASTC_5x5_sRGB, Write); - disableMTLPixFmtCaps(ASTC_6x5_sRGB, Write); - disableMTLPixFmtCaps(ASTC_6x6_sRGB, Write); - disableMTLPixFmtCaps(ASTC_8x5_sRGB, Write); - disableMTLPixFmtCaps(ASTC_8x6_sRGB, Write); - disableMTLPixFmtCaps(ASTC_8x8_sRGB, Write); - disableMTLPixFmtCaps(ASTC_10x5_sRGB, Write); - disableMTLPixFmtCaps(ASTC_10x6_sRGB, Write); - disableMTLPixFmtCaps(ASTC_10x8_sRGB, Write); - disableMTLPixFmtCaps(ASTC_10x10_sRGB, Write); - disableMTLPixFmtCaps(ASTC_12x10_sRGB, Write); - disableMTLPixFmtCaps(ASTC_12x12_sRGB, Write); + disableAllMTLPixFmtCaps( R8Unorm_sRGB ); + disableAllMTLPixFmtCaps( RG8Unorm_sRGB ); + disableAllMTLPixFmtCaps( B5G6R5Unorm ); + disableAllMTLPixFmtCaps( A1BGR5Unorm ); + disableAllMTLPixFmtCaps( ABGR4Unorm ); + disableAllMTLPixFmtCaps( BGR5A1Unorm ); + + disableAllMTLPixFmtCaps( BGRA10_XR ); + disableAllMTLPixFmtCaps( BGRA10_XR_sRGB ); + disableAllMTLPixFmtCaps( BGR10_XR ); + disableAllMTLPixFmtCaps( BGR10_XR_sRGB ); + + disableAllMTLPixFmtCaps( GBGR422 ); + disableAllMTLPixFmtCaps( BGRG422 ); + + disableMTLPixFmtCaps( RGB9E5Float, ColorAtt ); + + disableMTLPixFmtCaps( R8Unorm_sRGB, Write ); + disableMTLPixFmtCaps( RG8Unorm_sRGB, Write ); + disableMTLPixFmtCaps( RGBA8Unorm_sRGB, Write ); + disableMTLPixFmtCaps( BGRA8Unorm_sRGB, Write ); + disableMTLPixFmtCaps( PVRTC_RGBA_2BPP_sRGB, Write ); + disableMTLPixFmtCaps( PVRTC_RGBA_4BPP_sRGB, Write ); + disableMTLPixFmtCaps( ETC2_RGB8_sRGB, Write ); + disableMTLPixFmtCaps( ETC2_RGB8A1_sRGB, Write ); + disableMTLPixFmtCaps( EAC_RGBA8_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_4x4_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_5x4_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_5x5_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_6x5_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_6x6_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_8x5_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_8x6_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_8x8_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_10x5_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_10x6_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_10x8_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_10x10_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_12x10_sRGB, Write ); + disableMTLPixFmtCaps( ASTC_12x12_sRGB, Write ); } #endif #endif From 13e8103651e5a32c7c607cf95a734cbf88c4e764 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Fri, 14 Apr 2023 17:30:32 -0400 Subject: [PATCH 05/74] Ensure shaders using PhysicalStorageBufferAddresses encode the associated MTLBuffer. - MVKDevice track VkBuffers marked with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT. - Add SPIRVToMSLConversionResultInfo::usesPhysicalStorageBufferAddressesCapability to detect and track shaders that use PhysicalStorageBufferAddresses capability, and track such shader stages within pipeline. - MVKResourcesCommandEncoderState encode usage of VkBuffers marked with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT when pipeline uses PhysicalStorageBufferAddresses capability. - Rename MVKResourcesCommandEncoderState::encodeArgumentBufferResourceUsage() to encodeResourceUsage(). - MVKDevice move some functions to public scope and remove friend classes. - MVKDeviceMemory ensure _vkMemAllocFlags is always initialized (unrelated). - Rename MVKFoundation template method contains() to mvkContains() (unrelated). --- Docs/Whats_New.md | 1 + .../Commands/MVKCommandEncoderState.h | 26 ++--- .../Commands/MVKCommandEncoderState.mm | 28 +++-- MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm | 20 ++-- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 34 ++++-- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 104 +++++++++++------- .../MoltenVK/GPUObjects/MVKDeviceMemory.mm | 5 +- MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 11 ++ MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 24 +++- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 2 +- .../SPIRVToMSLConverter.cpp | 13 +++ .../SPIRVToMSLConverter.h | 2 + 13 files changed, 180 insertions(+), 92 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 01d6be494..f22472d77 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -22,6 +22,7 @@ Released TBD - `VK_KHR_map_memory2` - Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). - Fix memory leak when waiting on timeline semaphores. +- Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively disable recent fixes to handling LOD for arrayed depth images in shaders, on Apple Silicon, when those fixes cause regression in rendering behavior. diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 8667aabf3..9caca16c7 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -355,11 +355,11 @@ class MVKResourcesCommandEncoderState : public MVKCommandEncoderState { MVKArrayRef dynamicOffsets, uint32_t& dynamicOffsetIndex); - /** Encodes the Metal resource to the Metal command encoder. */ - virtual void encodeArgumentBufferResourceUsage(MVKShaderStage stage, - id mtlResource, - MTLResourceUsage mtlUsage, - MTLRenderStages mtlStages) = 0; + /** Encodes the indirect use of the Metal resource to the Metal command encoder. */ + virtual void encodeResourceUsage(MVKShaderStage stage, + id mtlResource, + MTLResourceUsage mtlUsage, + MTLRenderStages mtlStages) = 0; void markDirty() override; @@ -548,10 +548,10 @@ class MVKGraphicsResourcesCommandEncoderState : public MVKResourcesCommandEncode std::function bindTexture, std::function bindSampler); - void encodeArgumentBufferResourceUsage(MVKShaderStage stage, - id mtlResource, - MTLResourceUsage mtlUsage, - MTLRenderStages mtlStages) override; + void encodeResourceUsage(MVKShaderStage stage, + id mtlResource, + MTLResourceUsage mtlUsage, + MTLRenderStages mtlStages) override; /** Offset all buffers for vertex attribute bindings with zero divisors by the given number of strides. */ void offsetZeroDivisorVertexBuffers(MVKGraphicsStage stage, MVKGraphicsPipeline* pipeline, uint32_t firstInstance); @@ -609,10 +609,10 @@ class MVKComputeResourcesCommandEncoderState : public MVKResourcesCommandEncoder /** Sets the current dynamic offset buffer state. */ void bindDynamicOffsetBuffer(const MVKShaderImplicitRezBinding& binding, bool needDynamicOffsetBuffer); - void encodeArgumentBufferResourceUsage(MVKShaderStage stage, - id mtlResource, - MTLResourceUsage mtlUsage, - MTLRenderStages mtlStages) override; + void encodeResourceUsage(MVKShaderStage stage, + id mtlResource, + MTLResourceUsage mtlUsage, + MTLRenderStages mtlStages) override; /** * Marks the buffer binding using the index as having been overridden, diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index d8fc5d210..c1f7b4c02 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -693,6 +693,11 @@ encodeMetalArgumentBuffer(stage); + MVKPipeline* pipeline = getPipeline(); + if (pipeline && pipeline->usesPhysicalStorageBufferAddressesCapability(stage)) { + getDevice()->encodeGPUAddressableBuffers(this, stage); + } + auto& shaderStage = _shaderStageResourceBindings[stage]; if (shaderStage.swizzleBufferBinding.isDirty) { @@ -963,10 +968,10 @@ bindBuffer(stage, buffBind); } -void MVKGraphicsResourcesCommandEncoderState::encodeArgumentBufferResourceUsage(MVKShaderStage stage, - id mtlResource, - MTLResourceUsage mtlUsage, - MTLRenderStages mtlStages) { +void MVKGraphicsResourcesCommandEncoderState::encodeResourceUsage(MVKShaderStage stage, + id mtlResource, + MTLResourceUsage mtlUsage, + MTLRenderStages mtlStages) { if (mtlResource && mtlStages) { if (stage == kMVKShaderStageTessCtl) { auto* mtlCompEnc = _cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl); @@ -1039,8 +1044,10 @@ encodeMetalArgumentBuffer(kMVKShaderStageCompute); - MVKPipeline* pipeline = getPipeline(); - bool fullImageViewSwizzle = pipeline ? pipeline->fullImageViewSwizzle() : false; + MVKPipeline* pipeline = getPipeline(); + if (pipeline && pipeline->usesPhysicalStorageBufferAddressesCapability(kMVKShaderStageCompute)) { + getDevice()->encodeGPUAddressableBuffers(this, kMVKShaderStageCompute); + } if (_resourceBindings.swizzleBufferBinding.isDirty) { for (auto& b : _resourceBindings.textureBindings) { @@ -1053,6 +1060,7 @@ _resourceBindings.swizzleBufferBinding.index); } else { + bool fullImageViewSwizzle = pipeline ? pipeline->fullImageViewSwizzle() : false; assertMissingSwizzles(_resourceBindings.needsSwizzle && !fullImageViewSwizzle, "compute", _resourceBindings.textureBindings.contents()); } @@ -1116,10 +1124,10 @@ bindBuffer(buffBind); } -void MVKComputeResourcesCommandEncoderState::encodeArgumentBufferResourceUsage(MVKShaderStage stage, - id mtlResource, - MTLResourceUsage mtlUsage, - MTLRenderStages mtlStages) { +void MVKComputeResourcesCommandEncoderState::encodeResourceUsage(MVKShaderStage stage, + id mtlResource, + MTLResourceUsage mtlUsage, + MTLRenderStages mtlStages) { if (mtlResource) { auto* mtlCompEnc = _cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch); [mtlCompEnc useResource: mtlResource usage: mtlUsage]; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm index 172fb0366..c13296d20 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm @@ -786,10 +786,8 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s atIndex: argIdx]; } if (encodeUsage) { - rezEncState->encodeArgumentBufferResourceUsage(stage, - _mvkBuffer ? _mvkBuffer->getMTLBuffer() : nil, - getMTLResourceUsage(), - mvkDSLBind->getMTLRenderStages()); + id mtlBuffer = _mvkBuffer ? _mvkBuffer->getMTLBuffer() : nil; + rezEncState->encodeResourceUsage(stage, mtlBuffer, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); } } @@ -876,10 +874,8 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s atIndex: argIdx]; } if (encodeUsage) { - rezEncState->encodeArgumentBufferResourceUsage(stage, - _mvkMTLBufferAllocation ? _mvkMTLBufferAllocation->_mtlBuffer : nil, - getMTLResourceUsage(), - mvkDSLBind->getMTLRenderStages()); + id mtlBuffer = _mvkMTLBufferAllocation ? _mvkMTLBufferAllocation->_mtlBuffer : nil; + rezEncState->encodeResourceUsage(stage, mtlBuffer, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); } } @@ -994,7 +990,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s [mtlArgEncoder setTexture: mtlTexture atIndex: argIdx]; } if (encodeUsage) { - rezEncState->encodeArgumentBufferResourceUsage(stage, mtlTexture, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); + rezEncState->encodeResourceUsage(stage, mtlTexture, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); } if (descType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { id mtlTex = mtlTexture.parentTexture ? mtlTexture.parentTexture : mtlTexture; @@ -1005,7 +1001,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s [mtlArgEncoder setBuffer: mtlBuff offset: mtlTex.bufferOffset atIndex: argIdx]; } if (encodeUsage) { - rezEncState->encodeArgumentBufferResourceUsage(stage, mtlBuff, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); + rezEncState->encodeResourceUsage(stage, mtlBuff, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); } } } @@ -1294,7 +1290,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s [mtlArgEncoder setTexture: mtlTexture atIndex: argIdx]; } if (encodeUsage) { - rezEncState->encodeArgumentBufferResourceUsage(stage, mtlTexture, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); + rezEncState->encodeResourceUsage(stage, mtlTexture, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); } if (descType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { @@ -1305,7 +1301,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s [mtlArgEncoder setBuffer: mtlBuff offset: mtlTexture.bufferOffset atIndex: argIdx]; } if (encodeUsage) { - rezEncState->encodeArgumentBufferResourceUsage(stage, mtlBuff, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); + rezEncState->encodeResourceUsage(stage, mtlBuff, getMTLResourceUsage(), mvkDSLBind->getMTLRenderStages()); } } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 22f8649eb..5eddac115 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -63,6 +63,7 @@ class MVKSamplerYcbcrConversion; class MVKDescriptorSetLayout; class MVKDescriptorPool; class MVKDescriptorUpdateTemplate; +class MVKResourcesCommandEncoderState; class MVKFramebuffer; class MVKRenderPass; class MVKCommandPool; @@ -660,6 +661,22 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { #pragma mark Operations + /** Tell the GPU to be ready to use any of the GPU-addressable buffers. */ + void encodeGPUAddressableBuffers(MVKResourcesCommandEncoderState* rezEncState, + MVKShaderStage stage); + + /** Adds the specified host semaphore to be woken upon device loss. */ + void addSemaphore(MVKSemaphoreImpl* sem4); + + /** Removes the specified host semaphore. */ + void removeSemaphore(MVKSemaphoreImpl* sem4); + + /** Adds the specified timeline semaphore to be woken at the specified value upon device loss. */ + void addTimelineSemaphore(MVKTimelineSemaphore* sem4, uint64_t value); + + /** Removes the specified timeline semaphore. */ + void removeTimelineSemaphore(MVKTimelineSemaphore* sem4, uint64_t value); + /** Applies the specified global memory barrier to all resource issued by this device. */ void applyMemoryBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, @@ -855,19 +872,11 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { } protected: - friend class MVKSemaphoreEmulated; - friend class MVKTimelineSemaphoreMTLEvent; - friend class MVKTimelineSemaphoreEmulated; - friend class MVKFence; - friend class MVKEventEmulated; - void propagateDebugName() override {} - MVKResource* addResource(MVKResource* rez); - MVKResource* removeResource(MVKResource* rez); - void addSemaphore(MVKSemaphoreImpl* sem4); - void removeSemaphore(MVKSemaphoreImpl* sem4); - void addTimelineSemaphore(MVKTimelineSemaphore* sem4, uint64_t value); - void removeTimelineSemaphore(MVKTimelineSemaphore* sem4, uint64_t value); + MVKBuffer* addBuffer(MVKBuffer* mvkBuff); + MVKBuffer* removeBuffer(MVKBuffer* mvkBuff); + MVKImage* addImage(MVKImage* mvkImg); + MVKImage* removeImage(MVKImage* mvkImg); void initPerformanceTracking(); void initPhysicalDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo); void initQueues(const VkDeviceCreateInfo* pCreateInfo); @@ -887,6 +896,7 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { MVKCommandResourceFactory* _commandResourceFactory = nullptr; MVKSmallVector, kMVKQueueFamilyCount> _queuesByQueueFamilyIndex; MVKSmallVector _resources; + MVKSmallVector _gpuAddressableBuffers; MVKSmallVector _privateDataSlots; MVKSmallVector _privateDataSlotsAvailability; MVKSmallVector _awaitingSemaphores; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 6f2dbe789..3251449c5 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -3545,15 +3545,14 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope MVKBuffer* MVKDevice::createBuffer(const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator) { - return (MVKBuffer*)addResource(new MVKBuffer(this, pCreateInfo)); + return addBuffer(new MVKBuffer(this, pCreateInfo)); } void MVKDevice::destroyBuffer(MVKBuffer* mvkBuff, const VkAllocationCallbacks* pAllocator) { - if (mvkBuff) { - removeResource(mvkBuff); - mvkBuff->destroy(); - } + if ( !mvkBuff ) { return; } + removeBuffer(mvkBuff); + mvkBuff->destroy(); } MVKBufferView* MVKDevice::createBufferView(const VkBufferViewCreateInfo* pCreateInfo, @@ -3582,20 +3581,14 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope MVKImage* mvkImg = (swapchainInfo) ? new MVKPeerSwapchainImage(this, pCreateInfo, (MVKSwapchain*)swapchainInfo->swapchain, uint32_t(-1)) : new MVKImage(this, pCreateInfo); - for (auto& memoryBinding : mvkImg->_memoryBindings) { - addResource(memoryBinding); - } - return mvkImg; + return addImage(mvkImg); } void MVKDevice::destroyImage(MVKImage* mvkImg, const VkAllocationCallbacks* pAllocator) { - if (mvkImg) { - for (auto& memoryBinding : mvkImg->_memoryBindings) { - removeResource(memoryBinding); - } - mvkImg->destroy(); - } + if ( !mvkImg ) { return; } + removeImage(mvkImg); + mvkImg->destroy(); } MVKImageView* MVKDevice::createImageView(const VkImageViewCreateInfo* pCreateInfo, @@ -3636,22 +3629,16 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope MVKSwapchain* swapchain, uint32_t swapchainIndex, const VkAllocationCallbacks* pAllocator) { - MVKPresentableSwapchainImage* mvkImg = new MVKPresentableSwapchainImage(this, pCreateInfo, - swapchain, swapchainIndex); - for (auto& memoryBinding : mvkImg->_memoryBindings) { - addResource(memoryBinding); - } - return mvkImg; + auto* pImg = new MVKPresentableSwapchainImage(this, pCreateInfo, swapchain, swapchainIndex); + addImage(pImg); + return pImg; } void MVKDevice::destroyPresentableSwapchainImage(MVKPresentableSwapchainImage* mvkImg, const VkAllocationCallbacks* pAllocator) { - if (mvkImg) { - for (auto& memoryBinding : mvkImg->_memoryBindings) { - removeResource(memoryBinding); - } - mvkImg->destroy(); - } + if ( !mvkImg ) { return; } + removeImage(mvkImg); + mvkImg->destroy(); } MVKFence* MVKDevice::createFence(const VkFenceCreateInfo* pCreateInfo, @@ -3987,42 +3974,79 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope mvkPDS->destroy(); } - #pragma mark Operations -// Adds the specified resource for tracking, and returns the added resource. -MVKResource* MVKDevice::addResource(MVKResource* rez) { +// If the underlying MTLBuffer is referenced in a shader only via its gpuAddress, +// the GPU might not be aware that the MTLBuffer needs to be made resident. +// Track the buffer as needing to be made resident if a shader is bound that uses +// PhysicalStorageBufferAddresses to access the contents of the underlying MTLBuffer. +MVKBuffer* MVKDevice::addBuffer(MVKBuffer* mvkBuff) { + if ( !mvkBuff ) { return mvkBuff; } + + lock_guard lock(_rezLock); + _resources.push_back(mvkBuff); + if (mvkIsAnyFlagEnabled(mvkBuff->getUsage(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)) { + _gpuAddressableBuffers.push_back(mvkBuff); + } + return mvkBuff; +} + +MVKBuffer* MVKDevice::removeBuffer(MVKBuffer* mvkBuff) { + if ( !mvkBuff ) { return mvkBuff; } + lock_guard lock(_rezLock); - _resources.push_back(rez); - return rez; + mvkRemoveFirstOccurance(_resources, mvkBuff); + if (mvkIsAnyFlagEnabled(mvkBuff->getUsage(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)) { + mvkRemoveFirstOccurance(_gpuAddressableBuffers, mvkBuff); + } + return mvkBuff; +} + +void MVKDevice::encodeGPUAddressableBuffers(MVKResourcesCommandEncoderState* rezEncState, MVKShaderStage stage) { + MTLResourceUsage mtlUsage = MTLResourceUsageRead | MTLResourceUsageWrite; + MTLRenderStages mtlRendStage = (stage == kMVKShaderStageFragment) ? MTLRenderStageFragment : MTLRenderStageVertex; + + lock_guard lock(_rezLock); + for (auto& buff : _gpuAddressableBuffers) { + rezEncState->encodeResourceUsage(stage, buff->getMTLBuffer(), mtlUsage, mtlRendStage); + } } -// Removes the specified resource for tracking and returns the removed resource. -MVKResource* MVKDevice::removeResource(MVKResource* rez) { +MVKImage* MVKDevice::addImage(MVKImage* mvkImg) { + if ( !mvkImg ) { return mvkImg; } + lock_guard lock(_rezLock); - mvkRemoveFirstOccurance(_resources, rez); - return rez; + for (auto& mb : mvkImg->_memoryBindings) { + _resources.push_back(mb); + } + return mvkImg; +} + +MVKImage* MVKDevice::removeImage(MVKImage* mvkImg) { + if ( !mvkImg ) { return mvkImg; } + + lock_guard lock(_rezLock); + for (auto& mb : mvkImg->_memoryBindings) { + mvkRemoveFirstOccurance(_resources, mb); + } + return mvkImg; } -// Adds the specified host semaphore to be woken upon device loss. void MVKDevice::addSemaphore(MVKSemaphoreImpl* sem4) { lock_guard lock(_sem4Lock); _awaitingSemaphores.push_back(sem4); } -// Removes the specified host semaphore. void MVKDevice::removeSemaphore(MVKSemaphoreImpl* sem4) { lock_guard lock(_sem4Lock); mvkRemoveFirstOccurance(_awaitingSemaphores, sem4); } -// Adds the specified timeline semaphore to be woken at the specified value upon device loss. void MVKDevice::addTimelineSemaphore(MVKTimelineSemaphore* sem4, uint64_t value) { lock_guard lock(_sem4Lock); _awaitingTimelineSem4s.emplace_back(sem4, value); } -// Removes the specified timeline semaphore. void MVKDevice::removeTimelineSemaphore(MVKTimelineSemaphore* sem4, uint64_t value) { lock_guard lock(_sem4Lock); mvkRemoveFirstOccurance(_awaitingTimelineSem4s, make_pair(sem4, value)); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm index e7e97ea9f..76bc37c5a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm @@ -160,7 +160,7 @@ // If a dedicated alloc, ensure this image is the one and only image // I am dedicated to. If my image is aliasable, though, allow other aliasable // images to bind to me. - if (_isDedicated && (_imageMemoryBindings.empty() || !(contains(_imageMemoryBindings, mvkImg) || (_imageMemoryBindings[0]->_image->getIsAliasable() && mvkImg->_image->getIsAliasable()))) ) { + if (_isDedicated && (_imageMemoryBindings.empty() || !(mvkContains(_imageMemoryBindings, mvkImg) || (_imageMemoryBindings[0]->_image->getIsAliasable() && mvkImg->_image->getIsAliasable()))) ) { return reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not bind VkImage %p to a VkDeviceMemory dedicated to resource %p. A dedicated allocation may only be used with the resource it was dedicated to.", mvkImg, getDedicatedResource() ); } @@ -180,7 +180,7 @@ if (_mtlHeap) { return true; } - // Can't create a MTLHeap on a imported memory + // Can't create a MTLHeap on imported memory if (_isHostMemImported) { return true; } // Don't bother if we don't have placement heaps. @@ -284,6 +284,7 @@ const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator) : MVKVulkanAPIDeviceObject(device) { // Set Metal memory parameters + _vkMemAllocFlags = 0; _vkMemPropFlags = _device->_pMemoryProperties->memoryTypes[pAllocateInfo->memoryTypeIndex].propertyFlags; _mtlStorageMode = mvkMTLStorageModeFromVkMemoryPropertyFlags(_vkMemPropFlags); _mtlCPUCacheMode = mvkMTLCPUCacheModeFromVkMemoryPropertyFlags(_vkMemPropFlags); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 19822de6a..3fa4dce76 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -63,7 +63,7 @@ offset: memoryBinding->getDeviceMemoryOffset() + _subresources[0].layout.offset]; if (_image->_isAliasable) { [_mtlTexture makeAliasable]; } } else if (_image->_isAliasable && dvcMem && dvcMem->isDedicatedAllocation() && - !contains(dvcMem->_imageMemoryBindings, memoryBinding)) { + !mvkContains(dvcMem->_imageMemoryBindings, memoryBinding)) { // This is a dedicated allocation, but it belongs to another aliasable image. // In this case, use the MTLTexture from the memory's dedicated image. // We know the other image must be aliasable, or I couldn't have been bound diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index caffd5c24..8d09b87ea 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -164,6 +164,9 @@ class MVKPipeline : public MVKVulkanAPIDeviceObject { mvkIsAnyFlagEnabled(_flags, VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT)); } + /** Returns whether the shader for the stage uses physical storage buffer addresses. */ + virtual bool usesPhysicalStorageBufferAddressesCapability(MVKShaderStage stage) = 0; + /** Constructs an instance for the device. layout, and parent (which may be NULL). */ MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipelineLayout* layout, VkPipelineCreateFlags flags, MVKPipeline* parent); @@ -270,6 +273,8 @@ class MVKGraphicsPipeline : public MVKPipeline { /** Returns whether this pipeline has custom sample positions enabled. */ bool isUsingCustomSamplePositions() { return _isUsingCustomSamplePositions; } + bool usesPhysicalStorageBufferAddressesCapability(MVKShaderStage stage) override; + /** * Returns whether the MTLBuffer vertex shader buffer index is valid for a stage of this pipeline. * It is if it is a descriptor binding within the descriptor binding range, @@ -338,6 +343,8 @@ class MVKGraphicsPipeline : public MVKPipeline { MVKMTLFunction getMTLFunction(SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pShaderStage, const char* pStageName); + void markIfUsingPhysicalStorageBufferAddressesCapability(SPIRVToMSLConversionResultInfo& resultsInfo, + MVKShaderStage stage); const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr; const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr; @@ -356,6 +363,7 @@ class MVKGraphicsPipeline : public MVKPipeline { MVKSmallVector _zeroDivisorVertexBindings; MVKSmallVector _mtlArgumentEncoders; MVKSmallVector _descriptorBindingUse; + MVKSmallVector _stagesUsingPhysicalStorageBufferAddressesCapability; MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil; id _mtlTessVertexFunctions[3] = {nil, nil, nil}; @@ -425,6 +433,8 @@ class MVKComputePipeline : public MVKPipeline { /** Returns the array of descriptor binding use for the descriptor set. */ MVKBitArray& getDescriptorBindingUse(uint32_t descSetIndex, MVKShaderStage stage) override { return _descriptorBindingUse[descSetIndex]; } + bool usesPhysicalStorageBufferAddressesCapability(MVKShaderStage stage) override; + /** Constructs an instance for the device and parent (which may be NULL). */ MVKComputePipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, @@ -446,6 +456,7 @@ class MVKComputePipeline : public MVKPipeline { bool _needsDynamicOffsetBuffer = false; bool _needsDispatchBaseBuffer = false; bool _allowsDispatchBase = false; + bool _usesPhysicalStorageBufferAddressesCapability = false; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 652699ac2..e24e24e8d 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -929,6 +929,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 _needsVertexDynamicOffsetBuffer = funcRslts.needsDynamicOffsetBuffer; _needsVertexViewRangeBuffer = funcRslts.needsViewRangeBuffer; _needsVertexOutputBuffer = funcRslts.needsOutputBuffer; + markIfUsingPhysicalStorageBufferAddressesCapability(funcRslts, kMVKShaderStageVertex); addMTLArgumentEncoders(func, pCreateInfo, shaderConfig, kMVKShaderStageVertex); @@ -998,6 +999,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 _needsVertexBufferSizeBuffer = funcRslts.needsBufferSizeBuffer; _needsVertexDynamicOffsetBuffer = funcRslts.needsDynamicOffsetBuffer; _needsVertexOutputBuffer = funcRslts.needsOutputBuffer; + markIfUsingPhysicalStorageBufferAddressesCapability(funcRslts, kMVKShaderStageVertex); } addMTLArgumentEncoders(func, pCreateInfo, shaderConfig, kMVKShaderStageVertex); @@ -1057,6 +1059,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 _needsTessCtlOutputBuffer = funcRslts.needsOutputBuffer; _needsTessCtlPatchOutputBuffer = funcRslts.needsPatchOutputBuffer; _needsTessCtlInputBuffer = funcRslts.needsInputThreadgroupMem; + markIfUsingPhysicalStorageBufferAddressesCapability(funcRslts, kMVKShaderStageTessCtl); addMTLArgumentEncoders(func, pCreateInfo, shaderConfig, kMVKShaderStageTessCtl); @@ -1113,6 +1116,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 _needsTessEvalSwizzleBuffer = funcRslts.needsSwizzleBuffer; _needsTessEvalBufferSizeBuffer = funcRslts.needsBufferSizeBuffer; _needsTessEvalDynamicOffsetBuffer = funcRslts.needsDynamicOffsetBuffer; + markIfUsingPhysicalStorageBufferAddressesCapability(funcRslts, kMVKShaderStageTessEval); addMTLArgumentEncoders(func, pCreateInfo, shaderConfig, kMVKShaderStageTessEval); @@ -1170,6 +1174,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 _needsFragmentBufferSizeBuffer = funcRslts.needsBufferSizeBuffer; _needsFragmentDynamicOffsetBuffer = funcRslts.needsDynamicOffsetBuffer; _needsFragmentViewRangeBuffer = funcRslts.needsViewRangeBuffer; + markIfUsingPhysicalStorageBufferAddressesCapability(funcRslts, kMVKShaderStageFragment); addMTLArgumentEncoders(func, pCreateInfo, shaderConfig, kMVKShaderStageFragment); @@ -1804,6 +1809,17 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 return func; } +void MVKGraphicsPipeline::markIfUsingPhysicalStorageBufferAddressesCapability(SPIRVToMSLConversionResultInfo& resultsInfo, + MVKShaderStage stage) { + if (resultsInfo.usesPhysicalStorageBufferAddressesCapability) { + _stagesUsingPhysicalStorageBufferAddressesCapability.push_back(stage); + } +} + +bool MVKGraphicsPipeline::usesPhysicalStorageBufferAddressesCapability(MVKShaderStage stage) { + return mvkContains(_stagesUsingPhysicalStorageBufferAddressesCapability, stage); +} + MVKGraphicsPipeline::~MVKGraphicsPipeline() { @synchronized (getMTLDevice()) { [_mtlTessVertexStageDesc release]; @@ -1952,6 +1968,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 _needsBufferSizeBuffer = funcRslts.needsBufferSizeBuffer; _needsDynamicOffsetBuffer = funcRslts.needsDynamicOffsetBuffer; _needsDispatchBaseBuffer = funcRslts.needsDispatchBaseBuffer; + _usesPhysicalStorageBufferAddressesCapability = funcRslts.usesPhysicalStorageBufferAddressesCapability; addMTLArgumentEncoders(func, pCreateInfo, shaderConfig, kMVKShaderStageCompute); @@ -1962,6 +1979,10 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 return _device->_pMetalFeatures->maxPerStageBufferCount - (bufferIndexOffset + 1); } +bool MVKComputePipeline::usesPhysicalStorageBufferAddressesCapability(MVKShaderStage stage) { + return _usesPhysicalStorageBufferAddressesCapability; +} + MVKComputePipeline::~MVKComputePipeline() { @synchronized (getMTLDevice()) { [_mtlPipelineState release]; @@ -2428,7 +2449,8 @@ void serialize(Archive & archive, SPIRVToMSLConversionResultInfo& scr) { scr.needsDynamicOffsetBuffer, scr.needsInputThreadgroupMem, scr.needsDispatchBaseBuffer, - scr.needsViewRangeBuffer); + scr.needsViewRangeBuffer, + scr.usesPhysicalStorageBufferAddressesCapability); } } diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index 58b85d150..a0c96742b 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -484,7 +484,7 @@ void mvkReleaseContainerContents(C& container) { /** Returns whether the container contains an item equal to the value. */ template -bool contains(C& container, const T& val) { +bool mvkContains(C& container, const T& val) { for (const T& cVal : container) { if (cVal == val) { return true; } } return false; } diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp index f1672e2ba..b95b704db 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp +++ b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp @@ -366,6 +366,7 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConversionConfigur conversionResult.resultInfo.needsInputThreadgroupMem = pMSLCompiler && pMSLCompiler->needs_input_threadgroup_mem(); conversionResult.resultInfo.needsDispatchBaseBuffer = pMSLCompiler && pMSLCompiler->needs_dispatch_base_buffer(); conversionResult.resultInfo.needsViewRangeBuffer = pMSLCompiler && pMSLCompiler->needs_view_mask_buffer(); + conversionResult.resultInfo.usesPhysicalStorageBufferAddressesCapability = usesPhysicalStorageBufferAddressesCapability(pMSLCompiler); // When using Metal argument buffers, if the shader is provided with dynamic buffer offsets, // then it needs a buffer to hold these dynamic offsets. @@ -533,3 +534,15 @@ void SPIRVToMSLConverter::populateEntryPoint(Compiler* pCompiler, populateWorkgroupDimension(wgSize.height, spvEP.workgroup_size.y, heightSC); populateWorkgroupDimension(wgSize.depth, spvEP.workgroup_size.z, depthSC); } + +bool SPIRVToMSLConverter::usesPhysicalStorageBufferAddressesCapability(Compiler* pCompiler) { + if (pCompiler) { + auto& declaredCapabilities = pCompiler->get_declared_capabilities(); + for(auto dc: declaredCapabilities) { + if (dc == CapabilityPhysicalStorageBufferAddresses) { + return true; + } + } + } + return false; +} diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.h index 765e110ff..1789ee93c 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.h +++ b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.h @@ -244,6 +244,7 @@ namespace mvk { bool needsInputThreadgroupMem = false; bool needsDispatchBaseBuffer = false; bool needsViewRangeBuffer = false; + bool usesPhysicalStorageBufferAddressesCapability = false; } SPIRVToMSLConversionResultInfo; @@ -300,6 +301,7 @@ namespace mvk { void writeSPIRVToFile(std::string spvFilepath, std::string& log); void populateWorkgroupDimension(SPIRVWorkgroupSizeDimension& wgDim, uint32_t size, SPIRV_CROSS_NAMESPACE::SpecializationConstant& spvSpecConst); void populateEntryPoint(SPIRV_CROSS_NAMESPACE::Compiler* pCompiler, SPIRVToMSLConversionOptions& options, SPIRVEntryPoint& entryPoint); + bool usesPhysicalStorageBufferAddressesCapability(SPIRV_CROSS_NAMESPACE::Compiler* pCompiler); std::vector _spirv; }; From fc8e8182ee29a160f3373089cc800db5dac40889 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 24 Apr 2023 15:01:41 -0400 Subject: [PATCH 06/74] Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 2 ++ MoltenVK/MoltenVK/Utility/MVKCodec.mm | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index f22472d77..9c3154162 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -23,6 +23,7 @@ Released TBD - Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). - Fix memory leak when waiting on timeline semaphores. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. +- Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively disable recent fixes to handling LOD for arrayed depth images in shaders, on Apple Silicon, when those fixes cause regression in rendering behavior. diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index 6897f8434..7f770fce1 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -906,6 +906,8 @@ typedef struct { * 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. * diff --git a/MoltenVK/MoltenVK/Utility/MVKCodec.mm b/MoltenVK/MoltenVK/Utility/MVKCodec.mm index 7c07d6afd..49a8e6607 100644 --- a/MoltenVK/MoltenVK/Utility/MVKCodec.mm +++ b/MoltenVK/MoltenVK/Utility/MVKCodec.mm @@ -148,7 +148,9 @@ static size_t mvkCompressDecompress(const uint8_t* srcBytes, size_t srcSize, MVKConfigCompressionAlgorithm compAlgo, bool isCompressing) { size_t dstByteCount = 0; - if (compAlgo != MVK_CONFIG_COMPRESSION_ALGORITHM_NONE) { + bool compressionSupported = ([NSData instancesRespondToSelector: @selector(compressedDataUsingAlgorithm:error:)] && + [NSData instancesRespondToSelector: @selector(decompressedDataUsingAlgorithm:error:)]); + if (compressionSupported && compAlgo != MVK_CONFIG_COMPRESSION_ALGORITHM_NONE) { @autoreleasepool { NSDataCompressionAlgorithm sysCompAlgo = getSystemCompressionAlgo(compAlgo); NSData* srcData = [NSData dataWithBytesNoCopy: (void*)srcBytes length: srcSize freeWhenDone: NO]; From 4aa2b6dd9f5dab46f9a18a7e32ee9e1b02ed6889 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 24 Apr 2023 15:23:46 -0400 Subject: [PATCH 07/74] Support separate depth and stencil attachments during dynamic rendering. - MVKRenderSubpass add separate getDepthFormat() & getStencilFormat(), and isDepthAttachmentUsed() & isStencilAttachmentUsed() and use instead of testing pixel format for depth and stencil components. - Add MVKRenderingAttachmentIterator class to consistently iterate, and take actions, on the attachments in VkRenderingInfo to create synthetic MVKRenderPass and extract image views and clear colors. - Remove mvkCreateRenderPass() and mvkCreateFramebuffer() in favor of additional constructors, and remove mvkGetDepthStencilFormat() in favor of retrieving formats for separate depth and stencil attachments. - MVKRenderpass constructors reorganize order of adding attachments and subpasses, and connecting the two. - Renmame MVKRenderPassAttachment to MVKAttachmentDescription. - MVKPipeline reorganize member variables to minimize gaps in content and remove unnecessary _isRasterizingDepthStencil member var (unrelated). --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 20 +- .../MoltenVK/Commands/MVKCommandBuffer.mm | 20 +- .../Commands/MVKCommandEncoderState.mm | 7 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 4 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 10 + MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h | 11 +- .../MoltenVK/GPUObjects/MVKFramebuffer.mm | 54 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 18 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 27 +- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h | 98 ++- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm | 777 +++++++++--------- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 2 +- 13 files changed, 514 insertions(+), 535 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index f22472d77..7bdc87dbf 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -21,6 +21,7 @@ Released TBD - Add support for extensions: - `VK_KHR_map_memory2` - Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). +- Support separate depth and stencil attachments during dynamic rendering. - Fix memory leak when waiting on timeline semaphores. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index d72df15ee..0aa57b31f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1446,21 +1446,17 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma // The depth value (including vertex position Z value) is held in the last index. clearColors[kMVKClearAttachmentDepthStencilIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal }; - VkFormat vkAttFmt = subpass->getDepthStencilFormat(); - MTLPixelFormat mtlAttFmt = pixFmts->getMTLPixelFormat(vkAttFmt); - _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlAttFmt; - - bool isClearingDepth = _isClearingDepth && pixFmts->isDepthFormat(mtlAttFmt); - bool isClearingStencil = _isClearingStencil && pixFmts->isStencilFormat(mtlAttFmt); - if (!isClearingDepth && !isClearingStencil) { - // If the subpass attachment isn't actually used, don't try to clear it. + bool isClearingDepth = _isClearingDepth && subpass->isDepthAttachmentUsed(); + bool isClearingStencil = _isClearingStencil && subpass->isStencilAttachmentUsed(); + if (isClearingDepth) { + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getDepthFormat()); + } else if (isClearingStencil) { + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getStencilFormat()); + } else { _rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex); } - if (!_rpsKey.isAnyAttachmentEnabled()) { - // Nothing to do. - return; - } + if ( !_rpsKey.isAnyAttachmentEnabled() ) { return; } // Render the clear colors to the attachments MVKCommandEncodingPool* cmdEncPool = cmdEncoder->getCommandEncodingPool(); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index c42056850..5155a141e 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -401,10 +401,17 @@ ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE); - uint32_t maxAttCnt = (pRenderingInfo->colorAttachmentCount + 1) * 2; - MVKImageView* attachments[maxAttCnt]; + uint32_t maxAttCnt = (pRenderingInfo->colorAttachmentCount + 2) * 2; + MVKImageView* imageViews[maxAttCnt]; VkClearValue clearValues[maxAttCnt]; - uint32_t attCnt = mvkGetAttachments(pRenderingInfo, attachments, clearValues); + + uint32_t attCnt = 0; + MVKRenderingAttachmentIterator attIter(pRenderingInfo); + attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { + imageViews[attCnt] = (MVKImageView*)(isResolveAttachment ? pAttInfo->resolveImageView : pAttInfo->imageView); + clearValues[attCnt] = pAttInfo->clearValue; + attCnt++; + }); // If we're resuming a suspended renderpass, continue to use the existing renderpass // (with updated rendering flags) and framebuffer. Otherwise, create new transient @@ -419,13 +426,14 @@ mvkRP->setRenderingFlags(pRenderingInfo->flags); mvkFB = _pEncodingContext->getFramebuffer(); } else { - mvkRP = mvkCreateRenderPass(getDevice(), pRenderingInfo); - mvkFB = mvkCreateFramebuffer(getDevice(), pRenderingInfo, mvkRP); + auto* mvkDev = getDevice(); + mvkRP = mvkDev->createRenderPass(pRenderingInfo, nullptr); + mvkFB = mvkDev->createFramebuffer(pRenderingInfo, nullptr); } beginRenderpass(rendCmd, contents, mvkRP, mvkFB, pRenderingInfo->renderArea, MVKArrayRef(clearValues, attCnt), - MVKArrayRef(attachments, attCnt), + MVKArrayRef(imageViews, attCnt), MVKArrayRef>(), kMVKCommandUseBeginRendering); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index c1f7b4c02..0262d47db 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -328,15 +328,12 @@ MVKCommandEncoderState::beginMetalRenderPass(); MVKRenderSubpass* mvkSubpass = _cmdEncoder->getSubpass(); - MVKPixelFormats* pixFmts = _cmdEncoder->getPixelFormats(); - MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkSubpass->getDepthStencilFormat()); - bool prevHasDepthAttachment = _hasDepthAttachment; - _hasDepthAttachment = pixFmts->isDepthFormat(mtlDSFormat); + _hasDepthAttachment = mvkSubpass->isDepthAttachmentUsed(); if (_hasDepthAttachment != prevHasDepthAttachment) { markDirty(); } bool prevHasStencilAttachment = _hasStencilAttachment; - _hasStencilAttachment = pixFmts->isStencilFormat(mtlDSFormat); + _hasStencilAttachment = mvkSubpass->isStencilAttachmentUsed(); if (_hasStencilAttachment != prevHasStencilAttachment) { markDirty(); } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 5eddac115..b02cc7784 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -631,6 +631,8 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { MVKFramebuffer* createFramebuffer(const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator); + MVKFramebuffer* createFramebuffer(const VkRenderingInfo* pRenderingInfo, + const VkAllocationCallbacks* pAllocator); void destroyFramebuffer(MVKFramebuffer* mvkFB, const VkAllocationCallbacks* pAllocator); @@ -638,6 +640,8 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { const VkAllocationCallbacks* pAllocator); MVKRenderPass* createRenderPass(const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator); + MVKRenderPass* createRenderPass(const VkRenderingInfo* pRenderingInfo, + const VkAllocationCallbacks* pAllocator); void destroyRenderPass(MVKRenderPass* mvkRP, const VkAllocationCallbacks* pAllocator); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 3251449c5..8cdca02bd 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -3893,6 +3893,11 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope return new MVKFramebuffer(this, pCreateInfo); } +MVKFramebuffer* MVKDevice::createFramebuffer(const VkRenderingInfo* pRenderingInfo, + const VkAllocationCallbacks* pAllocator) { + return new MVKFramebuffer(this, pRenderingInfo); +} + void MVKDevice::destroyFramebuffer(MVKFramebuffer* mvkFB, const VkAllocationCallbacks* pAllocator) { if (mvkFB) { mvkFB->destroy(); } @@ -3908,6 +3913,11 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope return new MVKRenderPass(this, pCreateInfo); } +MVKRenderPass* MVKDevice::createRenderPass(const VkRenderingInfo* pRenderingInfo, + const VkAllocationCallbacks* pAllocator) { + return new MVKRenderPass(this, pRenderingInfo); +} + void MVKDevice::destroyRenderPass(MVKRenderPass* mvkRP, const VkAllocationCallbacks* pAllocator) { if (mvkRP) { mvkRP->destroy(); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h index ec9b3fdfa..d5e9c469c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h @@ -58,6 +58,8 @@ class MVKFramebuffer : public MVKVulkanAPIDeviceObject { MVKFramebuffer(MVKDevice* device, const VkFramebufferCreateInfo* pCreateInfo); + MVKFramebuffer(MVKDevice* device, const VkRenderingInfo* pRenderingInfo); + ~MVKFramebuffer() override; protected: @@ -69,12 +71,3 @@ class MVKFramebuffer : public MVKVulkanAPIDeviceObject { VkExtent2D _extent; uint32_t _layerCount; }; - - -#pragma mark - -#pragma mark Support functions - -/** Returns an image-less MVKFramebuffer object created from the rendering info. */ -MVKFramebuffer* mvkCreateFramebuffer(MVKDevice* device, - const VkRenderingInfo* pRenderingInfo, - MVKRenderPass* mvkRenderPass); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm index c6f56bc75..d0c376ad5 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm @@ -82,8 +82,8 @@ MVKFramebuffer::MVKFramebuffer(MVKDevice* device, const VkFramebufferCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { - _extent = { .width = pCreateInfo->width, .height = pCreateInfo->height }; _layerCount = pCreateInfo->layers; + _extent = { .width = pCreateInfo->width, .height = pCreateInfo->height }; // If this is not an image-less framebuffer, add the attachments if ( !mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) ) { @@ -94,51 +94,25 @@ } } -MVKFramebuffer::~MVKFramebuffer() { - [_mtlDummyTex release]; -} - - -#pragma mark - -#pragma mark Support functions +MVKFramebuffer::MVKFramebuffer(MVKDevice* device, + const VkRenderingInfo* pRenderingInfo) : MVKVulkanAPIDeviceObject(device) { + _layerCount = pRenderingInfo->layerCount; -MVKFramebuffer* mvkCreateFramebuffer(MVKDevice* device, - const VkRenderingInfo* pRenderingInfo, - MVKRenderPass* mvkRenderPass) { - uint32_t attCnt = 0; - VkExtent3D fbExtent = {}; + _extent = {}; for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) { auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx]; if (clrAtt.imageView) { - fbExtent = ((MVKImageView*)clrAtt.imageView)->getExtent3D(); - attCnt++; - if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) { - attCnt++; - } + _extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)clrAtt.imageView)->getExtent3D()); } } - auto* pDSAtt = pRenderingInfo->pDepthAttachment ? pRenderingInfo->pDepthAttachment : pRenderingInfo->pStencilAttachment; - if (pDSAtt) { - if (pDSAtt->imageView) { - fbExtent = ((MVKImageView*)pDSAtt->imageView)->getExtent3D(); - attCnt++; - } - if (pDSAtt->resolveImageView && pDSAtt->resolveMode != VK_RESOLVE_MODE_NONE) { - attCnt++; - } + if (pRenderingInfo->pDepthAttachment && pRenderingInfo->pDepthAttachment->imageView) { + _extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)pRenderingInfo->pDepthAttachment->imageView)->getExtent3D()); + } + if (pRenderingInfo->pStencilAttachment && pRenderingInfo->pStencilAttachment->imageView) { + _extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)pRenderingInfo->pStencilAttachment->imageView)->getExtent3D()); } - - VkFramebufferCreateInfo fbCreateInfo; - fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fbCreateInfo.pNext = nullptr; - fbCreateInfo.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT; - fbCreateInfo.renderPass = (VkRenderPass)mvkRenderPass; - fbCreateInfo.attachmentCount = attCnt; - fbCreateInfo.pAttachments = nullptr; - fbCreateInfo.width = fbExtent.width; - fbCreateInfo.height = fbExtent.height; - fbCreateInfo.layers = pRenderingInfo->layerCount; - - return device->createFramebuffer(&fbCreateInfo, nullptr); } +MVKFramebuffer::~MVKFramebuffer() { + [_mtlDummyTex release]; +} diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 8d09b87ea..154bcf674 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -346,11 +346,6 @@ class MVKGraphicsPipeline : public MVKPipeline { void markIfUsingPhysicalStorageBufferAddressesCapability(SPIRVToMSLConversionResultInfo& resultsInfo, MVKShaderStage stage); - const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pTessEvalSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pFragmentSS = nullptr; - VkPipelineTessellationStateCreateInfo _tessInfo; VkPipelineRasterizationStateCreateInfo _rasterInfo; VkPipelineDepthStencilStateCreateInfo _depthStencilInfo; @@ -364,7 +359,12 @@ class MVKGraphicsPipeline : public MVKPipeline { MVKSmallVector _mtlArgumentEncoders; MVKSmallVector _descriptorBindingUse; MVKSmallVector _stagesUsingPhysicalStorageBufferAddressesCapability; + std::unordered_map> _multiviewMTLPipelineStates; + const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr; + const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr; + const VkPipelineShaderStageCreateInfo* _pTessEvalSS = nullptr; + const VkPipelineShaderStageCreateInfo* _pFragmentSS = nullptr; MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil; id _mtlTessVertexFunctions[3] = {nil, nil, nil}; @@ -373,18 +373,17 @@ class MVKGraphicsPipeline : public MVKPipeline { id _mtlTessVertexStageIndex32State = nil; id _mtlTessControlStageState = nil; id _mtlPipelineState = nil; - std::unordered_map> _multiviewMTLPipelineStates; + + float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 }; MTLCullMode _mtlCullMode; MTLWinding _mtlFrontWinding; MTLTriangleFillMode _mtlFillMode; MTLDepthClipMode _mtlDepthClipMode; MTLPrimitiveType _mtlPrimitiveType; - - float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 }; - uint32_t _outputControlPointCount; MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount; MVKShaderImplicitRezBinding _viewRangeBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex; + uint32_t _outputControlPointCount; uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0; @@ -408,7 +407,6 @@ class MVKGraphicsPipeline : public MVKPipeline { bool _needsFragmentViewRangeBuffer = false; bool _isRasterizing = false; bool _isRasterizingColor = false; - bool _isRasterizingDepthStencil = false; bool _isUsingCustomSamplePositions = false; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index e24e24e8d..bf5e3f130 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -401,7 +401,6 @@ const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); _isRasterizing = !isRasterizationDisabled(pCreateInfo); _isRasterizingColor = _isRasterizing && mvkHasColorAttachments(pRendInfo); - _isRasterizingDepthStencil = _isRasterizing && mvkGetDepthStencilFormat(pRendInfo) != VK_FORMAT_UNDEFINED; // Get the tessellation shaders, if present. Do this now, because we need to extract // reflection data from them that informs everything else. @@ -488,8 +487,9 @@ initCustomSamplePositions(pCreateInfo); // Depth stencil content - clearing will disable depth and stencil testing - // Must ignore allowed bad pDepthStencilState pointer if rasterization disabled or no depth attachment - mvkSetOrClear(&_depthStencilInfo, _isRasterizingDepthStencil ? pCreateInfo->pDepthStencilState : nullptr); + // Must ignore allowed bad pDepthStencilState pointer if rasterization disabled or no depth or stencil attachment format + bool isRasterizingDepthStencil = _isRasterizing && (pRendInfo->depthAttachmentFormat || pRendInfo->stencilAttachmentFormat); + mvkSetOrClear(&_depthStencilInfo, isRasterizingDepthStencil ? pCreateInfo->pDepthStencilState : nullptr); // Viewports and scissors - must ignore allowed bad pViewportState pointer if rasterization is disabled auto pVPState = _isRasterizing ? pCreateInfo->pViewportState : nullptr; @@ -1469,16 +1469,15 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 } } - // Depth & stencil attachments + // Depth & stencil attachment formats MVKPixelFormats* pixFmts = getPixelFormats(); - MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkGetDepthStencilFormat(pRendInfo)); - if (pixFmts->isDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; } - if (pixFmts->isStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; } + plDesc.depthAttachmentPixelFormat = pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat); + plDesc.stencilAttachmentPixelFormat = pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat); - // In Vulkan, it's perfectly valid to render with no attachments. In Metal we need to check for - // support for it. If we have no attachments, then we may have to add a dummy attachment. - if (!caCnt && !pixFmts->isDepthFormat(mtlDSFormat) && !pixFmts->isStencilFormat(mtlDSFormat) && - !getDevice()->_pMetalFeatures->renderWithoutAttachments) { + // In Vulkan, it's perfectly valid to render without any attachments. In Metal, if that + // isn't supported, and we have no attachments, then we have to add a dummy attachment. + if (!getDevice()->_pMetalFeatures->renderWithoutAttachments && + !caCnt && !pRendInfo->depthAttachmentFormat && !pRendInfo->stencilAttachmentFormat) { MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[0]; colorDesc.pixelFormat = MTLPixelFormatR8Unorm; @@ -1553,8 +1552,6 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 _viewRangeBufferIndex = _indirectParamsIndex; const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); - MVKPixelFormats* pixFmts = getPixelFormats(); - MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkGetDepthStencilFormat(pRendInfo)); // Disable any unused color attachments, because Metal validation can complain if the // fragment shader outputs a color value without a corresponding color attachment. @@ -1574,8 +1571,8 @@ 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.enable_point_size_builtin = isRenderingPoints(pCreateInfo) || reflectData.pointMode; - shaderConfig.options.mslOptions.enable_frag_depth_builtin = pixFmts->isDepthFormat(mtlDSFormat); - shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = pixFmts->isStencilFormat(mtlDSFormat); + shaderConfig.options.mslOptions.enable_frag_depth_builtin = (pRendInfo->depthAttachmentFormat != VK_FORMAT_UNDEFINED); + shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = (pRendInfo->stencilAttachmentFormat != VK_FORMAT_UNDEFINED); shaderConfig.options.shouldFlipVertexY = mvkConfig().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; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h index 3b88f5b07..7d1bb1b00 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h @@ -54,9 +54,6 @@ class MVKRenderSubpass : public MVKBaseObject { /** Returns whether this subpass has any color attachments. */ bool hasColorAttachments(); - /** Returns whether this subpass has a depth/stencil attachment. */ - bool hasDepthStencilAttachment() { return _depthStencilAttachment.attachment != VK_ATTACHMENT_UNUSED; } - /** Returns the number of color attachments, which may be zero for depth-only rendering. */ uint32_t getColorAttachmentCount() { return uint32_t(_colorAttachments.size()); } @@ -69,8 +66,17 @@ class MVKRenderSubpass : public MVKBaseObject { /** Returns whether or not the color attachment is used as both a color attachment and an input attachment. */ bool isColorAttachmentAlsoInputAttachment(uint32_t colorAttIdx); - /** Returns the format of the depth/stencil attachment. */ - VkFormat getDepthStencilFormat(); + /** Returns whether or not the depth attachment is being used. */ + bool isDepthAttachmentUsed() { return _depthAttachment.attachment != VK_ATTACHMENT_UNUSED; } + + /** Returns whether or not the stencil attachment is being used. */ + bool isStencilAttachmentUsed() { return _stencilAttachment.attachment != VK_ATTACHMENT_UNUSED; } + + /** Return the depth attachment format. */ + VkFormat getDepthFormat(); + + /** Return the stencil attachment format. */ + VkFormat getStencilFormat(); /** Returns the Vulkan sample count of the attachments used in this subpass. */ VkSampleCountFlagBits getSampleCount(); @@ -146,10 +152,11 @@ class MVKRenderSubpass : public MVKBaseObject { MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription2* pCreateInfo); -private: + MVKRenderSubpass(MVKRenderPass* renderPass, const VkRenderingInfo* pRenderingInfo); +protected: friend class MVKRenderPass; - friend class MVKRenderPassAttachment; + friend class MVKAttachmentDescription; uint32_t getViewMaskGroupForMetalPass(uint32_t passIdx); MVKMTLFmtCaps getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx); @@ -162,8 +169,10 @@ class MVKRenderSubpass : public MVKBaseObject { MVKSmallVector _preserveAttachments; MVKSmallVector _colorAttachmentFormats; VkPipelineRenderingCreateInfo _pipelineRenderingCreateInfo; - VkAttachmentReference2 _depthStencilAttachment; - VkAttachmentReference2 _depthStencilResolveAttachment; + VkAttachmentReference2 _depthAttachment; + VkAttachmentReference2 _stencilAttachment; + VkAttachmentReference2 _depthResolveAttachment; + VkAttachmentReference2 _stencilResolveAttachment; VkResolveModeFlagBits _depthResolveMode = VK_RESOLVE_MODE_NONE; VkResolveModeFlagBits _stencilResolveMode = VK_RESOLVE_MODE_NONE; VkSampleCountFlagBits _defaultSampleCount = VK_SAMPLE_COUNT_1_BIT; @@ -172,10 +181,10 @@ class MVKRenderSubpass : public MVKBaseObject { #pragma mark - -#pragma mark MVKRenderPassAttachment +#pragma mark MVKAttachmentDescription /** Represents an attachment within a Vulkan render pass. */ -class MVKRenderPassAttachment : public MVKBaseObject { +class MVKAttachmentDescription : public MVKBaseObject { public: @@ -218,13 +227,20 @@ class MVKRenderPassAttachment : public MVKBaseObject { /** Returns whether this attachment should be cleared in the subpass. */ bool shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil); - MVKRenderPassAttachment(MVKRenderPass* renderPass, + MVKAttachmentDescription(MVKRenderPass* renderPass, const VkAttachmentDescription* pCreateInfo); - MVKRenderPassAttachment(MVKRenderPass* renderPass, + MVKAttachmentDescription(MVKRenderPass* renderPass, const VkAttachmentDescription2* pCreateInfo); + MVKAttachmentDescription(MVKRenderPass* renderPass, + const VkRenderingAttachmentInfo* pAttInfo, + bool isResolveAttachment); + protected: + friend class MVKRenderPass; + friend class MVKRenderSubpass; + bool isFirstUseOfAttachment(MVKRenderSubpass* subpass); bool isLastUseOfAttachment(MVKRenderSubpass* subpass); MTLStoreAction getMTLStoreAction(MVKRenderSubpass* subpass, @@ -234,7 +250,7 @@ class MVKRenderPassAttachment : public MVKBaseObject { bool canResolveFormat, bool isStencil, bool storeOverride); - void validateFormat(); + void linkToSubpasses(); VkAttachmentDescription2 _info; MVKRenderPass* _renderPass; @@ -282,13 +298,15 @@ class MVKRenderPass : public MVKVulkanAPIDeviceObject { MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo2* pCreateInfo); + MVKRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo); + protected: friend class MVKRenderSubpass; - friend class MVKRenderPassAttachment; + friend class MVKAttachmentDescription; void propagateDebugName() override {} - MVKSmallVector _attachments; + MVKSmallVector _attachments; MVKSmallVector _subpasses; MVKSmallVector _subpassDependencies; VkRenderingFlags _renderingFlags = 0; @@ -297,21 +315,44 @@ class MVKRenderPass : public MVKVulkanAPIDeviceObject { #pragma mark - -#pragma mark Support functions +#pragma mark MVKRenderingAttachmentIterator -/** Returns a MVKRenderPass object created from the rendering info. */ -MVKRenderPass* mvkCreateRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo); +typedef std::function MVKRenderingAttachmentInfoOperation; /** - * Extracts the usable attachments and their clear values from the rendering info, - * and sets them in the corresponding arrays, which must be large enough to hold - * all of the extracted values, and returns the number of attachments extracted. - * For consistency, the clear value of any resolve attachments are populated, - * even though they are ignored. + * Iterates the attachments in a VkRenderingInfo, and processes an operation + * on each attachment, once for the imageView, and once for the resolveImageView. + * + * Attachments are sequentially processed in this order: + * [color, color-resolve], ..., + * depth, depth-resolve, + * stencil, stencil-resolve + * skipping any attachments that do not have a VkImageView */ -uint32_t mvkGetAttachments(const VkRenderingInfo* pRenderingInfo, - MVKImageView* attachments[], - VkClearValue clearValues[]); +class MVKRenderingAttachmentIterator : public MVKBaseObject { + +public: + + MVKVulkanAPIObject* getVulkanAPIObject() override { return nullptr; } + + /** Iterates the attachments with the specified lambda function. */ + void iterate(MVKRenderingAttachmentInfoOperation attOperation); + + MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo) : _pRenderingInfo(pRenderingInfo) {} + +protected: + void handleAttachment(const VkRenderingAttachmentInfo* pAttInfo, + VkImageAspectFlagBits aspect, + MVKRenderingAttachmentInfoOperation attOperation); + + const VkRenderingInfo* _pRenderingInfo; +}; + + +#pragma mark - +#pragma mark Support functions /** Returns whether the view mask uses multiview. */ static constexpr bool mvkIsMultiview(uint32_t viewMask) { return viewMask != 0; } @@ -322,9 +363,6 @@ bool mvkIsColorAttachmentUsed(const VkPipelineRenderingCreateInfo* pRendInfo, ui /** Returns whether any attachment is being used. */ bool mvkHasColorAttachments(const VkPipelineRenderingCreateInfo* pRendInfo); -/** Extracts and returns the combined depth/stencil format . */ -VkFormat mvkGetDepthStencilFormat(const VkPipelineRenderingCreateInfo* pRendInfo); - /** * Extracts the first view, number of views, and the portion of the mask * to be rendered from the lowest clump of set bits in a view mask. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index 662bf2bbd..2c4bf185d 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm @@ -53,9 +53,7 @@ } bool MVKRenderSubpass::isColorAttachmentUsed(uint32_t colorAttIdx) { - if (colorAttIdx >= _colorAttachments.size()) { - return false; - } + if (colorAttIdx >= _colorAttachments.size()) { return false; } return _colorAttachments[colorAttIdx].attachment != VK_ATTACHMENT_UNUSED; } @@ -72,10 +70,12 @@ return false; } -VkFormat MVKRenderSubpass::getDepthStencilFormat() { - uint32_t rpAttIdx = _depthStencilAttachment.attachment; - if (rpAttIdx == VK_ATTACHMENT_UNUSED) { return VK_FORMAT_UNDEFINED; } - return _renderPass->_attachments[rpAttIdx].getFormat(); +VkFormat MVKRenderSubpass::getDepthFormat() { + return isDepthAttachmentUsed() ? _renderPass->_attachments[_depthAttachment.attachment].getFormat() : VK_FORMAT_UNDEFINED; +} + +VkFormat MVKRenderSubpass::getStencilFormat() { + return isStencilAttachmentUsed() ? _renderPass->_attachments[_stencilAttachment.attachment].getFormat() : VK_FORMAT_UNDEFINED; } VkSampleCountFlagBits MVKRenderSubpass::getSampleCount() { @@ -85,11 +85,12 @@ return _renderPass->_attachments[rpAttIdx].getSampleCount(); } } - uint32_t rpAttIdx = _depthStencilAttachment.attachment; - if (rpAttIdx != VK_ATTACHMENT_UNUSED) { - return _renderPass->_attachments[rpAttIdx].getSampleCount(); + if (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED) { + return _renderPass->_attachments[_depthAttachment.attachment].getSampleCount(); + } + if (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED) { + return _renderPass->_attachments[_stencilAttachment.attachment].getSampleCount(); } - return VK_SAMPLE_COUNT_1_BIT; } @@ -176,7 +177,7 @@ } // Configure the color attachment - MVKRenderPassAttachment* clrMVKRPAtt = &_renderPass->_attachments[clrRPAttIdx]; + MVKAttachmentDescription* clrMVKRPAtt = &_renderPass->_attachments[clrRPAttIdx]; if (clrMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc, this, attachments[clrRPAttIdx], isRenderingEntireAttachment, hasResolveAttachment, canResolveFormat, @@ -193,66 +194,75 @@ } } - // Populate the Metal depth and stencil attachments - uint32_t dsRPAttIdx = _depthStencilAttachment.attachment; - uint32_t dsRslvRPAttIdx = _depthStencilResolveAttachment.attachment; - if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) { - MVKRenderPassAttachment* dsMVKRPAtt = &_renderPass->_attachments[dsRPAttIdx]; - MVKImageView* dsImage = attachments[dsRPAttIdx]; - MVKImageView* dsRslvImage = nullptr; - MTLPixelFormat mtlDSFormat = dsImage->getMTLPixelFormat(0); + // Populate the Metal depth attachment + uint32_t depthRPAttIdx = _depthAttachment.attachment; + if (depthRPAttIdx != VK_ATTACHMENT_UNUSED) { + MVKAttachmentDescription* depthMVKRPAtt = &_renderPass->_attachments[depthRPAttIdx]; + MVKImageView* depthImage = attachments[depthRPAttIdx]; - if (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED) { - dsRslvImage = attachments[dsRslvRPAttIdx]; + MVKImageView* depthRslvImage = nullptr; + uint32_t depthRslvRPAttIdx = _depthResolveAttachment.attachment; + if (depthRslvRPAttIdx != VK_ATTACHMENT_UNUSED) { + depthRslvImage = attachments[depthRslvRPAttIdx]; } - if (pixFmts->isDepthFormat(mtlDSFormat)) { - MTLRenderPassDepthAttachmentDescriptor* mtlDepthAttDesc = mtlRPDesc.depthAttachment; - bool hasResolveAttachment = (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE); - if (hasResolveAttachment) { - dsRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlDepthAttDesc); - mtlDepthAttDesc.depthResolveFilterMVK = mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(_depthResolveMode); - if (isMultiview()) { - mtlDepthAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx); - } - } - if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this, dsImage, - isRenderingEntireAttachment, - hasResolveAttachment, true, - false, loadOverride)) { - mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[dsRPAttIdx]); - } + MTLRenderPassDepthAttachmentDescriptor* mtlDepthAttDesc = mtlRPDesc.depthAttachment; + bool hasDepthResolve = depthRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE; + if (hasDepthResolve) { + depthRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlDepthAttDesc); + mtlDepthAttDesc.depthResolveFilterMVK = mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(_depthResolveMode); if (isMultiview()) { - mtlDepthAttDesc.slice += getFirstViewIndexInMetalPass(passIdx); + mtlDepthAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx); } } - if (pixFmts->isStencilFormat(mtlDSFormat)) { - MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment; - bool hasResolveAttachment = (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE); - if (hasResolveAttachment) { - dsRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlStencilAttDesc); + if (depthMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this, depthImage, + isRenderingEntireAttachment, + hasDepthResolve, true, + false, loadOverride)) { + mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[depthRPAttIdx]); + } + if (isMultiview()) { + mtlDepthAttDesc.slice += getFirstViewIndexInMetalPass(passIdx); + } + } + + // Populate the Metal stencil attachment + uint32_t stencilRPAttIdx = _stencilAttachment.attachment; + if (stencilRPAttIdx != VK_ATTACHMENT_UNUSED) { + MVKAttachmentDescription* stencilMVKRPAtt = &_renderPass->_attachments[stencilRPAttIdx]; + MVKImageView* stencilImage = attachments[stencilRPAttIdx]; + + MVKImageView* stencilRslvImage = nullptr; + uint32_t stencilRslvRPAttIdx = _stencilResolveAttachment.attachment; + if (stencilRslvRPAttIdx != VK_ATTACHMENT_UNUSED) { + stencilRslvImage = attachments[stencilRslvRPAttIdx]; + } + + MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment; + bool hasStencilResolve = (stencilRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE); + if (hasStencilResolve) { + stencilRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlStencilAttDesc); #if MVK_MACOS_OR_IOS - mtlStencilAttDesc.stencilResolveFilterMVK = mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(_stencilResolveMode); + mtlStencilAttDesc.stencilResolveFilterMVK = mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(_stencilResolveMode); #endif - if (isMultiview()) { - mtlStencilAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx); - } - } - if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this, dsImage, - isRenderingEntireAttachment, - hasResolveAttachment, true, - true, loadOverride)) { - mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[dsRPAttIdx]); - } if (isMultiview()) { - mtlStencilAttDesc.slice += getFirstViewIndexInMetalPass(passIdx); + mtlStencilAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx); } } + if (stencilMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this, stencilImage, + isRenderingEntireAttachment, + hasStencilResolve, true, + true, loadOverride)) { + mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[stencilRPAttIdx]); + } + if (isMultiview()) { + mtlStencilAttDesc.slice += getFirstViewIndexInMetalPass(passIdx); + } } // Vulkan supports rendering without attachments, but older Metal does not. // If Metal does not support rendering without attachments, create a dummy attachment to pass Metal validation. - if (caUsedCnt == 0 && dsRPAttIdx == VK_ATTACHMENT_UNUSED) { + if (caUsedCnt == 0 && depthRPAttIdx == VK_ATTACHMENT_UNUSED && stencilRPAttIdx == VK_ATTACHMENT_UNUSED) { if (_renderPass->getDevice()->_pMetalFeatures->renderWithoutAttachments) { mtlRPDesc.defaultRasterSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_defaultSampleCount); } else { @@ -285,42 +295,42 @@ _renderPass->_attachments[clrRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[clrRPAttIdx], isRenderingEntireAttachment, hasResolveAttachment, canResolveFormat, caIdx, false, storeOverride); } } - uint32_t dsRPAttIdx = _depthStencilAttachment.attachment; - if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) { - bool hasResolveAttachment = _depthStencilResolveAttachment.attachment != VK_ATTACHMENT_UNUSED; - bool hasDepthResolveAttachment = hasResolveAttachment && _depthResolveMode != VK_RESOLVE_MODE_NONE; - bool hasStencilResolveAttachment = hasResolveAttachment && _stencilResolveMode != VK_RESOLVE_MODE_NONE; - bool canResolveFormat = true; - _renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[dsRPAttIdx], isRenderingEntireAttachment, hasDepthResolveAttachment, canResolveFormat, 0, false, storeOverride); - _renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[dsRPAttIdx], isRenderingEntireAttachment, hasStencilResolveAttachment, canResolveFormat, 0, true, storeOverride); - } + if (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED) { + _renderPass->_attachments[_depthAttachment.attachment].encodeStoreAction(cmdEncoder, this, attachments[_depthAttachment.attachment], isRenderingEntireAttachment, + (_depthResolveAttachment.attachment != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE), + true, 0, false, storeOverride); + } + if (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED) { + _renderPass->_attachments[_stencilAttachment.attachment].encodeStoreAction(cmdEncoder, this, attachments[_stencilAttachment.attachment], isRenderingEntireAttachment, + (_stencilResolveAttachment.attachment != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE), + true, 0, true, storeOverride); + } } void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts, const MVKArrayRef clearValues) { - uint32_t attIdx; uint32_t caCnt = getColorAttachmentCount(); for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { - attIdx = _colorAttachments[caIdx].attachment; + uint32_t attIdx = _colorAttachments[caIdx].attachment; if ((attIdx != VK_ATTACHMENT_UNUSED) && _renderPass->_attachments[attIdx].shouldClearAttachment(this, false)) { clearAtts.push_back( { VK_IMAGE_ASPECT_COLOR_BIT, caIdx, clearValues[attIdx] } ); } } - attIdx = _depthStencilAttachment.attachment; - if (attIdx != VK_ATTACHMENT_UNUSED) { - MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); - MTLPixelFormat mtlDSFmt = pixFmts->getMTLPixelFormat(getDepthStencilFormat()); - auto& rpAtt = _renderPass->_attachments[attIdx]; - VkImageAspectFlags aspectMask = 0; - if (rpAtt.shouldClearAttachment(this, false) && pixFmts->isDepthFormat(mtlDSFmt)) { - mvkEnableFlags(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT); - } - if (rpAtt.shouldClearAttachment(this, true) && pixFmts->isStencilFormat(mtlDSFmt)) { - mvkEnableFlags(aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT); + // If depth and stencil both need clearing and are the same attachment, just clear once, otherwise, clear them separately. + bool shouldClearDepth = (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED && + _renderPass->_attachments[_depthAttachment.attachment].shouldClearAttachment(this, false)); + bool shouldClearStencil = (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED && + _renderPass->_attachments[_stencilAttachment.attachment].shouldClearAttachment(this, true)); + + if (shouldClearDepth && shouldClearStencil && _depthAttachment.attachment == _stencilAttachment.attachment) { + clearAtts.push_back( { VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, clearValues[_depthAttachment.attachment] } ); + } else { + if (shouldClearDepth) { + clearAtts.push_back( { VK_IMAGE_ASPECT_DEPTH_BIT, 0, clearValues[_depthAttachment.attachment] } ); } - if (aspectMask) { - clearAtts.push_back( { aspectMask, 0, clearValues[attIdx] } ); + if (shouldClearStencil) { + clearAtts.push_back( { VK_IMAGE_ASPECT_STENCIL_BIT, 0, clearValues[_stencilAttachment.attachment] } ); } } } @@ -328,18 +338,24 @@ void MVKRenderSubpass::populateMultiviewClearRects(MVKSmallVector& clearRects, MVKCommandEncoder* cmdEncoder, uint32_t caIdx, VkImageAspectFlags aspectMask) { - uint32_t attIdx; - assert(this == cmdEncoder->getSubpass()); - if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - attIdx = _depthStencilAttachment.attachment; - if (attIdx != VK_ATTACHMENT_UNUSED) { - _renderPass->_attachments[attIdx].populateMultiviewClearRects(clearRects, cmdEncoder); + if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_COLOR_BIT)) { + uint32_t clrAttIdx = _colorAttachments[caIdx].attachment; + if (clrAttIdx != VK_ATTACHMENT_UNUSED) { + _renderPass->_attachments[clrAttIdx].populateMultiviewClearRects(clearRects, cmdEncoder); } - return; } - attIdx = _colorAttachments[caIdx].attachment; - if (attIdx != VK_ATTACHMENT_UNUSED) { - _renderPass->_attachments[attIdx].populateMultiviewClearRects(clearRects, cmdEncoder); + + // If depth and stencil are the same attachment, only clear once. + if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT) && + _depthAttachment.attachment != VK_ATTACHMENT_UNUSED) { + + _renderPass->_attachments[_depthAttachment.attachment].populateMultiviewClearRects(clearRects, cmdEncoder); + } + if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT) && + _stencilAttachment.attachment != VK_ATTACHMENT_UNUSED && + _stencilAttachment.attachment != _depthAttachment.attachment) { + + _renderPass->_attachments[_stencilAttachment.attachment].populateMultiviewClearRects(clearRects, cmdEncoder); } } @@ -368,8 +384,12 @@ break; } } - if (_depthStencilAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt); } - if (_depthStencilResolveAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsResolve); } + if (_depthAttachment.attachment == rpAttIdx || _stencilAttachment.attachment == rpAttIdx) { + mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt); + } + if (_depthResolveAttachment.attachment == rpAttIdx || _stencilResolveAttachment.attachment == rpAttIdx) { + mvkEnableFlags(caps, kMVKMTLFmtCapsResolve); + } return caps; } @@ -405,9 +425,7 @@ } } -// Must be called after renderpass has both subpasses and attachments bound void MVKRenderSubpass::populatePipelineRenderingCreateInfo() { - MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); _pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; _pipelineRenderingCreateInfo.pNext = nullptr; @@ -415,141 +433,220 @@ for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { _colorAttachmentFormats.push_back(getColorAttachmentFormat(caIdx)); } - _pipelineRenderingCreateInfo.pColorAttachmentFormats = _colorAttachmentFormats.data(); _pipelineRenderingCreateInfo.colorAttachmentCount = caCnt; - - VkFormat dsFmt = getDepthStencilFormat(); - MTLPixelFormat dsMTLFmt = pixFmts->getMTLPixelFormat(dsFmt); - _pipelineRenderingCreateInfo.depthAttachmentFormat = pixFmts->isDepthFormat(dsMTLFmt) ? dsFmt : VK_FORMAT_UNDEFINED; - _pipelineRenderingCreateInfo.stencilAttachmentFormat = pixFmts->isStencilFormat(dsMTLFmt) ? dsFmt : VK_FORMAT_UNDEFINED; + _pipelineRenderingCreateInfo.pColorAttachmentFormats = _colorAttachmentFormats.data(); + _pipelineRenderingCreateInfo.depthAttachmentFormat = getDepthFormat(); + _pipelineRenderingCreateInfo.stencilAttachmentFormat = getStencilFormat(); } -MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, - const VkSubpassDescription* pCreateInfo, - const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects, - uint32_t viewMask) { +static const VkAttachmentReference2 _unusedAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED, 0}; + +MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription2* pCreateInfo) { + + VkSubpassDescriptionDepthStencilResolve* pDSResolveInfo = nullptr; + for (auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { + switch (next->sType) { + case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE: + pDSResolveInfo = (VkSubpassDescriptionDepthStencilResolve*)next; + break; + default: + break; + } + } + _renderPass = renderPass; _subpassIndex = (uint32_t)_renderPass->_subpasses.size(); - _pipelineRenderingCreateInfo.viewMask = viewMask; + _pipelineRenderingCreateInfo.viewMask = pCreateInfo->viewMask; // Add attachments _inputAttachments.reserve(pCreateInfo->inputAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->inputAttachmentCount; i++) { - const VkAttachmentReference& att = pCreateInfo->pInputAttachments[i]; - _inputAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0}); - } - if (pInputAspects && pInputAspects->aspectReferenceCount) { - for (uint32_t i = 0; i < pInputAspects->aspectReferenceCount; i++) { - const VkInputAttachmentAspectReference& aspectRef = pInputAspects->pAspectReferences[i]; - if (aspectRef.subpass == _subpassIndex) { - _inputAttachments[aspectRef.inputAttachmentIndex].aspectMask = aspectRef.aspectMask; - } - } + _inputAttachments.push_back(pCreateInfo->pInputAttachments[i]); } _colorAttachments.reserve(pCreateInfo->colorAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) { - const VkAttachmentReference& att = pCreateInfo->pColorAttachments[i]; - _colorAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0}); + _colorAttachments.push_back(pCreateInfo->pColorAttachments[i]); } if (pCreateInfo->pResolveAttachments) { _resolveAttachments.reserve(pCreateInfo->colorAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) { - const VkAttachmentReference& att = pCreateInfo->pResolveAttachments[i]; - _resolveAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0}); + _resolveAttachments.push_back(pCreateInfo->pResolveAttachments[i]); } } - if (pCreateInfo->pDepthStencilAttachment) { - _depthStencilAttachment.attachment = pCreateInfo->pDepthStencilAttachment->attachment; - _depthStencilAttachment.layout = pCreateInfo->pDepthStencilAttachment->layout; - } else { - _depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED; + MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); + + _depthAttachment = _unusedAttachment; + _stencilAttachment = _unusedAttachment; + const auto* pDSAtt = pCreateInfo->pDepthStencilAttachment; + if (pDSAtt && pDSAtt->attachment != VK_ATTACHMENT_UNUSED) { + MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[pDSAtt->attachment].getFormat()); + if (pixFmts->isDepthFormat(mtlDSFormat)) { + _depthAttachment = *pCreateInfo->pDepthStencilAttachment; + } + if (pixFmts->isStencilFormat(mtlDSFormat)) { + _stencilAttachment = *pCreateInfo->pDepthStencilAttachment; + } } - _depthStencilResolveAttachment.attachment = VK_ATTACHMENT_UNUSED; + _depthResolveAttachment = _unusedAttachment; + _stencilResolveAttachment = _unusedAttachment; + const auto* pDSRslvAtt = pDSResolveInfo ? pDSResolveInfo->pDepthStencilResolveAttachment : nullptr; + if (pDSRslvAtt && pDSRslvAtt->attachment != VK_ATTACHMENT_UNUSED) { + MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[pDSRslvAtt->attachment].getFormat()); + if (pixFmts->isDepthFormat(mtlDSFormat)) { + _depthResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment; + _depthResolveMode = pDSResolveInfo->depthResolveMode; + } + if (pixFmts->isStencilFormat(mtlDSFormat)) { + _stencilResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment; + _stencilResolveMode = pDSResolveInfo->stencilResolveMode; + } + } _preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) { _preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]); } + + populatePipelineRenderingCreateInfo(); } MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, - const VkSubpassDescription2* pCreateInfo) { - - VkSubpassDescriptionDepthStencilResolve* pDSResolveInfo = nullptr; - for (auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { - switch (next->sType) { - case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE: - pDSResolveInfo = (VkSubpassDescriptionDepthStencilResolve*)next; - break; - default: - break; - } - } - + const VkSubpassDescription* pCreateInfo, + const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects, + uint32_t viewMask) { _renderPass = renderPass; _subpassIndex = (uint32_t)_renderPass->_subpasses.size(); - _pipelineRenderingCreateInfo.viewMask = pCreateInfo->viewMask; + _pipelineRenderingCreateInfo.viewMask = viewMask; // Add attachments _inputAttachments.reserve(pCreateInfo->inputAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->inputAttachmentCount; i++) { - _inputAttachments.push_back(pCreateInfo->pInputAttachments[i]); + const VkAttachmentReference& att = pCreateInfo->pInputAttachments[i]; + _inputAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT}); + } + if (pInputAspects && pInputAspects->aspectReferenceCount) { + for (uint32_t i = 0; i < pInputAspects->aspectReferenceCount; i++) { + const VkInputAttachmentAspectReference& aspectRef = pInputAspects->pAspectReferences[i]; + if (aspectRef.subpass == _subpassIndex) { + _inputAttachments[aspectRef.inputAttachmentIndex].aspectMask = aspectRef.aspectMask; + } + } } _colorAttachments.reserve(pCreateInfo->colorAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) { - _colorAttachments.push_back(pCreateInfo->pColorAttachments[i]); + const VkAttachmentReference& att = pCreateInfo->pColorAttachments[i]; + _colorAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT}); } if (pCreateInfo->pResolveAttachments) { _resolveAttachments.reserve(pCreateInfo->colorAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) { - _resolveAttachments.push_back(pCreateInfo->pResolveAttachments[i]); + const VkAttachmentReference& att = pCreateInfo->pResolveAttachments[i]; + _resolveAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT}); } } + _depthAttachment = _unusedAttachment; + _stencilAttachment = _unusedAttachment; if (pCreateInfo->pDepthStencilAttachment) { - _depthStencilAttachment = *pCreateInfo->pDepthStencilAttachment; - } else { - _depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED; + auto* dsAtt = pCreateInfo->pDepthStencilAttachment; + uint32_t dsAttIdx = dsAtt->attachment; + if (dsAttIdx != VK_ATTACHMENT_UNUSED) { + MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); + MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[dsAttIdx].getFormat()); + if (pixFmts->isDepthFormat(mtlDSFormat)) { + _depthAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, dsAtt->attachment, dsAtt->layout, VK_IMAGE_ASPECT_DEPTH_BIT}; + } + if (pixFmts->isStencilFormat(mtlDSFormat)) { + _stencilAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, dsAtt->attachment, dsAtt->layout, VK_IMAGE_ASPECT_STENCIL_BIT}; + } + } } - if (pDSResolveInfo && pDSResolveInfo->pDepthStencilResolveAttachment) { - _depthStencilResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment; - _depthResolveMode = pDSResolveInfo->depthResolveMode; - _stencilResolveMode = pDSResolveInfo->stencilResolveMode; - } else { - _depthStencilResolveAttachment.attachment = VK_ATTACHMENT_UNUSED; - } + _depthResolveAttachment = _unusedAttachment; + _stencilResolveAttachment = _unusedAttachment; _preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) { _preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]); } + + populatePipelineRenderingCreateInfo(); + +} + +MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, const VkRenderingInfo* pRenderingInfo) { + + _renderPass = renderPass; + _subpassIndex = (uint32_t)_renderPass->_subpasses.size(); + _pipelineRenderingCreateInfo.viewMask = pRenderingInfo->viewMask; + + _depthAttachment = _unusedAttachment; + _depthResolveAttachment = _unusedAttachment; + _stencilAttachment = _unusedAttachment; + _stencilResolveAttachment = _unusedAttachment; + + uint32_t attIdx = 0; + MVKRenderingAttachmentIterator attIter(pRenderingInfo); + attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { + VkAttachmentReference2 attRef = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, attIdx++, pAttInfo->imageLayout, aspect}; + switch (aspect) { + case VK_IMAGE_ASPECT_COLOR_BIT: + if (isResolveAttachment) { + _resolveAttachments.push_back(attRef); + } else { + _colorAttachments.push_back(attRef); + } + break; + + case VK_IMAGE_ASPECT_DEPTH_BIT: + if (isResolveAttachment) { + _depthResolveAttachment = attRef; + _depthResolveMode = pAttInfo->resolveMode; + } else { + _depthAttachment = attRef; + } + break; + case VK_IMAGE_ASPECT_STENCIL_BIT: + if (isResolveAttachment) { + _stencilResolveAttachment = attRef; + _stencilResolveMode = pAttInfo->resolveMode; + } else { + _stencilAttachment = attRef; + } + break; + + default: + break; + } + }); + + populatePipelineRenderingCreateInfo(); } #pragma mark - -#pragma mark MVKRenderPassAttachment +#pragma mark MVKAttachmentDescription -MVKVulkanAPIObject* MVKRenderPassAttachment::getVulkanAPIObject() { return _renderPass->getVulkanAPIObject(); }; +MVKVulkanAPIObject* MVKAttachmentDescription::getVulkanAPIObject() { return _renderPass->getVulkanAPIObject(); }; -VkFormat MVKRenderPassAttachment::getFormat() { return _info.format; } +VkFormat MVKAttachmentDescription::getFormat() { return _info.format; } -VkSampleCountFlagBits MVKRenderPassAttachment::getSampleCount() { return _info.samples; } +VkSampleCountFlagBits MVKAttachmentDescription::getSampleCount() { return _info.samples; } -bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRenderPassAttachmentDescriptor* mtlAttDesc, - MVKRenderSubpass* subpass, - MVKImageView* attachment, - bool isRenderingEntireAttachment, - bool hasResolveAttachment, - bool canResolveFormat, - bool isStencil, - bool loadOverride) { +bool MVKAttachmentDescription::populateMTLRenderPassAttachmentDescriptor(MTLRenderPassAttachmentDescriptor* mtlAttDesc, + MVKRenderSubpass* subpass, + MVKImageView* attachment, + bool isRenderingEntireAttachment, + bool hasResolveAttachment, + bool canResolveFormat, + bool isStencil, + bool loadOverride) { // Populate from the attachment image view attachment->populateMTLRenderPassAttachmentDescriptor(mtlAttDesc); @@ -597,15 +694,15 @@ return (mtlLA == MTLLoadActionClear); } -void MVKRenderPassAttachment::encodeStoreAction(MVKCommandEncoder* cmdEncoder, - MVKRenderSubpass* subpass, - MVKImageView* attachment, - bool isRenderingEntireAttachment, - bool hasResolveAttachment, - bool canResolveFormat, - uint32_t caIdx, - bool isStencil, - bool storeOverride) { +void MVKAttachmentDescription::encodeStoreAction(MVKCommandEncoder* cmdEncoder, + MVKRenderSubpass* subpass, + MVKImageView* attachment, + bool isRenderingEntireAttachment, + bool hasResolveAttachment, + bool canResolveFormat, + uint32_t caIdx, + bool isStencil, + bool storeOverride) { // For a combined depth-stencil format in an attachment with VK_IMAGE_ASPECT_STENCIL_BIT, // the attachment format may have been swizzled to a stencil-only format. In this case, // we want to guard against an attempt to store the non-existent depth component. @@ -630,7 +727,7 @@ } } -void MVKRenderPassAttachment::populateMultiviewClearRects(MVKSmallVector& clearRects, MVKCommandEncoder* cmdEncoder) { +void MVKAttachmentDescription::populateMultiviewClearRects(MVKSmallVector& clearRects, MVKCommandEncoder* cmdEncoder) { MVKRenderSubpass* subpass = cmdEncoder->getSubpass(); uint32_t clearMask = subpass->getViewMaskGroupForMetalPass(cmdEncoder->getMultiviewPassIndex()) & _firstUseViewMasks[subpass->_subpassIndex]; @@ -643,7 +740,7 @@ } while (clearMask); } -bool MVKRenderPassAttachment::isFirstUseOfAttachment(MVKRenderSubpass* subpass) { +bool MVKAttachmentDescription::isFirstUseOfAttachment(MVKRenderSubpass* subpass) { if ( subpass->isMultiview() ) { return _firstUseViewMasks[subpass->_subpassIndex] == subpass->_pipelineRenderingCreateInfo.viewMask; } else { @@ -651,7 +748,7 @@ } } -bool MVKRenderPassAttachment::isLastUseOfAttachment(MVKRenderSubpass* subpass) { +bool MVKAttachmentDescription::isLastUseOfAttachment(MVKRenderSubpass* subpass) { if ( subpass->isMultiview() ) { return _lastUseViewMasks[subpass->_subpassIndex] == subpass->_pipelineRenderingCreateInfo.viewMask; } else { @@ -659,13 +756,13 @@ } } -MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subpass, - bool isRenderingEntireAttachment, - bool isMemorylessAttachment, - bool hasResolveAttachment, - bool canResolveFormat, - bool isStencil, - bool storeOverride) { +MTLStoreAction MVKAttachmentDescription::getMTLStoreAction(MVKRenderSubpass* subpass, + bool isRenderingEntireAttachment, + bool isMemorylessAttachment, + bool hasResolveAttachment, + bool canResolveFormat, + bool isStencil, + bool storeOverride) { // If the renderpass is going to be suspended, and resumed later, store the contents to preserve them until then. if (mvkIsAnyFlagEnabled(_renderPass->getRenderingFlags(), VK_RENDERING_SUSPENDING_BIT)) { @@ -690,7 +787,7 @@ return mvkMTLStoreActionFromVkAttachmentStoreOp(storeOp, hasResolveAttachment, canResolveFormat); } -bool MVKRenderPassAttachment::shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil) { +bool MVKAttachmentDescription::shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil) { // If the renderpass is being resumed after being suspended, don't clear this attachment. if (mvkIsAnyFlagEnabled(_renderPass->getRenderingFlags(), VK_RENDERING_RESUMING_BIT_KHR)) { return false; } @@ -705,7 +802,8 @@ return loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR; } -void MVKRenderPassAttachment::validateFormat() { +// Must be called after renderpass has both subpasses and attachments bound +void MVKAttachmentDescription::linkToSubpasses() { // Validate pixel format is supported MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); if ( !pixFmts->isSupportedOrSubstitutable(_info.format) ) { @@ -715,7 +813,7 @@ // Determine the indices of the first and last render subpasses to use this attachment. _firstUseSubpassIdx = kMVKUndefinedLargeUInt32; _lastUseSubpassIdx = 0; - if ( _renderPass->isMultiview() ) { + if (_renderPass->_subpasses[0].isMultiview()) { _firstUseViewMasks.reserve(_renderPass->_subpasses.size()); _lastUseViewMasks.reserve(_renderPass->_subpasses.size()); } @@ -746,8 +844,8 @@ } } -MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass, - const VkAttachmentDescription* pCreateInfo) { +MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass, + const VkAttachmentDescription* pCreateInfo) { _info.flags = pCreateInfo->flags; _info.format = pCreateInfo->format; _info.samples = pCreateInfo->samples; @@ -759,17 +857,41 @@ _info.finalLayout = pCreateInfo->finalLayout; _renderPass = renderPass; _attachmentIndex = uint32_t(_renderPass->_attachments.size()); - - validateFormat(); } -MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass, - const VkAttachmentDescription2* pCreateInfo) { +MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass, + const VkAttachmentDescription2* pCreateInfo) { _info = *pCreateInfo; _renderPass = renderPass; _attachmentIndex = uint32_t(_renderPass->_attachments.size()); +} - validateFormat(); +MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass, + const VkRenderingAttachmentInfo* pAttInfo, + bool isResolveAttachment) { + if (isResolveAttachment) { + _info.flags = 0; + _info.format = ((MVKImageView*)pAttInfo->resolveImageView)->getVkFormat(); + _info.samples = VK_SAMPLE_COUNT_1_BIT; + _info.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + _info.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + _info.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + _info.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + _info.initialLayout = pAttInfo->resolveImageLayout; + _info.finalLayout = pAttInfo->resolveImageLayout; + } else { + _info.flags = 0; + _info.format = ((MVKImageView*)pAttInfo->imageView)->getVkFormat(); + _info.samples = ((MVKImageView*)pAttInfo->imageView)->getSampleCount(); + _info.loadOp = pAttInfo->loadOp; + _info.storeOp = pAttInfo->storeOp; + _info.stencilLoadOp = pAttInfo->loadOp; + _info.stencilStoreOp = pAttInfo->storeOp; + _info.initialLayout = pAttInfo->imageLayout; + _info.finalLayout = pAttInfo->imageLayout; + } + _renderPass = renderPass; + _attachmentIndex = uint32_t(_renderPass->_attachments.size()); } @@ -786,8 +908,6 @@ return { 1, 1 }; } -bool MVKRenderPass::isMultiview() const { return _subpasses[0].isMultiview(); } - MVKRenderPass::MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { @@ -815,7 +935,13 @@ viewOffsets = pMultiviewCreateInfo->pViewOffsets; } - // Add subpasses and dependencies first + // Add attachments first so subpasses can access them during creation + _attachments.reserve(pCreateInfo->attachmentCount); + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + _attachments.emplace_back(this, &pCreateInfo->pAttachments[i]); + } + + // Add subpasses and dependencies _subpasses.reserve(pCreateInfo->subpassCount); for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { _subpasses.emplace_back(this, &pCreateInfo->pSubpasses[i], pInputAspectCreateInfo, viewMasks ? viewMasks[i] : 0); @@ -837,23 +963,22 @@ _subpassDependencies.push_back(dependency); } - // Add attachments after subpasses, so each attachment can link to subpasses - _attachments.reserve(pCreateInfo->attachmentCount); - for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { - _attachments.emplace_back(this, &pCreateInfo->pAttachments[i]); - } - - // Populate additional subpass info after attachments added. - for (auto& mvkSP : _subpasses) { - mvkSP.populatePipelineRenderingCreateInfo(); + // Link attachments to subpasses + for (auto& att : _attachments) { + att.linkToSubpasses(); } } - MVKRenderPass::MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo2* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { - // Add subpasses and dependencies first + // Add attachments first so subpasses can access them during creation + _attachments.reserve(pCreateInfo->attachmentCount); + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + _attachments.emplace_back(this, &pCreateInfo->pAttachments[i]); + } + + // Add subpasses and dependencies _subpasses.reserve(pCreateInfo->subpassCount); for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { _subpasses.emplace_back(this, &pCreateInfo->pSubpasses[i]); @@ -863,215 +988,61 @@ _subpassDependencies.push_back(pCreateInfo->pDependencies[i]); } - // Add attachments after subpasses, so each attachment can link to subpasses - _attachments.reserve(pCreateInfo->attachmentCount); - for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { - _attachments.emplace_back(this, &pCreateInfo->pAttachments[i]); - } - - // Populate additional subpass info after attachments added. - for (auto& mvkSP : _subpasses) { - mvkSP.populatePipelineRenderingCreateInfo(); + // Link attachments to subpasses + for (auto& att : _attachments) { + att.linkToSubpasses(); } } +MVKRenderPass::MVKRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo) : MVKVulkanAPIDeviceObject(device) { -#pragma mark - -#pragma mark Support functions + _renderingFlags = pRenderingInfo->flags; -// Adds the rendering attachment info to the array of attachment descriptors at the index, -// and increments the index, for both the base view and the resolve view, if it is present. -static void mvkAddAttachmentDescriptor(const VkRenderingAttachmentInfo* pAttInfo, - const VkRenderingAttachmentInfo* pStencilAttInfo, - VkAttachmentDescription2 attachmentDescriptors[], - uint32_t& attDescIdx) { - VkAttachmentDescription2 attDesc; - attDesc.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; - attDesc.pNext = nullptr; - attDesc.flags = 0; - attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - - // Handle stencil-only possibility. - if ( !pAttInfo ) { pAttInfo = pStencilAttInfo; } + // Add attachments first so subpasses can access them during creation + uint32_t attCnt = 0; + MVKRenderingAttachmentIterator attIter(pRenderingInfo); + attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { attCnt++; }); + _attachments.reserve(attCnt); + attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { + _attachments.emplace_back(this, pAttInfo, isResolveAttachment); + }); - if (pAttInfo && pAttInfo->imageView) { - MVKImageView* mvkImgView = (MVKImageView*)pAttInfo->imageView; - attDesc.format = mvkImgView->getVkFormat(); - attDesc.samples = mvkImgView->getSampleCount(); - attDesc.loadOp = pAttInfo->loadOp; - attDesc.storeOp = pAttInfo->storeOp; - attDesc.stencilLoadOp = pStencilAttInfo ? pStencilAttInfo->loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.stencilStoreOp = pStencilAttInfo ? pStencilAttInfo->storeOp : VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc.initialLayout = pAttInfo->imageLayout; - attDesc.finalLayout = pAttInfo->imageLayout; - attachmentDescriptors[attDescIdx++] = attDesc; + // Add subpass + _subpasses.emplace_back(this, pRenderingInfo); - if (pAttInfo->resolveImageView && pAttInfo->resolveMode != VK_RESOLVE_MODE_NONE) { - attDesc.samples = VK_SAMPLE_COUNT_1_BIT; - attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.stencilStoreOp = pStencilAttInfo ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc.initialLayout = pAttInfo->resolveImageLayout; - attDesc.finalLayout = pAttInfo->resolveImageLayout; - attachmentDescriptors[attDescIdx++] = attDesc; - } + // Link attachments to subpasses + for (auto& att : _attachments) { + att.linkToSubpasses(); } } -MVKRenderPass* mvkCreateRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo) { - - // Renderpass attachments are sequentially indexed in this order: - // [color, color-resolve], ..., ds, ds-resolve - // skipping any attachments that do not have a VkImageView - uint32_t maxAttDescCnt = (pRenderingInfo->colorAttachmentCount + 1) * 2; - VkAttachmentDescription2 attachmentDescriptors[maxAttDescCnt]; - VkAttachmentReference2 colorAttachmentRefs[pRenderingInfo->colorAttachmentCount]; - VkAttachmentReference2 resolveAttachmentRefs[pRenderingInfo->colorAttachmentCount]; - - VkAttachmentReference2 attRef; - attRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2; - attRef.pNext = nullptr; - attRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - uint32_t attDescIdx = 0; - uint32_t caRefIdx = 0; - bool hasClrRslvAtt = false; - for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) { - auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx]; - if (clrAtt.imageView) { - attRef.layout = clrAtt.imageLayout; - attRef.attachment = attDescIdx; - colorAttachmentRefs[caRefIdx] = attRef; - - if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) { - attRef.layout = clrAtt.resolveImageLayout; - attRef.attachment = attDescIdx + 1; - resolveAttachmentRefs[caRefIdx] = attRef; - hasClrRslvAtt = true; - } - caRefIdx++; - } - mvkAddAttachmentDescriptor(&clrAtt, nullptr, attachmentDescriptors, attDescIdx); - } - - // Combine depth and stencil attachments into one depth-stencil attachment. - // If both depth and stencil are present, their views and layouts must match. - VkAttachmentReference2 dsAttRef; - VkAttachmentReference2 dsRslvAttRef; - VkResolveModeFlagBits depthResolveMode = VK_RESOLVE_MODE_NONE; - VkResolveModeFlagBits stencilResolveMode = VK_RESOLVE_MODE_NONE; - - attRef.aspectMask = 0; - attRef.layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkImageLayout rslvLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - if (pRenderingInfo->pDepthAttachment && pRenderingInfo->pDepthAttachment->imageView) { - attRef.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - depthResolveMode = pRenderingInfo->pDepthAttachment->resolveMode; - attRef.layout = pRenderingInfo->pDepthAttachment->imageLayout; - rslvLayout = pRenderingInfo->pDepthAttachment->resolveImageLayout; - } - if (pRenderingInfo->pStencilAttachment && pRenderingInfo->pStencilAttachment->imageView) { - attRef.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - stencilResolveMode = pRenderingInfo->pStencilAttachment->resolveMode; - attRef.layout = pRenderingInfo->pStencilAttachment->imageLayout; - rslvLayout = pRenderingInfo->pStencilAttachment->resolveImageLayout; - } - - attRef.attachment = attRef.aspectMask ? attDescIdx : VK_ATTACHMENT_UNUSED; - dsAttRef = attRef; - - attRef.layout = rslvLayout; - attRef.attachment = attDescIdx + 1; - dsRslvAttRef = attRef; - - mvkAddAttachmentDescriptor(pRenderingInfo->pDepthAttachment, - pRenderingInfo->pStencilAttachment, - attachmentDescriptors, attDescIdx); - - // Depth/stencil resolve handled via VkSubpassDescription2 pNext - VkSubpassDescriptionDepthStencilResolve dsRslv; - dsRslv.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE; - dsRslv.pNext = nullptr; - dsRslv.depthResolveMode = depthResolveMode; - dsRslv.stencilResolveMode = stencilResolveMode; - dsRslv.pDepthStencilResolveAttachment = &dsRslvAttRef; - bool hasDSRslvAtt = depthResolveMode != VK_RESOLVE_MODE_NONE || stencilResolveMode != VK_RESOLVE_MODE_NONE; - - // Define the subpass - VkSubpassDescription2 spDesc; - spDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2; - spDesc.pNext = hasDSRslvAtt ? &dsRslv : nullptr; - spDesc.flags = 0; - spDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - spDesc.viewMask = pRenderingInfo->viewMask; - spDesc.inputAttachmentCount = 0; - spDesc.pInputAttachments = nullptr; - spDesc.colorAttachmentCount = caRefIdx; - spDesc.pColorAttachments = colorAttachmentRefs; - spDesc.pResolveAttachments = hasClrRslvAtt ? resolveAttachmentRefs : nullptr;; - spDesc.pDepthStencilAttachment = &dsAttRef; - spDesc.preserveAttachmentCount = 0; - spDesc.pPreserveAttachments = nullptr; - - // Define the renderpass - VkRenderPassCreateInfo2 rpCreateInfo; - rpCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2; - rpCreateInfo.pNext = nullptr; - rpCreateInfo.flags = 0; - rpCreateInfo.attachmentCount = attDescIdx; - rpCreateInfo.pAttachments = attachmentDescriptors; - rpCreateInfo.subpassCount = 1; - rpCreateInfo.pSubpasses = &spDesc; - rpCreateInfo.dependencyCount = 0; - rpCreateInfo.pDependencies = nullptr; - rpCreateInfo.correlatedViewMaskCount = 0; - rpCreateInfo.pCorrelatedViewMasks = nullptr; - - auto* mvkRP = device->createRenderPass(&rpCreateInfo, nullptr); - mvkRP->setRenderingFlags(pRenderingInfo->flags); - return mvkRP; -} -uint32_t mvkGetAttachments(const VkRenderingInfo* pRenderingInfo, - MVKImageView* attachments[], - VkClearValue clearValues[]) { +#pragma mark - +#pragma mark MVKRenderingAttachmentIterator - // Renderpass attachments are sequentially indexed in this order: - // [color, color-resolve], ..., ds, ds-resolve - // skipping any attachments that do not have a VkImageView - // For consistency, we populate the clear value of any resolve attachments, even though they are ignored. - uint32_t attIdx = 0; - for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) { - auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx]; - if (clrAtt.imageView) { - clearValues[attIdx] = clrAtt.clearValue; - attachments[attIdx++] = (MVKImageView*)clrAtt.imageView; - if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) { - clearValues[attIdx] = clrAtt.clearValue; - attachments[attIdx++] = (MVKImageView*)clrAtt.resolveImageView; - } - } +void MVKRenderingAttachmentIterator::iterate(MVKRenderingAttachmentInfoOperation attOperation) { + for (uint32_t caIdx = 0; caIdx < _pRenderingInfo->colorAttachmentCount; caIdx++) { + handleAttachment(&_pRenderingInfo->pColorAttachments[caIdx], VK_IMAGE_ASPECT_COLOR_BIT, attOperation); } + handleAttachment(_pRenderingInfo->pDepthAttachment, VK_IMAGE_ASPECT_DEPTH_BIT, attOperation); + handleAttachment(_pRenderingInfo->pStencilAttachment, VK_IMAGE_ASPECT_STENCIL_BIT, attOperation); +} - // We need to combine the DS attachments into one - auto* pDSAtt = pRenderingInfo->pDepthAttachment ? pRenderingInfo->pDepthAttachment : pRenderingInfo->pStencilAttachment; - if (pDSAtt) { - if (pDSAtt->imageView) { - clearValues[attIdx] = pDSAtt->clearValue; - attachments[attIdx++] = (MVKImageView*)pDSAtt->imageView; - } - if (pDSAtt->resolveImageView && pDSAtt->resolveMode != VK_RESOLVE_MODE_NONE) { - clearValues[attIdx] = pDSAtt->clearValue; - attachments[attIdx++] = (MVKImageView*)pDSAtt->resolveImageView; +void MVKRenderingAttachmentIterator::handleAttachment(const VkRenderingAttachmentInfo* pAttInfo, + VkImageAspectFlagBits aspect, + MVKRenderingAttachmentInfoOperation attOperation) { + if (pAttInfo && pAttInfo->imageView) { + attOperation(pAttInfo, aspect, false); + if (pAttInfo->resolveImageView && pAttInfo->resolveMode != VK_RESOLVE_MODE_NONE) { + attOperation(pAttInfo, aspect, true); } } - - return attIdx; } + +#pragma mark - +#pragma mark Support functions + bool mvkIsColorAttachmentUsed(const VkPipelineRenderingCreateInfo* pRendInfo, uint32_t colorAttIdx) { return pRendInfo && pRendInfo->pColorAttachmentFormats[colorAttIdx]; } @@ -1085,14 +1056,6 @@ bool mvkHasColorAttachments(const VkPipelineRenderingCreateInfo* pRendInfo) { return false; } -VkFormat mvkGetDepthStencilFormat(const VkPipelineRenderingCreateInfo* pRendInfo) { - return (pRendInfo - ? (pRendInfo->depthAttachmentFormat - ? pRendInfo->depthAttachmentFormat - : pRendInfo->stencilAttachmentFormat) - : VK_FORMAT_UNDEFINED); -} - uint32_t mvkGetNextViewMaskGroup(uint32_t viewMask, uint32_t* startView, uint32_t* viewCount, uint32_t *groupMask) { // First, find the first set bit. This is the start of the next clump of views to be rendered. // n.b. ffs(3) returns a 1-based index. This actually bit me during development of this feature. diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index ce68d29f8..60bafd8f8 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -70,7 +70,7 @@ MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_map_memory2, KHR_MAP_MEMORY_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_map_memory2, KHR_MAP_MEMORY_2, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_portability_subset, KHR_PORTABILITY_SUBSET, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE, 10.11, 8.0) From abb12a5288f5faa9abe80fea3334a4be51160ac2 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 26 Apr 2023 06:29:07 -0400 Subject: [PATCH 08/74] Fix Metal validation errors with dynamic rendering. - MVKPipeline validate depth & stencil formats before setting frag shader depth and stencil builtins, and before setting formats in MTLRenderPipelineDescriptor. - MVKCmdClearAttachments always set depth/stencil format if subpass includes a depth or stencil attachment, even if they are not being cleared. - MVKRenderingAttachmentIterator add synthetic attachment if depth or stencil attachment is not provided, but image format supports both depth and stencil. --- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 16 +++++---- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 3 ++ MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 13 +++++--- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h | 7 ++-- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm | 33 ++++++++++++++++--- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 0aa57b31f..7cee3bc01 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1446,15 +1446,17 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma // The depth value (including vertex position Z value) is held in the last index. clearColors[kMVKClearAttachmentDepthStencilIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal }; + MTLPixelFormat mtlDSFmt = pixFmts->getMTLPixelFormat(subpass->isStencilAttachmentUsed() + ? subpass->getStencilFormat() + : subpass->getDepthFormat()); + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlDSFmt; + + // If neither the depth or stencil attachments are being cleared, nor being used, don't try to clear them. bool isClearingDepth = _isClearingDepth && subpass->isDepthAttachmentUsed(); bool isClearingStencil = _isClearingStencil && subpass->isStencilAttachmentUsed(); - if (isClearingDepth) { - _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getDepthFormat()); - } else if (isClearingStencil) { - _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getStencilFormat()); - } else { - _rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex); - } + if ( !isClearingDepth && !isClearingStencil ) { + _rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex); + } if ( !_rpsKey.isAnyAttachmentEnabled() ) { return; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index c2a03ee53..fadc2504f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -560,6 +560,9 @@ class MVKImageView : public MVKVulkanAPIDeviceObject { /** Returns the 3D extent of this image at the specified mipmap level. */ VkExtent3D getExtent3D(uint8_t planeIndex = 0, uint32_t mipLevel = 0) { return _image->getExtent3D(planeIndex, mipLevel); } + /** Return the underlying image. */ + MVKImage* getImage() { return _image; } + #pragma mark Metal /** Returns the Metal texture underlying this image view. */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index bf5e3f130..19d0d06c1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -1471,8 +1471,12 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 // Depth & stencil attachment formats MVKPixelFormats* pixFmts = getPixelFormats(); - plDesc.depthAttachmentPixelFormat = pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat); - plDesc.stencilAttachmentPixelFormat = pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat); + + MTLPixelFormat mtlDepthPixFmt = pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat); + if (pixFmts->isDepthFormat(mtlDepthPixFmt)) { plDesc.depthAttachmentPixelFormat = mtlDepthPixFmt; } + + MTLPixelFormat mtlStencilPixFmt = pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat); + if (pixFmts->isStencilFormat(mtlStencilPixFmt)) { plDesc.stencilAttachmentPixelFormat = mtlStencilPixFmt; } // In Vulkan, it's perfectly valid to render without any attachments. In Metal, if that // isn't supported, and we have no attachments, then we have to add a dummy attachment. @@ -1552,6 +1556,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 _viewRangeBufferIndex = _indirectParamsIndex; const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); + MVKPixelFormats* pixFmts = getPixelFormats(); // Disable any unused color attachments, because Metal validation can complain if the // fragment shader outputs a color value without a corresponding color attachment. @@ -1571,8 +1576,8 @@ 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.enable_point_size_builtin = isRenderingPoints(pCreateInfo) || reflectData.pointMode; - shaderConfig.options.mslOptions.enable_frag_depth_builtin = (pRendInfo->depthAttachmentFormat != VK_FORMAT_UNDEFINED); - shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = (pRendInfo->stencilAttachmentFormat != VK_FORMAT_UNDEFINED); + 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.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; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h index 7d1bb1b00..534ec018f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h @@ -340,14 +340,17 @@ class MVKRenderingAttachmentIterator : public MVKBaseObject { /** Iterates the attachments with the specified lambda function. */ void iterate(MVKRenderingAttachmentInfoOperation attOperation); - MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo) : _pRenderingInfo(pRenderingInfo) {} + MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo); protected: void handleAttachment(const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, MVKRenderingAttachmentInfoOperation attOperation); + const VkRenderingAttachmentInfo* getAttachmentInfo(const VkRenderingAttachmentInfo* pAtt, + const VkRenderingAttachmentInfo* pAltAtt, + bool isStencil); - const VkRenderingInfo* _pRenderingInfo; + VkRenderingInfo _renderingInfo; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index 2c4bf185d..af06d9b0b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm @@ -1021,11 +1021,11 @@ #pragma mark MVKRenderingAttachmentIterator void MVKRenderingAttachmentIterator::iterate(MVKRenderingAttachmentInfoOperation attOperation) { - for (uint32_t caIdx = 0; caIdx < _pRenderingInfo->colorAttachmentCount; caIdx++) { - handleAttachment(&_pRenderingInfo->pColorAttachments[caIdx], VK_IMAGE_ASPECT_COLOR_BIT, attOperation); + for (uint32_t caIdx = 0; caIdx < _renderingInfo.colorAttachmentCount; caIdx++) { + handleAttachment(&_renderingInfo.pColorAttachments[caIdx], VK_IMAGE_ASPECT_COLOR_BIT, attOperation); } - handleAttachment(_pRenderingInfo->pDepthAttachment, VK_IMAGE_ASPECT_DEPTH_BIT, attOperation); - handleAttachment(_pRenderingInfo->pStencilAttachment, VK_IMAGE_ASPECT_STENCIL_BIT, attOperation); + handleAttachment(_renderingInfo.pDepthAttachment, VK_IMAGE_ASPECT_DEPTH_BIT, attOperation); + handleAttachment(_renderingInfo.pStencilAttachment, VK_IMAGE_ASPECT_STENCIL_BIT, attOperation); } void MVKRenderingAttachmentIterator::handleAttachment(const VkRenderingAttachmentInfo* pAttInfo, @@ -1039,6 +1039,31 @@ } } +MVKRenderingAttachmentIterator::MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo) { + _renderingInfo = *pRenderingInfo; + _renderingInfo.pDepthAttachment = getAttachmentInfo(pRenderingInfo->pDepthAttachment, pRenderingInfo->pStencilAttachment, false); + _renderingInfo.pStencilAttachment = getAttachmentInfo(pRenderingInfo->pStencilAttachment, pRenderingInfo->pDepthAttachment, true); +} + +// If the depth/stencil attachment is not in use, but the alternate stencil/depth attachment is, +// and the MTLPixelFormat is usable by both attachments, force the use of the alternate attachment +// for both attachments, to avoid Metal validation errors when a pipeline expects both depth and +// stencil, but only one of the attachments has been provided here. +// Check the MTLPixelFormat of the MVKImage underlying the MVKImageView, to bypass possible +// substitution of MTLPixelFormat in the MVKImageView due to swizzling, or stencil-only access. +const VkRenderingAttachmentInfo* MVKRenderingAttachmentIterator::getAttachmentInfo(const VkRenderingAttachmentInfo* pAtt, + const VkRenderingAttachmentInfo* pAltAtt, + bool isStencil) { + bool useAlt = false; + if ( !(pAtt && pAtt->imageView) && (pAltAtt && pAltAtt->imageView) ) { + MVKImage* mvkImg = ((MVKImageView*)pAltAtt->imageView)->getImage(); + useAlt = (isStencil + ? mvkImg->getPixelFormats()->isStencilFormat(mvkImg->getMTLPixelFormat()) + : mvkImg->getPixelFormats()->isDepthFormat(mvkImg->getMTLPixelFormat())); + } + return useAlt ? pAltAtt : pAtt; +} + #pragma mark - #pragma mark Support functions From fd6b97317d542a76b86762a96c11beb3b2ee5d0e Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 27 Apr 2023 13:10:30 -0400 Subject: [PATCH 09/74] Clear attachments support separate depth and stencil attachments. - Also rename kMVKCachedColorAttachmentCount to kMVKMaxColorAttachmentCount and kMVKCachedViewportScissorCount to kMVKMaxViewportScissorCount and (unrelated) --- MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h | 4 +-- .../MoltenVK/Commands/MVKCmdRenderPass.mm | 4 +-- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h | 4 +-- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 29 +++++++------------ .../Commands/MVKCommandEncoderState.h | 4 +-- .../Commands/MVKCommandResourceFactory.h | 8 +++-- .../Commands/MVKCommandResourceFactory.mm | 29 +++++++++++-------- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 4 +-- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 10 +++---- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 4 +-- 10 files changed, 48 insertions(+), 52 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h index 4d6614752..66c7c304f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h @@ -262,7 +262,7 @@ class MVKCmdSetViewport : public MVKCommand { // Concrete template class implementations. typedef MVKCmdSetViewport<1> MVKCmdSetViewport1; -typedef MVKCmdSetViewport MVKCmdSetViewportMulti; +typedef MVKCmdSetViewport MVKCmdSetViewportMulti; #pragma mark - @@ -292,7 +292,7 @@ class MVKCmdSetScissor : public MVKCommand { // Concrete template class implementations. typedef MVKCmdSetScissor<1> MVKCmdSetScissor1; -typedef MVKCmdSetScissor MVKCmdSetScissorMulti; +typedef MVKCmdSetScissor MVKCmdSetScissorMulti; #pragma mark - diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm index 829264d3c..08bbe8513 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm @@ -282,7 +282,7 @@ } template class MVKCmdSetViewport<1>; -template class MVKCmdSetViewport; +template class MVKCmdSetViewport; #pragma mark - @@ -309,7 +309,7 @@ } template class MVKCmdSetScissor<1>; -template class MVKCmdSetScissor; +template class MVKCmdSetScissor; #pragma mark - diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h index ce0af39fd..e25158b6f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h @@ -284,8 +284,6 @@ class MVKCmdClearAttachments : public MVKCommand { float _mtlDepthVal; uint32_t _mtlStencilValue; MVKCommandUse _commandUse; - bool _isClearingDepth; - bool _isClearingStencil; }; @@ -326,7 +324,7 @@ class MVKCmdClearMultiAttachments : public MVKCmdClearAttachments { VkClearValue& getClearValue(uint32_t attIdx) override { return _vkClearValues[attIdx]; } void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) override { _vkClearValues[attIdx] = clearValue; } - VkClearValue _vkClearValues[kMVKCachedColorAttachmentCount]; + VkClearValue _vkClearValues[kMVKMaxColorAttachmentCount]; }; typedef MVKCmdClearMultiAttachments<1> MVKCmdClearMultiAttachments1; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 7cee3bc01..88e0b562d 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1260,8 +1260,6 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma _commandUse = cmdUse; _mtlDepthVal = 0.0; _mtlStencilValue = 0; - _isClearingDepth = false; - _isClearingStencil = false; MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats(); // For each attachment to be cleared, mark it so in the render pipeline state @@ -1279,14 +1277,12 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma } if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT)) { - _isClearingDepth = true; - _rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex); + _rpsKey.enableAttachment(kMVKClearAttachmentDepthIndex); _mtlDepthVal = pixFmts->getMTLClearDepthValue(clrAtt.clearValue); } if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT)) { - _isClearingStencil = true; - _rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex); + _rpsKey.enableAttachment(kMVKClearAttachmentStencilIndex); _mtlStencilValue = pixFmts->getMTLClearStencilValue(clrAtt.clearValue); } } @@ -1443,20 +1439,14 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma clearColors[caIdx] = { (float)mtlCC.red, (float)mtlCC.green, (float)mtlCC.blue, (float)mtlCC.alpha}; } - // The depth value (including vertex position Z value) is held in the last index. - clearColors[kMVKClearAttachmentDepthStencilIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal }; + // The depth value is the vertex position Z value. + clearColors[kMVKClearAttachmentDepthIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal }; - MTLPixelFormat mtlDSFmt = pixFmts->getMTLPixelFormat(subpass->isStencilAttachmentUsed() - ? subpass->getStencilFormat() - : subpass->getDepthFormat()); - _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlDSFmt; + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthIndex] = pixFmts->getMTLPixelFormat(subpass->getDepthFormat()); + if ( !subpass->isDepthAttachmentUsed() ) { _rpsKey.disableAttachment(kMVKClearAttachmentDepthIndex); } - // If neither the depth or stencil attachments are being cleared, nor being used, don't try to clear them. - bool isClearingDepth = _isClearingDepth && subpass->isDepthAttachmentUsed(); - bool isClearingStencil = _isClearingStencil && subpass->isStencilAttachmentUsed(); - if ( !isClearingDepth && !isClearingStencil ) { - _rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex); - } + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getStencilFormat()); + if ( !subpass->isStencilAttachmentUsed() ) { _rpsKey.disableAttachment(kMVKClearAttachmentStencilIndex); } if ( !_rpsKey.isAnyAttachmentEnabled() ) { return; } @@ -1465,7 +1455,8 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma id mtlRendEnc = cmdEncoder->_mtlRenderEncoder; [mtlRendEnc pushDebugGroup: getMTLDebugGroupLabel()]; [mtlRendEnc setRenderPipelineState: cmdEncPool->getCmdClearMTLRenderPipelineState(_rpsKey)]; - [mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(isClearingDepth, isClearingStencil)]; + [mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(_rpsKey.isAttachmentUsed(kMVKClearAttachmentDepthIndex), + _rpsKey.isAttachmentUsed(kMVKClearAttachmentStencilIndex))]; [mtlRendEnc setStencilReferenceValue: _mtlStencilValue]; [mtlRendEnc setCullMode: MTLCullModeNone]; [mtlRendEnc setTriangleFillMode: MTLTriangleFillModeFill]; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 9caca16c7..b47cc22e2 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -152,7 +152,7 @@ class MVKViewportCommandEncoderState : public MVKCommandEncoderState { protected: void encodeImpl(uint32_t stage) override; - MVKSmallVector _viewports, _dynamicViewports; + MVKSmallVector _viewports, _dynamicViewports; }; @@ -180,7 +180,7 @@ class MVKScissorCommandEncoderState : public MVKCommandEncoderState { protected: void encodeImpl(uint32_t stage) override; - MVKSmallVector _scissors, _dynamicScissors; + MVKSmallVector _scissors, _dynamicScissors; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index bd30da20c..1e37844f9 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -107,9 +107,11 @@ namespace std { #pragma mark - #pragma mark MVKRPSKeyClearAtt -#define kMVKClearAttachmentCount (kMVKCachedColorAttachmentCount + 1) -#define kMVKClearAttachmentDepthStencilIndex (kMVKClearAttachmentCount - 1) -#define kMVKClearAttachmentLayeredRenderingBitIndex kMVKClearAttachmentCount +const static uint32_t kMVKClearColorAttachmentCount = kMVKMaxColorAttachmentCount; +const static uint32_t kMVKClearAttachmentDepthIndex = kMVKClearColorAttachmentCount; +const static uint32_t kMVKClearAttachmentStencilIndex = kMVKClearAttachmentDepthIndex + 1; +const static uint32_t kMVKClearAttachmentCount = kMVKClearAttachmentStencilIndex + 1; +const static uint32_t kMVKClearAttachmentLayeredRenderingBitIndex = kMVKClearAttachmentStencilIndex + 1; /** * Key to use for looking up cached MTLRenderPipelineState instances. diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index d6c6efb6d..36fb03b7c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -113,6 +113,8 @@ id MVKCommandResourceFactory::newCmdClearMTLRenderPipelineState(MVKRPSKeyClearAtt& attKey, MVKVulkanAPIDeviceObject* owner) { + MVKPixelFormats* pixFmts = getPixelFormats(); + id vtxFunc = newClearVertFunction(attKey); // temp retain id fragFunc = newClearFragFunction(attKey); // temp retain MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // temp retain @@ -122,15 +124,17 @@ plDesc.sampleCount = attKey.mtlSampleCount; plDesc.inputPrimitiveTopologyMVK = MTLPrimitiveTopologyClassTriangle; - for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { + for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) { MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[caIdx]; colorDesc.pixelFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]; colorDesc.writeMask = attKey.isAttachmentEnabled(caIdx) ? MTLColorWriteMaskAll : MTLColorWriteMaskNone; } - MVKPixelFormats* pixFmts = getPixelFormats(); - MTLPixelFormat mtlDSFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex]; - if (pixFmts->isDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; } - if (pixFmts->isStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; } + + MTLPixelFormat mtlDepthFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthIndex]; + if (pixFmts->isDepthFormat(mtlDepthFormat)) { plDesc.depthAttachmentPixelFormat = mtlDepthFormat; } + + MTLPixelFormat mtlStencilFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentStencilIndex]; + if (pixFmts->isStencilFormat(mtlStencilFormat)) { plDesc.stencilAttachmentPixelFormat = mtlStencilFormat; } MTLVertexDescriptor* vtxDesc = plDesc.vertexDescriptor; @@ -273,7 +277,7 @@ [msl appendLineMVK: @" return out;"]; [msl appendLineMVK: @"}"]; -// MVKLogDebug("\n%s", msl.UTF8String); +// MVKLogInfo("\n%s", msl.UTF8String); return newMTLFunction(msl, funcName); } @@ -300,15 +304,16 @@ [msl appendLineMVK]; NSString* funcName = @"vertClear"; - [msl appendFormat: @"vertex VaryingsPos %@(AttributesPos attributes [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) {", funcName]; + [msl appendFormat: @"vertex VaryingsPos %@(AttributesPos attributes [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) {", funcName]; [msl appendLineMVK]; [msl appendLineMVK: @" VaryingsPos varyings;"]; - [msl appendLineMVK: @" varyings.v_position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[8].r, 1.0);"]; + [msl appendFormat: @" varyings.v_position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[%d].r, 1.0);", kMVKClearAttachmentDepthIndex]; + [msl appendLineMVK]; [msl appendLineMVK: @" varyings.layer = uint(attributes.a_position.w);"]; [msl appendLineMVK: @" return varyings;"]; [msl appendLineMVK: @"}"]; -// MVKLogDebug("\n%s", msl.UTF8String); +// MVKLogInfo("\n%s", msl.UTF8String); return newMTLFunction(msl, funcName); } @@ -329,7 +334,7 @@ [msl appendLineMVK: @"} ClearColorsIn;"]; [msl appendLineMVK]; [msl appendLineMVK: @"typedef struct {"]; - for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { + for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) { if (attKey.isAttachmentUsed(caIdx)) { NSString* typeStr = getMTLFormatTypeString((MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]); [msl appendFormat: @" %@4 color%u [[color(%u)]];", typeStr, caIdx, caIdx]; @@ -343,7 +348,7 @@ [msl appendFormat: @"fragment ClearColorsOut %@(VaryingsPos varyings [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) {", funcName]; [msl appendLineMVK]; [msl appendLineMVK: @" ClearColorsOut ccOut;"]; - for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { + for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) { if (attKey.isAttachmentUsed(caIdx)) { NSString* typeStr = getMTLFormatTypeString((MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]); [msl appendFormat: @" ccOut.color%u = %@4(ccIn.colors[%u]);", caIdx, typeStr, caIdx]; @@ -353,7 +358,7 @@ [msl appendLineMVK: @" return ccOut;"]; [msl appendLineMVK: @"}"]; -// MVKLogDebug("\n%s", msl.UTF8String); +// MVKLogInfo("\n%s", msl.UTF8String); return newMTLFunction(msl, funcName); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index b02cc7784..42921801e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -80,8 +80,8 @@ const static uint32_t kMVKQueueFamilyCount = 4; const static uint32_t kMVKQueueCountPerQueueFamily = 1; // Must be 1. See comments in MVKPhysicalDevice::getQueueFamilies() const static uint32_t kMVKMinSwapchainImageCount = 2; const static uint32_t kMVKMaxSwapchainImageCount = 3; -const static uint32_t kMVKCachedViewportScissorCount = 16; -const static uint32_t kMVKCachedColorAttachmentCount = 8; +const static uint32_t kMVKMaxColorAttachmentCount = 8; +const static uint32_t kMVKMaxViewportScissorCount = 16; const static uint32_t kMVKMaxDescriptorSetCount = SPIRV_CROSS_NAMESPACE::kMaxArgumentBuffers; #if !MVK_XCODE_12 diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 8cdca02bd..8937b90a3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2269,17 +2269,17 @@ void MVKPhysicalDevice::initLimits() { #if MVK_TVOS - _properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount; + _properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount; #endif #if MVK_IOS if (supportsMTLFeatureSet(iOS_GPUFamily2_v1)) { - _properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount; + _properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount; } else { - _properties.limits.maxColorAttachments = 4; // < kMVKCachedColorAttachmentCount + _properties.limits.maxColorAttachments = 4; // < kMVKMaxColorAttachmentCount } #endif #if MVK_MACOS - _properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount; + _properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount; #endif _properties.limits.maxFragmentOutputAttachments = _properties.limits.maxColorAttachments; @@ -2309,7 +2309,7 @@ float maxVPDim = max(_properties.limits.maxViewportDimensions[0], _properties.limits.maxViewportDimensions[1]); _properties.limits.viewportBoundsRange[0] = (-2.0 * maxVPDim); _properties.limits.viewportBoundsRange[1] = (2.0 * maxVPDim) - 1; - _properties.limits.maxViewports = _features.multiViewport ? kMVKCachedViewportScissorCount : 1; + _properties.limits.maxViewports = _features.multiViewport ? kMVKMaxViewportScissorCount : 1; _properties.limits.maxImageDimension3D = _metalFeatures.maxTextureLayers; _properties.limits.maxImageArrayLayers = _metalFeatures.maxTextureLayers; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 154bcf674..efb7c4926 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -350,8 +350,8 @@ class MVKGraphicsPipeline : public MVKPipeline { VkPipelineRasterizationStateCreateInfo _rasterInfo; VkPipelineDepthStencilStateCreateInfo _depthStencilInfo; - MVKSmallVector _viewports; - MVKSmallVector _scissors; + MVKSmallVector _viewports; + MVKSmallVector _scissors; MVKSmallVector _dynamicState; MVKSmallVector _customSamplePositions; MVKSmallVector _translatedVertexBindings; From 937b0bf9437539701bafe47f2b2e0496bca65bf2 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 1 May 2023 17:30:21 -0400 Subject: [PATCH 10/74] Deprecate the obsolete and non-standard VK_MVK_moltenvk extension. The VK_MVK_moltenvk extension has never been brought inside Vulkan, and the functions have never been supported by the Vulkan Loader and Layers. Most of the functionality has long been replaced by the official VK_metal_objects extension. - Remove VK_MVK_moltenvk as an advertised extension. - Refactor vk_mvk_moltenvk.h header file into separate headers files: - mvk_config.h - Valid public config functions - mvk_private_api.h - Valid development debugging functions used with care - mvk_deprecated_api.h - Formally deprecated functions. - Retain skeleton vk_mvk_moltenvk.h header file for legacy compatibility only. - Update documentation and header comments to explain changes. --- Docs/MoltenVK_Runtime_UserGuide.md | 67 +- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 40 +- MoltenVK/MoltenVK/API/mvk_config.h | 1061 ++++++++++++ MoltenVK/MoltenVK/API/mvk_datatypes.h | 16 +- MoltenVK/MoltenVK/API/mvk_deprecated_api.h | 215 +++ MoltenVK/MoltenVK/API/mvk_private_api.h | 296 ++++ MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 1425 +---------------- MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm | 1 - MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 1 - MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm | 1 - MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 1 - .../MoltenVK/GPUObjects/MVKDeviceMemory.mm | 1 - MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 1 - MoltenVK/MoltenVK/GPUObjects/MVKInstance.h | 1 - MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 6 + .../MoltenVK/GPUObjects/MVKPixelFormats.h | 5 +- MoltenVK/MoltenVK/GPUObjects/MVKResource.mm | 1 - MoltenVK/MoltenVK/GPUObjects/MVKSurface.h | 1 - MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 - MoltenVK/MoltenVK/Layers/MVKExtensions.mm | 4 - MoltenVK/MoltenVK/Layers/MVKLayers.mm | 1 - MoltenVK/MoltenVK/OS/MVKGPUCapture.mm | 2 - MoltenVK/MoltenVK/Utility/MVKBaseObject.h | 2 +- MoltenVK/MoltenVK/Utility/MVKCodec.h | 1 - MoltenVK/MoltenVK/Utility/MVKCodec.mm | 2 + MoltenVK/MoltenVK/Utility/MVKEnvironment.h | 3 +- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 3 +- MoltenVK/MoltenVK/Utility/MVKWatermark.mm | 2 +- .../Vulkan/{vk_mvk_moltenvk.mm => mvk_api.mm} | 19 +- README.md | 6 +- Scripts/runcts | 3 +- 33 files changed, 1690 insertions(+), 1502 deletions(-) create mode 100644 MoltenVK/MoltenVK/API/mvk_config.h create mode 100644 MoltenVK/MoltenVK/API/mvk_deprecated_api.h create mode 100644 MoltenVK/MoltenVK/API/mvk_private_api.h rename MoltenVK/MoltenVK/Vulkan/{vk_mvk_moltenvk.mm => mvk_api.mm} (96%) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index a4d951594..98abf8f91 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -25,7 +25,7 @@ Table of Contents - [Install *MoltenVK* replacing the Vulkan SDK `libMoltenVK.dylib`](#install_vksdk) - [Build and Runtime Requirements](#requirements) - [Interacting with the **MoltenVK** Runtime](#interaction) - - [MoltenVK `VK_MVK_moltenvk` Extension](#moltenvk_extension) + - [MoltenVK Header Files](#moltenvk_headers) - [Configuring MoltenVK](#moltenvk_config) - [*Metal Shading Language* Shaders](#shaders) - [Troubleshooting Shader Conversion](#spv_vs_msl) @@ -384,7 +384,6 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_texture_compression_astc_hdr` *(iOS and macOS, requires family 6 (A13) or better Apple GPU)* - `VK_MVK_ios_surface` *(iOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)* - `VK_MVK_macos_surface` *(macOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)* -- `VK_MVK_moltenvk` - `VK_AMD_gpu_shader_half_float` - `VK_AMD_negative_viewport_height` - `VK_AMD_shader_image_load_store_lod` *(requires Apple GPU)* @@ -425,14 +424,12 @@ extension in the *Vulkan* specification for more information about the use of th `VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` flag. + +### MoltenVK Header Files - -### MoltenVK `VK_MVK_moltenvk` Extension - -The `VK_MVK_moltenvk` *Vulkan* extension provides functionality beyond standard *Vulkan* functionality, -to support configuration options and behaviour that is specific to the **MoltenVK** implementation of *Vulkan* -functionality. You can access this functionality by including the `vk_mvk_moltenvk.h` header file in your code. -The `vk_mvk_moltenvk.h` file also includes the API documentation for this `VK_MVK_moltenvk` extension. +**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 can be included in your application source code as follows: @@ -441,37 +438,33 @@ can be included in your application source code as follows: where `HEADER_FILE` is one of the following: -- `vk_mvk_moltenvk.h` - Contains declarations and documentation for the functions, structures, - and enumerations that define the behaviour of the `VK_MVK_moltenvk` *Vulkan* extension. - -- `mvk_vulkan.h` - This is a convenience header file that loads the `vulkan.h` header file - with the appropriate **MoltenVK** *Vulkan* platform surface extension automatically - enabled for *macOS*, *iOS*, or *tvOS*. Use this header file in place of the `vulkan.h` - header file, where access to a **MoltenVK** platform surface extension is required. - - The `mvk_vulkan.h` header file automatically enables the `VK_USE_PLATFORM_METAL_EXT` - build setting and `VK_EXT_metal_surface` *Vulkan* extension. +- `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_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 for your own purposes such as interacting with *Metal* - directly, or simply logging data values. - ->***Note:*** Except for `vkGetMoltenVKConfigurationMVK()` and `vkSetMoltenVKConfigurationMVK()`, - the functions in `vk_mvk_moltenvk.h` are not supported by the *Vulkan SDK Loader and Layers* - framework. The opaque Vulkan objects used by the functions in `vk_mvk_moltenvk.h` (`VkPhysicalDevice`, - `VkShaderModule`, `VKImage`, ...), must have been retrieved directly from **MoltenVK**, and not through - the *Vulkan SDK Loader and Layers* framework. The *Vulkan SDK Loader and Layers* framework often changes - these opaque objects, and passing them from a higher layer directly to **MoltenVK** will result in - undefined behaviour. +- `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_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 -The `VK_MVK_moltenvk` *Vulkan* extension provides the ability to configure and optimize -**MoltenVK** for your particular application runtime requirements. +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. There are three mechanisms for setting the values of the **MoltenVK** configuration parameters: @@ -488,9 +481,9 @@ by a corresponding environment variable, or if the environment variable is not s 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. -See the description of the `MVKConfiguration` structure parameters and corresponding environment -variables in the `vk_mvk_moltenvk.h` file for more info about configuring and optimizing -**MoltenVK** at runtime or build time. +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. diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 1917e97de..add2a09e3 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -22,6 +22,7 @@ Released TBD - `VK_KHR_map_memory2` - Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). - Support separate depth and stencil attachments during dynamic rendering. +- Deprecate the obsolete and non-standard `VK_MVK_moltenvk` extension. - Fix memory leak when waiting on timeline semaphores. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index 2c4b87eb0..ff2a8fdef 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -105,7 +105,7 @@ 2FEA0AA324902F9F00EEF3AD /* MVKRenderPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7941C7DFB4800632CA3 /* MVKRenderPass.mm */; }; 2FEA0AA424902F9F00EEF3AD /* MVKCmdTransfer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB76D1C7DFB4800632CA3 /* MVKCmdTransfer.mm */; }; 2FEA0AA524902F9F00EEF3AD /* MVKCmdQueries.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7711C7DFB4800632CA3 /* MVKCmdQueries.mm */; }; - 2FEA0AA624902F9F00EEF3AD /* vk_mvk_moltenvk.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* vk_mvk_moltenvk.mm */; }; + 2FEA0AA624902F9F00EEF3AD /* mvk_api.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* mvk_api.mm */; }; 2FEA0AA724902F9F00EEF3AD /* MVKSwapchain.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB79C1C7DFB4800632CA3 /* MVKSwapchain.mm */; }; 2FEA0AA824902F9F00EEF3AD /* MVKCommandEncoderState.mm in Sources */ = {isa = PBXBuildFile; fileRef = A95B7D681D3EE486003183D3 /* MVKCommandEncoderState.mm */; }; 2FEA0AA924902F9F00EEF3AD /* MVKGPUCapture.mm in Sources */ = {isa = PBXBuildFile; fileRef = A93E83342121F0C8001FEBD4 /* MVKGPUCapture.mm */; }; @@ -261,8 +261,8 @@ A94FB81F1C7DFB4800632CA3 /* MVKLayers.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A11C7DFB4800632CA3 /* MVKLayers.mm */; }; A94FB82A1C7DFB4800632CA3 /* mvk_datatypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A91C7DFB4800632CA3 /* mvk_datatypes.mm */; }; A94FB82B1C7DFB4800632CA3 /* mvk_datatypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A91C7DFB4800632CA3 /* mvk_datatypes.mm */; }; - A94FB8301C7DFB4800632CA3 /* vk_mvk_moltenvk.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* vk_mvk_moltenvk.mm */; }; - A94FB8311C7DFB4800632CA3 /* vk_mvk_moltenvk.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* vk_mvk_moltenvk.mm */; }; + A94FB8301C7DFB4800632CA3 /* mvk_api.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* mvk_api.mm */; }; + A94FB8311C7DFB4800632CA3 /* mvk_api.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* mvk_api.mm */; }; A94FB8321C7DFB4800632CA3 /* vulkan.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AD1C7DFB4800632CA3 /* vulkan.mm */; }; A94FB8331C7DFB4800632CA3 /* vulkan.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AD1C7DFB4800632CA3 /* vulkan.mm */; }; A95870F81C90D29F009EB096 /* MVKCommandResourceFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = A95870F61C90D29F009EB096 /* MVKCommandResourceFactory.h */; }; @@ -318,6 +318,15 @@ A9A5E9C725C0822700E9085E /* MVKEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */; }; A9A5E9C825C0822700E9085E /* MVKEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */; }; A9A5E9C925C0822700E9085E /* MVKEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */; }; + A9B3D73B29F9B3B100745CD4 /* mvk_deprecated_api.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D73829F9B3B100745CD4 /* mvk_deprecated_api.h */; }; + A9B3D73C29F9B3B100745CD4 /* mvk_deprecated_api.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D73829F9B3B100745CD4 /* mvk_deprecated_api.h */; }; + A9B3D73D29F9B3B100745CD4 /* mvk_deprecated_api.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D73829F9B3B100745CD4 /* mvk_deprecated_api.h */; }; + A9B3D73E29F9B3B100745CD4 /* mvk_config.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D73A29F9B3B100745CD4 /* mvk_config.h */; }; + A9B3D73F29F9B3B100745CD4 /* mvk_config.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D73A29F9B3B100745CD4 /* mvk_config.h */; }; + A9B3D74029F9B3B100745CD4 /* mvk_config.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D73A29F9B3B100745CD4 /* mvk_config.h */; }; + A9B3D74229F9BDEE00745CD4 /* mvk_private_api.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D74129F9BDEE00745CD4 /* mvk_private_api.h */; }; + A9B3D74329F9BDEE00745CD4 /* mvk_private_api.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D74129F9BDEE00745CD4 /* mvk_private_api.h */; }; + A9B3D74429F9BDEE00745CD4 /* mvk_private_api.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B3D74129F9BDEE00745CD4 /* mvk_private_api.h */; }; A9B51BD7225E986A00AC74D2 /* MVKOSExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */; }; A9B51BD8225E986A00AC74D2 /* MVKOSExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */; }; A9B51BD9225E986A00AC74D2 /* MVKOSExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */; }; @@ -493,7 +502,7 @@ A94FB7A01C7DFB4800632CA3 /* MVKLayers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKLayers.h; sourceTree = ""; }; A94FB7A11C7DFB4800632CA3 /* MVKLayers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKLayers.mm; sourceTree = ""; }; A94FB7A91C7DFB4800632CA3 /* mvk_datatypes.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mvk_datatypes.mm; sourceTree = ""; }; - A94FB7AC1C7DFB4800632CA3 /* vk_mvk_moltenvk.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = vk_mvk_moltenvk.mm; sourceTree = ""; }; + A94FB7AC1C7DFB4800632CA3 /* mvk_api.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mvk_api.mm; sourceTree = ""; }; A94FB7AD1C7DFB4800632CA3 /* vulkan.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = vulkan.mm; sourceTree = ""; }; A95870F61C90D29F009EB096 /* MVKCommandResourceFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCommandResourceFactory.h; sourceTree = ""; }; A95870F71C90D29F009EB096 /* MVKCommandResourceFactory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCommandResourceFactory.mm; sourceTree = ""; }; @@ -521,6 +530,9 @@ A99C91012295FAC500A061DA /* MVKVulkanAPIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKVulkanAPIObject.h; sourceTree = ""; }; A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MVKEnvironment.cpp; sourceTree = ""; }; A9AD67C72054DD6C00ED3C08 /* vulkan */ = {isa = PBXFileReference; lastKnownFileType = folder; path = vulkan; sourceTree = ""; }; + A9B3D73829F9B3B100745CD4 /* mvk_deprecated_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mvk_deprecated_api.h; sourceTree = ""; }; + A9B3D73A29F9B3B100745CD4 /* mvk_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mvk_config.h; sourceTree = ""; }; + A9B3D74129F9BDEE00745CD4 /* mvk_private_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mvk_private_api.h; sourceTree = ""; }; A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKOSExtensions.mm; sourceTree = ""; }; A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKOSExtensions.h; sourceTree = ""; }; A9B8EE0A1A98D796009C5A02 /* libMoltenVK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMoltenVK.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -569,7 +581,10 @@ A94FB7651C7DFB4800632CA3 /* API */ = { isa = PBXGroup; children = ( + A9B3D73A29F9B3B100745CD4 /* mvk_config.h */, A94FB7671C7DFB4800632CA3 /* mvk_datatypes.h */, + A9B3D73829F9B3B100745CD4 /* mvk_deprecated_api.h */, + A9B3D74129F9BDEE00745CD4 /* mvk_private_api.h */, A948BB7E1E51642700DE59F2 /* mvk_vulkan.h */, A94FB7691C7DFB4800632CA3 /* vk_mvk_moltenvk.h */, ); @@ -676,7 +691,7 @@ children = ( A9CEAAD1227378D400FAF779 /* mvk_datatypes.hpp */, A94FB7A91C7DFB4800632CA3 /* mvk_datatypes.mm */, - A94FB7AC1C7DFB4800632CA3 /* vk_mvk_moltenvk.mm */, + A94FB7AC1C7DFB4800632CA3 /* mvk_api.mm */, A94FB7AD1C7DFB4800632CA3 /* vulkan.mm */, ); path = Vulkan; @@ -819,9 +834,11 @@ 2FEA0A5624902F9F00EEF3AD /* MVKWatermarkShaderSource.h in Headers */, 2FEA0A5724902F9F00EEF3AD /* MTLSamplerDescriptor+MoltenVK.h in Headers */, 2FEA0A5824902F9F00EEF3AD /* MVKSync.h in Headers */, + A9B3D73F29F9B3B100745CD4 /* mvk_config.h in Headers */, 2FEA0A5924902F9F00EEF3AD /* MVKDevice.h in Headers */, 2FEA0A5A24902F9F00EEF3AD /* MVKSmallVector.h in Headers */, 2FEA0A5C24902F9F00EEF3AD /* MVKCommandPool.h in Headers */, + A9B3D74329F9BDEE00745CD4 /* mvk_private_api.h in Headers */, 2FEA0A5D24902F9F00EEF3AD /* MVKShaderModule.h in Headers */, 2FEA0A5E24902F9F00EEF3AD /* MVKVulkanAPIObject.h in Headers */, 2FEA0A5F24902F9F00EEF3AD /* MVKCmdQueries.h in Headers */, @@ -844,6 +861,7 @@ 2FEA0A7024902F9F00EEF3AD /* MVKCmdTransfer.h in Headers */, 2FEA0A7124902F9F00EEF3AD /* MVKDescriptor.h in Headers */, 2FEA0A7224902F9F00EEF3AD /* MVKCmdDraw.h in Headers */, + A9B3D73C29F9B3B100745CD4 /* mvk_deprecated_api.h in Headers */, 2FEA0A7324902F9F00EEF3AD /* MVKCommandBuffer.h in Headers */, 2FEA0A7424902F9F00EEF3AD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */, 2FEA0A7524902F9F00EEF3AD /* MVKCmdDebug.h in Headers */, @@ -870,6 +888,7 @@ A909F65F213B190700FCD6BE /* MVKExtensions.h in Headers */, A94FB7B41C7DFB4800632CA3 /* vk_mvk_moltenvk.h in Headers */, A987B669289AFB8A00F933C8 /* MVKDeviceFeatureStructs.def in Headers */, + A9B3D73E29F9B3B100745CD4 /* mvk_config.h in Headers */, A94FB7B01C7DFB4800632CA3 /* mvk_datatypes.h in Headers */, A948BB7F1E51642700DE59F2 /* mvk_vulkan.h in Headers */, A98149511FB6A3F7005F00B4 /* MVKEnvironment.h in Headers */, @@ -899,10 +918,12 @@ A94FB80C1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */, A99C91042295FAC600A061DA /* MVKVulkanAPIObject.h in Headers */, A94FB7C01C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */, + A9B3D73B29F9B3B100745CD4 /* mvk_deprecated_api.h in Headers */, A94FB7CC1C7DFB4800632CA3 /* MVKCommand.h in Headers */, A981494F1FB6A3F7005F00B4 /* MVKBaseObject.h in Headers */, A9C96DD01DDC20C20053187F /* MVKMTLBufferAllocation.h in Headers */, A98149571FB6A3F7005F00B4 /* MVKObjectPool.h in Headers */, + A9B3D74229F9BDEE00745CD4 /* mvk_private_api.h in Headers */, A94FB8141C7DFB4800632CA3 /* MVKSwapchain.h in Headers */, A93E832F2121C5D4001FEBD4 /* MVKGPUCapture.h in Headers */, A94FB7DC1C7DFB4800632CA3 /* MVKBuffer.h in Headers */, @@ -944,6 +965,7 @@ A909F660213B190700FCD6BE /* MVKExtensions.h in Headers */, A94FB7B51C7DFB4800632CA3 /* vk_mvk_moltenvk.h in Headers */, A987B66B289AFB8C00F933C8 /* MVKDeviceFeatureStructs.def in Headers */, + A9B3D74029F9B3B100745CD4 /* mvk_config.h in Headers */, A94FB7B11C7DFB4800632CA3 /* mvk_datatypes.h in Headers */, A948BB801E51642700DE59F2 /* mvk_vulkan.h in Headers */, A98149521FB6A3F7005F00B4 /* MVKEnvironment.h in Headers */, @@ -973,10 +995,12 @@ A99C91052295FAC600A061DA /* MVKVulkanAPIObject.h in Headers */, A94FB7C11C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */, A94FB7CD1C7DFB4800632CA3 /* MVKCommand.h in Headers */, + A9B3D73D29F9B3B100745CD4 /* mvk_deprecated_api.h in Headers */, A98149501FB6A3F7005F00B4 /* MVKBaseObject.h in Headers */, A9C96DD11DDC20C20053187F /* MVKMTLBufferAllocation.h in Headers */, A98149581FB6A3F7005F00B4 /* MVKObjectPool.h in Headers */, A94FB8151C7DFB4800632CA3 /* MVKSwapchain.h in Headers */, + A9B3D74429F9BDEE00745CD4 /* mvk_private_api.h in Headers */, A93E83302121C5D4001FEBD4 /* MVKGPUCapture.h in Headers */, A94FB7DD1C7DFB4800632CA3 /* MVKBuffer.h in Headers */, A9F042A51FB4CF83009FCCB8 /* MVKCommonEnvironment.h in Headers */, @@ -1361,7 +1385,7 @@ 2FEA0AA324902F9F00EEF3AD /* MVKRenderPass.mm in Sources */, 2FEA0AA424902F9F00EEF3AD /* MVKCmdTransfer.mm in Sources */, 2FEA0AA524902F9F00EEF3AD /* MVKCmdQueries.mm in Sources */, - 2FEA0AA624902F9F00EEF3AD /* vk_mvk_moltenvk.mm in Sources */, + 2FEA0AA624902F9F00EEF3AD /* mvk_api.mm in Sources */, 2FEA0AA724902F9F00EEF3AD /* MVKSwapchain.mm in Sources */, 2FEA0AA824902F9F00EEF3AD /* MVKCommandEncoderState.mm in Sources */, 2FEA0AA924902F9F00EEF3AD /* MVKGPUCapture.mm in Sources */, @@ -1420,7 +1444,7 @@ A94FB8061C7DFB4800632CA3 /* MVKRenderPass.mm in Sources */, A94FB7BA1C7DFB4800632CA3 /* MVKCmdTransfer.mm in Sources */, A94FB7C21C7DFB4800632CA3 /* MVKCmdQueries.mm in Sources */, - A94FB8301C7DFB4800632CA3 /* vk_mvk_moltenvk.mm in Sources */, + A94FB8301C7DFB4800632CA3 /* mvk_api.mm in Sources */, A94FB8161C7DFB4800632CA3 /* MVKSwapchain.mm in Sources */, A95B7D6B1D3EE486003183D3 /* MVKCommandEncoderState.mm in Sources */, A93E83352121F0C8001FEBD4 /* MVKGPUCapture.mm in Sources */, @@ -1480,7 +1504,7 @@ A94FB8071C7DFB4800632CA3 /* MVKRenderPass.mm in Sources */, A94FB7BB1C7DFB4800632CA3 /* MVKCmdTransfer.mm in Sources */, A94FB7C31C7DFB4800632CA3 /* MVKCmdQueries.mm in Sources */, - A94FB8311C7DFB4800632CA3 /* vk_mvk_moltenvk.mm in Sources */, + A94FB8311C7DFB4800632CA3 /* mvk_api.mm in Sources */, A94FB8171C7DFB4800632CA3 /* MVKSwapchain.mm in Sources */, A95B7D6C1D3EE486003183D3 /* MVKCommandEncoderState.mm in Sources */, A93E83362121F0C8001FEBD4 /* MVKGPUCapture.mm in Sources */, diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h new file mode 100644 index 000000000..bd4d03cb4 --- /dev/null +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -0,0 +1,1061 @@ +/* + * mvk_config.h + * + * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#ifndef __mvk_config_h_ +#define __mvk_config_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include + + +/** This header contains the public configuration API for MoltenVK. */ + + +/** + * 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. + * + * 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 4 + +#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 37 + +/** 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_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. + * + * There are three mechanisms for setting the values of the MoltenVK configuration parameters: + * - Runtime API via the vkGetMoltenVKConfigurationMVK()/vkSetMoltenVKConfigurationMVK() functions. + * - 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 VK_MVK_MOLTENVK_SPEC_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. + */ +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_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 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; + +} 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 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 + * VK_MVK_MOLTENVK_SPEC_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 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 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 + * VK_MVK_MOLTENVK_SPEC_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 ignored, + 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 + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h index 76470233c..c5c2e182f 100644 --- a/MoltenVK/MoltenVK/API/mvk_datatypes.h +++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h @@ -16,14 +16,6 @@ * limitations under the License. */ - -/* - * This file contains functions for converting between Vulkan and Metal data types. - * - * The functions here are used internally by MoltenVK, and are exposed here - * as a convenience for use elsewhere within applications using MoltenVK. - */ - #ifndef __mvkDataTypes_h_ #define __mvkDataTypes_h_ 1 @@ -37,6 +29,14 @@ extern "C" { #import +/* + * This file contains functions for converting between Vulkan and Metal data types. + * + * The functions here are used internally by MoltenVK, and are exposed here + * as a convenience for use elsewhere within applications using MoltenVK. + */ + + #pragma mark - #pragma mark Image properties diff --git a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h new file mode 100644 index 000000000..b7d7c6ff5 --- /dev/null +++ b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h @@ -0,0 +1,215 @@ +/* + * mvk_deprecated_api.h + * + * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __mvk_deprecated_api_h_ +#define __mvk_deprecated_api_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include +#include + + +#define VK_MVK_MOLTENVK_SPEC_VERSION 37 +#define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk" + +#define MVK_DEPRECATED VKAPI_ATTR [[deprecated]] +#define MVK_DEPRECATED_USE_MTL_OBJS VKAPI_ATTR [[deprecated("Use the VK_EXT_metal_objects extension instead.")]] + + +/** + * This header contains obsolete and deprecated MoltenVK functions, that were origionally + * part of the obsolete and deprecated private VK_MVK_moltenvk extension. + * + * 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. + * THE VULKAN OBJECTS PASSED IN THESE FUNCTIONS MUST HAVE BEEN RETRIEVED DIRECTLY + * FROM MOLTENVK, WITHOUT LINKING THROUGH THE VULKAN LOADER AND LAYERS. + * + * To interact with the Metal objects underlying Vulkan objects in MoltenVK, + * use the standard Vulkan VK_EXT_metal_objects extension. + * The VK_EXT_metal_objects extension is supported by the Vulkan Loader and Layers. + */ + + +#pragma mark - +#pragma mark Function types + +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); +typedef void (VKAPI_PTR *PFN_vkGetIOSurfaceMVK)(VkImage image, IOSurfaceRef* pIOSurface); + +#ifdef __OBJC__ +typedef void (VKAPI_PTR *PFN_vkGetMTLDeviceMVK)(VkPhysicalDevice physicalDevice, id* pMTLDevice); +typedef VkResult (VKAPI_PTR *PFN_vkSetMTLTextureMVK)(VkImage image, id mtlTexture); +typedef void (VKAPI_PTR *PFN_vkGetMTLTextureMVK)(VkImage image, id* pMTLTexture); +typedef void (VKAPI_PTR *PFN_vkGetMTLBufferMVK)(VkBuffer buffer, id* pMTLBuffer); +typedef void (VKAPI_PTR *PFN_vkGetMTLCommandQueueMVK)(VkQueue queue, id* pMTLCommandQueue); +#endif // __OBJC__ + + +#pragma mark - +#pragma mark Function prototypes + +#ifndef VK_NO_PROTOTYPES + +/** + * Returns a human readable version of the MoltenVK and Vulkan versions. + * + * This function is provided as a convenience for reporting. Use the MVK_VERSION, + * VK_API_VERSION_1_0, and VK_HEADER_VERSION macros for programmatically accessing + * the corresponding version numbers. + */ + MVK_DEPRECATED void VKAPI_CALL vkGetVersionStringsMVK( + char* pMoltenVersionStringBuffer, + uint32_t moltenVersionStringBufferLength, + char* pVulkanVersionStringBuffer, + uint32_t vulkanVersionStringBufferLength); + +/** + * Sets the number of threads in a workgroup for a compute kernel. + * + * This needs to be called if you are creating compute shader modules from MSL source code + * or MSL compiled code. If you are using SPIR-V, workgroup size is determined automatically. + * + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. + */ + MVK_DEPRECATED void VKAPI_CALL vkSetWorkgroupSizeMVK( + VkShaderModule shaderModule, + uint32_t x, + uint32_t y, + uint32_t z); + +#ifdef __OBJC__ + +/** + * Returns, in the pMTLDevice pointer, the MTLDevice used by the VkPhysicalDevice. + * + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. + */ +MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLDeviceMVK( + VkPhysicalDevice physicalDevice, + id* pMTLDevice); + +/** + * Sets the VkImage to use the specified MTLTexture. + * + * Any differences in the properties of mtlTexture and this image will modify the + * properties of this image. + * + * If a MTLTexture has already been created for this image, it will be destroyed. + * + * Returns VK_SUCCESS. + * + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. + */ +MVK_DEPRECATED_USE_MTL_OBJS VkResult VKAPI_CALL vkSetMTLTextureMVK( + VkImage image, + id mtlTexture); + +/** + * Returns, in the pMTLTexture pointer, the MTLTexture currently underlaying the VkImage. + * + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. + */ +MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLTextureMVK( + VkImage image, + id* pMTLTexture); + +/** +* Returns, in the pMTLBuffer pointer, the MTLBuffer currently underlaying the VkBuffer. +* + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. +*/ +MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLBufferMVK( + VkBuffer buffer, + id* pMTLBuffer); + +/** +* Returns, in the pMTLCommandQueue pointer, the MTLCommandQueue currently underlaying the VkQueue. +* + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. +*/ +MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLCommandQueueMVK( + VkQueue queue, + id* pMTLCommandQueue); + +#endif // __OBJC__ + +/** + * Indicates that a VkImage should use an IOSurface to underlay the Metal texture. + * + * If ioSurface is not null, it will be used as the IOSurface, and any differences + * in the properties of that IOSurface will modify the properties of this image. + * + * If ioSurface is null, this image will create and use an IOSurface + * whose properties are compatible with the properties of this image. + * + * If a MTLTexture has already been created for this image, it will be destroyed. + * + * IOSurfaces are supported on the following platforms: + * - macOS 10.11 and above + * - iOS 11.0 and above + * + * To enable IOSurface support, ensure the Deployment Target build setting + * (MACOSX_DEPLOYMENT_TARGET or IPHONEOS_DEPLOYMENT_TARGET) is set to at least + * one of the values above when compiling MoltenVK, and any app that uses MoltenVK. + * + * Returns: + * - VK_SUCCESS. + * - VK_ERROR_FEATURE_NOT_PRESENT if IOSurfaces are not supported on the platform. + * - VK_ERROR_INITIALIZATION_FAILED if ioSurface is specified and is not compatible with this VkImage. + * + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. + */ +MVK_DEPRECATED_USE_MTL_OBJS VkResult VKAPI_CALL vkUseIOSurfaceMVK( + VkImage image, + IOSurfaceRef ioSurface); + +/** + * Returns, in the pIOSurface pointer, the IOSurface currently underlaying the VkImage, + * as set by the useIOSurfaceMVK() function, or returns null if the VkImage is not using + * an IOSurface, or if the platform does not support IOSurfaces. + * + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. + */ +MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetIOSurfaceMVK( + VkImage image, + IOSurfaceRef* pIOSurface); + + +#endif // VK_NO_PROTOTYPES + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif diff --git a/MoltenVK/MoltenVK/API/mvk_private_api.h b/MoltenVK/MoltenVK/API/mvk_private_api.h new file mode 100644 index 000000000..dd79756de --- /dev/null +++ b/MoltenVK/MoltenVK/API/mvk_private_api.h @@ -0,0 +1,296 @@ +/* + * mvk_private_api.h + * + * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __mvk_private_api_h_ +#define __mvk_private_api_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include + +#ifdef __OBJC__ +#import +#else +typedef unsigned long MTLLanguageVersion; +typedef unsigned long MTLArgumentBuffersTier; +#endif + + +/** + * This header contains functions to query MoltenVK about + * available Metal features, and runtime performance information. + * + * NOTE: THE FUNCTIONS BELOW SHOULD BE USED WITH CARE. THESE FUNCTIONS ARE + * NOT PART OF VULKAN, AND ARE NOT SUPPORTED BY THE VULKAN LOADER AND LAYERS. + * THE VULKAN OBJECTS PASSED IN THESE FUNCTIONS MUST HAVE BEEN RETRIEVED + * DIRECTLY FROM MOLTENVK, WITHOUT LINKING THROUGH THE VULKAN LOADER AND LAYERS. + */ + + +#define MVK_PRIVATE_API_VERSION 37 + + +/** Identifies the type of rounding Metal uses for float to integer conversions in particular calculatons. */ +typedef enum MVKFloatRounding { + MVK_FLOAT_ROUNDING_NEAREST = 0, /**< Metal rounds to nearest. */ + MVK_FLOAT_ROUNDING_UP = 1, /**< Metal rounds towards positive infinity. */ + MVK_FLOAT_ROUNDING_DOWN = 2, /**< Metal rounds towards negative infinity. */ + MVK_FLOAT_ROUNDING_UP_MAX_ENUM = 0x7FFFFFFF +} MVKFloatRounding; + +/** Identifies the pipeline points where GPU counter sampling can occur. Maps to MTLCounterSamplingPoint. */ +typedef enum MVKCounterSamplingBits { + MVK_COUNTER_SAMPLING_AT_DRAW = 0x00000001, + MVK_COUNTER_SAMPLING_AT_DISPATCH = 0x00000002, + MVK_COUNTER_SAMPLING_AT_BLIT = 0x00000004, + MVK_COUNTER_SAMPLING_AT_PIPELINE_STAGE = 0x00000008, + MVK_COUNTER_SAMPLING_MAX_ENUM = 0X7FFFFFFF +} MVKCounterSamplingBits; +typedef VkFlags MVKCounterSamplingFlags; + +/** + * Features provided by the current implementation of Metal on the current device. You can + * retrieve a copy of this structure using the vkGetPhysicalDeviceMetalFeaturesMVK() function. + * + * 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 VK_MVK_MOLTENVK_SPEC_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 vkGetPhysicalDeviceMetalFeaturesMVK() function + * 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. + */ +typedef struct { + uint32_t mslVersion; /**< The version of the Metal Shading Language available on this device. The format of the integer is MMmmpp, with two decimal digts each for Major, minor, and patch version values (eg. MSL 1.2 would appear as 010200). */ + VkBool32 indirectDrawing; /**< If true, draw calls support parameters held in a GPU buffer. */ + VkBool32 baseVertexInstanceDrawing; /**< If true, draw calls support specifiying the base vertex and instance. */ + uint32_t dynamicMTLBufferSize; /**< If greater than zero, dynamic MTLBuffers for setting vertex, fragment, and compute bytes are supported, and their content must be below this value. */ + VkBool32 shaderSpecialization; /**< If true, shader specialization (aka Metal function constants) is supported. */ + VkBool32 ioSurfaces; /**< If true, VkImages can be underlaid by IOSurfaces via the vkUseIOSurfaceMVK() function, to support inter-process image transfers. */ + VkBool32 texelBuffers; /**< If true, texel buffers are supported, allowing the contents of a buffer to be interpreted as an image via a VkBufferView. */ + VkBool32 layeredRendering; /**< If true, layered rendering to multiple cube or texture array layers is supported. */ + VkBool32 presentModeImmediate; /**< If true, immediate surface present mode (VK_PRESENT_MODE_IMMEDIATE_KHR), allowing a swapchain image to be presented immediately, without waiting for the vertical sync period of the display, is supported. */ + VkBool32 stencilViews; /**< If true, stencil aspect views are supported through the MTLPixelFormatX24_Stencil8 and MTLPixelFormatX32_Stencil8 formats. */ + VkBool32 multisampleArrayTextures; /**< If true, MTLTextureType2DMultisampleArray is supported. */ + VkBool32 samplerClampToBorder; /**< If true, the border color set when creating a sampler will be respected. */ + uint32_t maxTextureDimension; /**< The maximum size of each texture dimension (width, height, or depth). */ + uint32_t maxPerStageBufferCount; /**< The total number of per-stage Metal buffers available for shader uniform content and attributes. */ + uint32_t maxPerStageTextureCount; /**< The total number of per-stage Metal textures available for shader uniform content. */ + uint32_t maxPerStageSamplerCount; /**< The total number of per-stage Metal samplers available for shader uniform content. */ + VkDeviceSize maxMTLBufferSize; /**< The max size of a MTLBuffer (in bytes). */ + VkDeviceSize mtlBufferAlignment; /**< The alignment used when allocating memory for MTLBuffers. Must be PoT. */ + VkDeviceSize maxQueryBufferSize; /**< The maximum size of an occlusion query buffer (in bytes). */ + VkDeviceSize mtlCopyBufferAlignment; /**< The alignment required during buffer copy operations (in bytes). */ + VkSampleCountFlags supportedSampleCounts; /**< A bitmask identifying the sample counts supported by the device. */ + uint32_t minSwapchainImageCount; /**< The minimum number of swapchain images that can be supported by a surface. */ + uint32_t maxSwapchainImageCount; /**< The maximum number of swapchain images that can be supported by a surface. */ + VkBool32 combinedStoreResolveAction; /**< If true, the device supports VK_ATTACHMENT_STORE_OP_STORE with a simultaneous resolve attachment. */ + VkBool32 arrayOfTextures; /**< If true, arrays of textures is supported. */ + VkBool32 arrayOfSamplers; /**< If true, arrays of texture samplers is supported. */ + MTLLanguageVersion mslVersionEnum; /**< The version of the Metal Shading Language available on this device, as a Metal enumeration. */ + VkBool32 depthSampleCompare; /**< If true, depth texture samplers support the comparison of the pixel value against a reference value. */ + VkBool32 events; /**< If true, Metal synchronization events (MTLEvent) are supported. */ + VkBool32 memoryBarriers; /**< If true, full memory barriers within Metal render passes are supported. */ + VkBool32 multisampleLayeredRendering; /**< If true, layered rendering to multiple multi-sampled cube or texture array layers is supported. */ + VkBool32 stencilFeedback; /**< If true, fragment shaders that write to [[stencil]] outputs are supported. */ + VkBool32 textureBuffers; /**< If true, textures of type MTLTextureTypeBuffer are supported. */ + VkBool32 postDepthCoverage; /**< If true, coverage masks in fragment shaders post-depth-test are supported. */ + VkBool32 fences; /**< If true, Metal synchronization fences (MTLFence) are supported. */ + VkBool32 rasterOrderGroups; /**< If true, Raster order groups in fragment shaders are supported. */ + VkBool32 native3DCompressedTextures; /**< If true, 3D compressed images are supported natively, without manual decompression. */ + VkBool32 nativeTextureSwizzle; /**< If true, component swizzle is supported natively, without manual swizzling in shaders. */ + VkBool32 placementHeaps; /**< If true, MTLHeap objects support placement of resources. */ + VkDeviceSize pushConstantSizeAlignment; /**< The alignment used internally when allocating memory for push constants. Must be PoT. */ + uint32_t maxTextureLayers; /**< The maximum number of layers in an array texture. */ + uint32_t maxSubgroupSize; /**< The maximum number of threads in a SIMD-group. */ + VkDeviceSize vertexStrideAlignment; /**< The alignment used for the stride of vertex attribute bindings. */ + VkBool32 indirectTessellationDrawing; /**< If true, tessellation draw calls support parameters held in a GPU buffer. */ + VkBool32 nonUniformThreadgroups; /**< If true, the device supports arbitrary-sized grids in compute workloads. */ + VkBool32 renderWithoutAttachments; /**< If true, we don't have to create a dummy attachment for a render pass if there isn't one. */ + VkBool32 deferredStoreActions; /**< If true, render pass store actions can be specified after the render encoder is created. */ + VkBool32 sharedLinearTextures; /**< If true, linear textures and texture buffers can be created from buffers in Shared storage. */ + VkBool32 depthResolve; /**< If true, resolving depth textures with filters other than Sample0 is supported. */ + VkBool32 stencilResolve; /**< If true, resolving stencil textures with filters other than Sample0 is supported. */ + uint32_t maxPerStageDynamicMTLBufferCount; /**< The maximum number of inline buffers that can be set on a command buffer. */ + uint32_t maxPerStageStorageTextureCount; /**< The total number of per-stage Metal textures with read-write access available for writing to from a shader. */ + VkBool32 astcHDRTextures; /**< If true, ASTC HDR pixel formats are supported. */ + VkBool32 renderLinearTextures; /**< If true, linear textures are renderable. */ + VkBool32 pullModelInterpolation; /**< If true, explicit interpolation functions are supported. */ + VkBool32 samplerMirrorClampToEdge; /**< If true, the mirrored clamp to edge address mode is supported in samplers. */ + VkBool32 quadPermute; /**< If true, quadgroup permutation functions (vote, ballot, shuffle) are supported in shaders. */ + VkBool32 simdPermute; /**< If true, SIMD-group permutation functions (vote, ballot, shuffle) are supported in shaders. */ + VkBool32 simdReduction; /**< If true, SIMD-group reduction functions (arithmetic) are supported in shaders. */ + uint32_t minSubgroupSize; /**< The minimum number of threads in a SIMD-group. */ + VkBool32 textureBarriers; /**< If true, texture barriers are supported within Metal render passes. */ + VkBool32 tileBasedDeferredRendering; /**< If true, this device uses tile-based deferred rendering. */ + VkBool32 argumentBuffers; /**< If true, Metal argument buffers are supported. */ + VkBool32 descriptorSetArgumentBuffers; /**< If true, a Metal argument buffer can be assigned to a descriptor set, and used on any pipeline and pipeline stage. If false, a different Metal argument buffer must be used for each pipeline-stage/descriptor-set combination. */ + MVKFloatRounding clearColorFloatRounding; /**< Identifies the type of rounding Metal uses for MTLClearColor float to integer conversions. */ + MVKCounterSamplingFlags counterSamplingPoints; /**< Identifies the points where pipeline GPU counter sampling may occur. */ + VkBool32 programmableSamplePositions; /**< If true, programmable MSAA sample positions are supported. */ + VkBool32 shaderBarycentricCoordinates; /**< If true, fragment shader barycentric coordinates are supported. */ + MTLArgumentBuffersTier argumentBuffersTier; /**< The argument buffer tier available on this device, as a Metal enumeration. */ + VkBool32 needsSampleDrefLodArrayWorkaround; /**< If true, sampling from arrayed depth images with explicit LoD is broken and needs a workaround. */ + VkDeviceSize hostMemoryPageSize; /**< The size of a page of host memory on this platform. */ +} MVKPhysicalDeviceMetalFeatures; + +/** MoltenVK performance of a particular type of activity. */ +typedef struct { + uint32_t count; /**< The number of activities of this type. */ + double latestDuration; /**< The latest (most recent) duration of the activity, in milliseconds. */ + double averageDuration; /**< The average duration of the activity, in milliseconds. */ + double minimumDuration; /**< The minimum duration of the activity, in milliseconds. */ + double maximumDuration; /**< The maximum duration of the activity, in milliseconds. */ +} MVKPerformanceTracker; + +/** MoltenVK performance of shader compilation activities. */ +typedef struct { + MVKPerformanceTracker hashShaderCode; /** Create a hash from the incoming shader code. */ + MVKPerformanceTracker spirvToMSL; /** Convert SPIR-V to MSL source code. */ + MVKPerformanceTracker mslCompile; /** Compile MSL source code into a MTLLibrary. */ + MVKPerformanceTracker mslLoad; /** Load pre-compiled MSL code into a MTLLibrary. */ + MVKPerformanceTracker mslCompress; /** Compress MSL source code after compiling a MTLLibrary, to hold it in a pipeline cache. */ + MVKPerformanceTracker mslDecompress; /** Decompress MSL source code to write the MSL when serializing a pipeline cache. */ + MVKPerformanceTracker shaderLibraryFromCache; /** Retrieve a shader library from the cache, lazily creating it if needed. */ + MVKPerformanceTracker functionRetrieval; /** Retrieve a MTLFunction from a MTLLibrary. */ + MVKPerformanceTracker functionSpecialization; /** Specialize a retrieved MTLFunction. */ + MVKPerformanceTracker pipelineCompile; /** Compile MTLFunctions into a pipeline. */ + MVKPerformanceTracker glslToSPRIV; /** Convert GLSL to SPIR-V code. */ +} MVKShaderCompilationPerformance; + +/** MoltenVK performance of pipeline cache activities. */ +typedef struct { + MVKPerformanceTracker sizePipelineCache; /** Calculate the size of cache data required to write MSL to pipeline cache data stream. */ + MVKPerformanceTracker writePipelineCache; /** Write MSL to pipeline cache data stream. */ + MVKPerformanceTracker readPipelineCache; /** Read MSL from pipeline cache data stream. */ +} MVKPipelineCachePerformance; + +/** MoltenVK performance of queue activities. */ +typedef struct { + MVKPerformanceTracker mtlQueueAccess; /** Create an MTLCommandQueue or access an existing cached instance. */ + MVKPerformanceTracker mtlCommandBufferCompletion; /** Completion of a MTLCommandBuffer on the GPU, from commit to completion callback. */ + MVKPerformanceTracker nextCAMetalDrawable; /** Retrieve next CAMetalDrawable from CAMetalLayer during presentation. */ + MVKPerformanceTracker frameInterval; /** Frame presentation interval (1000/FPS). */ +} MVKQueuePerformance; + +/** + * MoltenVK performance. You can retrieve a copy of this structure using the vkGetPerformanceStatisticsMVK() function. + * + * 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 VK_MVK_MOLTENVK_SPEC_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 vkGetPerformanceStatisticsMVK() function 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. + */ +typedef struct { + MVKShaderCompilationPerformance shaderCompilation; /** Shader compilations activities. */ + MVKPipelineCachePerformance pipelineCache; /** Pipeline cache activities. */ + MVKQueuePerformance queue; /** Queue activities. */ +} MVKPerformanceStatistics; + + +#pragma mark - +#pragma mark Function types + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceMetalFeaturesMVK)(VkPhysicalDevice physicalDevice, MVKPhysicalDeviceMetalFeatures* pMetalFeatures, size_t* pMetalFeaturesSize); +typedef VkResult (VKAPI_PTR *PFN_vkGetPerformanceStatisticsMVK)(VkDevice device, MVKPerformanceStatistics* pPerf, size_t* pPerfSize); + + +#pragma mark - +#pragma mark Function prototypes + +#ifndef VK_NO_PROTOTYPES + +/** + * Populates the pMetalFeatures structure with the Metal-specific features + * supported by the specified physical device. + * + * If you are linking to an implementation of MoltenVK that was compiled from a different + * VK_MVK_MOLTENVK_SPEC_VERSION than your app was, the size of the MVKPhysicalDeviceMetalFeatures + * 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 *pMetalFeaturesSize to sizeof(MVKPhysicalDeviceMetalFeatures), + * to tell MoltenVK the limit of the size of your MVKPhysicalDeviceMetalFeatures structure. Upon return from + * this function, the value of *pMetalFeaturesSize will hold the actual number of bytes copied into your + * passed MVKPhysicalDeviceMetalFeatures structure, which will be the smaller of what your app thinks is the + * size of MVKPhysicalDeviceMetalFeatures, 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 MVKPhysicalDeviceMetalFeatures is different than the value passed in + * *pMetalFeaturesSize, 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 MVKPhysicalDeviceMetalFeatures to be by setting the value of pMetalFeatures to NULL. + * In that case, this function will set *pMetalFeaturesSize to the size that MoltenVK expects + * MVKPhysicalDeviceMetalFeatures to be. + * + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. + */ +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceMetalFeaturesMVK( + VkPhysicalDevice physicalDevice, + MVKPhysicalDeviceMetalFeatures* pMetalFeatures, + size_t* pMetalFeaturesSize); + +/** + * Populates the pPerf structure with the current performance statistics for the device. + * + * If you are linking to an implementation of MoltenVK that was compiled from a different + * VK_MVK_MOLTENVK_SPEC_VERSION than your app was, the size of the MVKPerformanceStatistics + * 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 *pPerfSize to sizeof(MVKPerformanceStatistics), + * to tell MoltenVK the limit of the size of your MVKPerformanceStatistics structure. Upon return + * from this function, the value of *pPerfSize will hold the actual number of bytes copied into + * your passed MVKPerformanceStatistics structure, which will be the smaller of what your app + * thinks is the size of MVKPerformanceStatistics, 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 MVKPerformanceStatistics is different than the value passed + * in *pPerfSize, 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 MVKPerformanceStatistics to be by setting the value of + * pPerf to NULL. In that case, this function will set *pPerfSize to the size that MoltenVK + * expects MVKPerformanceStatistics to be. + * + * This function is not supported by the Vulkan SDK Loader and Layers framework + * and is unavailable when using the Vulkan SDK Loader and Layers framework. + */ +VKAPI_ATTR VkResult VKAPI_CALL vkGetPerformanceStatisticsMVK( + VkDevice device, + MVKPerformanceStatistics* pPerf, + size_t* pPerfSize); + + +#endif // VK_NO_PROTOTYPES + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index 7f770fce1..b6cabcd57 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -16,1424 +16,21 @@ * limitations under the License. */ - -/** Vulkan extension VK_MVK_moltenvk. */ - -#ifndef __vk_mvk_moltenvk_h_ -#define __vk_mvk_moltenvk_h_ 1 - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#include "mvk_vulkan.h" -#include - -#ifdef __OBJC__ -#import -#else -typedef unsigned long MTLLanguageVersion; -typedef unsigned long MTLArgumentBuffersTier; -#endif - - -/** - * 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. - * - * 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 4 - -#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) -#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH) - -#define VK_MVK_MOLTENVK_SPEC_VERSION 37 -#define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk" - -/** 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_MOLTENVK = 0x00000002, /**< This VK_MVK_moltenvk extension. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_WSI = 0x00000004, /**< WSI extensions supported on the platform. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_PORTABILITY = 0x00000008, /**< 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_MAX_ENUM = 0x7FFFFFFF, -} MVKConfigActivityPerformanceLoggingStyle; - /** - * MoltenVK configuration settings. + * This header is provided for legacy compatibility only. This header contains obsolete and + * deprecated MoltenVK functions, that were origionally part of the obsolete and deprecated + * private VK_MVK_moltenvk extension, and use of this header is not recommended. + * Instead, in your application, use the following header file: * - * 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. + * #include * - * There are three mechanisms for setting the values of the MoltenVK configuration parameters: - * - Runtime API via the vkGetMoltenVKConfigurationMVK()/vkSetMoltenVKConfigurationMVK() functions. - * - Application runtime environment variables. - * - Build settings at MoltenVK build time. + * And if you require the MoltenVK Configuration API, also include the following header file: * - * 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 VK_MVK_MOLTENVK_SPEC_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. + * #include */ -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_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 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; - -} MVKConfiguration; - -/** Identifies the type of rounding Metal uses for float to integer conversions in particular calculatons. */ -typedef enum MVKFloatRounding { - MVK_FLOAT_ROUNDING_NEAREST = 0, /**< Metal rounds to nearest. */ - MVK_FLOAT_ROUNDING_UP = 1, /**< Metal rounds towards positive infinity. */ - MVK_FLOAT_ROUNDING_DOWN = 2, /**< Metal rounds towards negative infinity. */ - MVK_FLOAT_ROUNDING_UP_MAX_ENUM = 0x7FFFFFFF -} MVKFloatRounding; - -/** Identifies the pipeline points where GPU counter sampling can occur. Maps to MTLCounterSamplingPoint. */ -typedef enum MVKCounterSamplingBits { - MVK_COUNTER_SAMPLING_AT_DRAW = 0x00000001, - MVK_COUNTER_SAMPLING_AT_DISPATCH = 0x00000002, - MVK_COUNTER_SAMPLING_AT_BLIT = 0x00000004, - MVK_COUNTER_SAMPLING_AT_PIPELINE_STAGE = 0x00000008, - MVK_COUNTER_SAMPLING_MAX_ENUM = 0X7FFFFFFF -} MVKCounterSamplingBits; -typedef VkFlags MVKCounterSamplingFlags; - -/** - * Features provided by the current implementation of Metal on the current device. You can - * retrieve a copy of this structure using the vkGetPhysicalDeviceMetalFeaturesMVK() function. - * - * 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 VK_MVK_MOLTENVK_SPEC_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 vkGetPhysicalDeviceMetalFeaturesMVK() function - * 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. - */ -typedef struct { - uint32_t mslVersion; /**< The version of the Metal Shading Language available on this device. The format of the integer is MMmmpp, with two decimal digts each for Major, minor, and patch version values (eg. MSL 1.2 would appear as 010200). */ - VkBool32 indirectDrawing; /**< If true, draw calls support parameters held in a GPU buffer. */ - VkBool32 baseVertexInstanceDrawing; /**< If true, draw calls support specifiying the base vertex and instance. */ - uint32_t dynamicMTLBufferSize; /**< If greater than zero, dynamic MTLBuffers for setting vertex, fragment, and compute bytes are supported, and their content must be below this value. */ - VkBool32 shaderSpecialization; /**< If true, shader specialization (aka Metal function constants) is supported. */ - VkBool32 ioSurfaces; /**< If true, VkImages can be underlaid by IOSurfaces via the vkUseIOSurfaceMVK() function, to support inter-process image transfers. */ - VkBool32 texelBuffers; /**< If true, texel buffers are supported, allowing the contents of a buffer to be interpreted as an image via a VkBufferView. */ - VkBool32 layeredRendering; /**< If true, layered rendering to multiple cube or texture array layers is supported. */ - VkBool32 presentModeImmediate; /**< If true, immediate surface present mode (VK_PRESENT_MODE_IMMEDIATE_KHR), allowing a swapchain image to be presented immediately, without waiting for the vertical sync period of the display, is supported. */ - VkBool32 stencilViews; /**< If true, stencil aspect views are supported through the MTLPixelFormatX24_Stencil8 and MTLPixelFormatX32_Stencil8 formats. */ - VkBool32 multisampleArrayTextures; /**< If true, MTLTextureType2DMultisampleArray is supported. */ - VkBool32 samplerClampToBorder; /**< If true, the border color set when creating a sampler will be respected. */ - uint32_t maxTextureDimension; /**< The maximum size of each texture dimension (width, height, or depth). */ - uint32_t maxPerStageBufferCount; /**< The total number of per-stage Metal buffers available for shader uniform content and attributes. */ - uint32_t maxPerStageTextureCount; /**< The total number of per-stage Metal textures available for shader uniform content. */ - uint32_t maxPerStageSamplerCount; /**< The total number of per-stage Metal samplers available for shader uniform content. */ - VkDeviceSize maxMTLBufferSize; /**< The max size of a MTLBuffer (in bytes). */ - VkDeviceSize mtlBufferAlignment; /**< The alignment used when allocating memory for MTLBuffers. Must be PoT. */ - VkDeviceSize maxQueryBufferSize; /**< The maximum size of an occlusion query buffer (in bytes). */ - VkDeviceSize mtlCopyBufferAlignment; /**< The alignment required during buffer copy operations (in bytes). */ - VkSampleCountFlags supportedSampleCounts; /**< A bitmask identifying the sample counts supported by the device. */ - uint32_t minSwapchainImageCount; /**< The minimum number of swapchain images that can be supported by a surface. */ - uint32_t maxSwapchainImageCount; /**< The maximum number of swapchain images that can be supported by a surface. */ - VkBool32 combinedStoreResolveAction; /**< If true, the device supports VK_ATTACHMENT_STORE_OP_STORE with a simultaneous resolve attachment. */ - VkBool32 arrayOfTextures; /**< If true, arrays of textures is supported. */ - VkBool32 arrayOfSamplers; /**< If true, arrays of texture samplers is supported. */ - MTLLanguageVersion mslVersionEnum; /**< The version of the Metal Shading Language available on this device, as a Metal enumeration. */ - VkBool32 depthSampleCompare; /**< If true, depth texture samplers support the comparison of the pixel value against a reference value. */ - VkBool32 events; /**< If true, Metal synchronization events (MTLEvent) are supported. */ - VkBool32 memoryBarriers; /**< If true, full memory barriers within Metal render passes are supported. */ - VkBool32 multisampleLayeredRendering; /**< If true, layered rendering to multiple multi-sampled cube or texture array layers is supported. */ - VkBool32 stencilFeedback; /**< If true, fragment shaders that write to [[stencil]] outputs are supported. */ - VkBool32 textureBuffers; /**< If true, textures of type MTLTextureTypeBuffer are supported. */ - VkBool32 postDepthCoverage; /**< If true, coverage masks in fragment shaders post-depth-test are supported. */ - VkBool32 fences; /**< If true, Metal synchronization fences (MTLFence) are supported. */ - VkBool32 rasterOrderGroups; /**< If true, Raster order groups in fragment shaders are supported. */ - VkBool32 native3DCompressedTextures; /**< If true, 3D compressed images are supported natively, without manual decompression. */ - VkBool32 nativeTextureSwizzle; /**< If true, component swizzle is supported natively, without manual swizzling in shaders. */ - VkBool32 placementHeaps; /**< If true, MTLHeap objects support placement of resources. */ - VkDeviceSize pushConstantSizeAlignment; /**< The alignment used internally when allocating memory for push constants. Must be PoT. */ - uint32_t maxTextureLayers; /**< The maximum number of layers in an array texture. */ - uint32_t maxSubgroupSize; /**< The maximum number of threads in a SIMD-group. */ - VkDeviceSize vertexStrideAlignment; /**< The alignment used for the stride of vertex attribute bindings. */ - VkBool32 indirectTessellationDrawing; /**< If true, tessellation draw calls support parameters held in a GPU buffer. */ - VkBool32 nonUniformThreadgroups; /**< If true, the device supports arbitrary-sized grids in compute workloads. */ - VkBool32 renderWithoutAttachments; /**< If true, we don't have to create a dummy attachment for a render pass if there isn't one. */ - VkBool32 deferredStoreActions; /**< If true, render pass store actions can be specified after the render encoder is created. */ - VkBool32 sharedLinearTextures; /**< If true, linear textures and texture buffers can be created from buffers in Shared storage. */ - VkBool32 depthResolve; /**< If true, resolving depth textures with filters other than Sample0 is supported. */ - VkBool32 stencilResolve; /**< If true, resolving stencil textures with filters other than Sample0 is supported. */ - uint32_t maxPerStageDynamicMTLBufferCount; /**< The maximum number of inline buffers that can be set on a command buffer. */ - uint32_t maxPerStageStorageTextureCount; /**< The total number of per-stage Metal textures with read-write access available for writing to from a shader. */ - VkBool32 astcHDRTextures; /**< If true, ASTC HDR pixel formats are supported. */ - VkBool32 renderLinearTextures; /**< If true, linear textures are renderable. */ - VkBool32 pullModelInterpolation; /**< If true, explicit interpolation functions are supported. */ - VkBool32 samplerMirrorClampToEdge; /**< If true, the mirrored clamp to edge address mode is supported in samplers. */ - VkBool32 quadPermute; /**< If true, quadgroup permutation functions (vote, ballot, shuffle) are supported in shaders. */ - VkBool32 simdPermute; /**< If true, SIMD-group permutation functions (vote, ballot, shuffle) are supported in shaders. */ - VkBool32 simdReduction; /**< If true, SIMD-group reduction functions (arithmetic) are supported in shaders. */ - uint32_t minSubgroupSize; /**< The minimum number of threads in a SIMD-group. */ - VkBool32 textureBarriers; /**< If true, texture barriers are supported within Metal render passes. */ - VkBool32 tileBasedDeferredRendering; /**< If true, this device uses tile-based deferred rendering. */ - VkBool32 argumentBuffers; /**< If true, Metal argument buffers are supported. */ - VkBool32 descriptorSetArgumentBuffers; /**< If true, a Metal argument buffer can be assigned to a descriptor set, and used on any pipeline and pipeline stage. If false, a different Metal argument buffer must be used for each pipeline-stage/descriptor-set combination. */ - MVKFloatRounding clearColorFloatRounding; /**< Identifies the type of rounding Metal uses for MTLClearColor float to integer conversions. */ - MVKCounterSamplingFlags counterSamplingPoints; /**< Identifies the points where pipeline GPU counter sampling may occur. */ - VkBool32 programmableSamplePositions; /**< If true, programmable MSAA sample positions are supported. */ - VkBool32 shaderBarycentricCoordinates; /**< If true, fragment shader barycentric coordinates are supported. */ - MTLArgumentBuffersTier argumentBuffersTier; /**< The argument buffer tier available on this device, as a Metal enumeration. */ - VkBool32 needsSampleDrefLodArrayWorkaround; /**< If true, sampling from arrayed depth images with explicit LoD is broken and needs a workaround. */ - VkDeviceSize hostMemoryPageSize; /**< The size of a page of host memory on this platform. */ -} MVKPhysicalDeviceMetalFeatures; - -/** MoltenVK performance of a particular type of activity. */ -typedef struct { - uint32_t count; /**< The number of activities of this type. */ - double latestDuration; /**< The latest (most recent) duration of the activity, in milliseconds. */ - double averageDuration; /**< The average duration of the activity, in milliseconds. */ - double minimumDuration; /**< The minimum duration of the activity, in milliseconds. */ - double maximumDuration; /**< The maximum duration of the activity, in milliseconds. */ -} MVKPerformanceTracker; - -/** MoltenVK performance of shader compilation activities. */ -typedef struct { - MVKPerformanceTracker hashShaderCode; /** Create a hash from the incoming shader code. */ - MVKPerformanceTracker spirvToMSL; /** Convert SPIR-V to MSL source code. */ - MVKPerformanceTracker mslCompile; /** Compile MSL source code into a MTLLibrary. */ - MVKPerformanceTracker mslLoad; /** Load pre-compiled MSL code into a MTLLibrary. */ - MVKPerformanceTracker mslCompress; /** Compress MSL source code after compiling a MTLLibrary, to hold it in a pipeline cache. */ - MVKPerformanceTracker mslDecompress; /** Decompress MSL source code to write the MSL when serializing a pipeline cache. */ - MVKPerformanceTracker shaderLibraryFromCache; /** Retrieve a shader library from the cache, lazily creating it if needed. */ - MVKPerformanceTracker functionRetrieval; /** Retrieve a MTLFunction from a MTLLibrary. */ - MVKPerformanceTracker functionSpecialization; /** Specialize a retrieved MTLFunction. */ - MVKPerformanceTracker pipelineCompile; /** Compile MTLFunctions into a pipeline. */ - MVKPerformanceTracker glslToSPRIV; /** Convert GLSL to SPIR-V code. */ -} MVKShaderCompilationPerformance; - -/** MoltenVK performance of pipeline cache activities. */ -typedef struct { - MVKPerformanceTracker sizePipelineCache; /** Calculate the size of cache data required to write MSL to pipeline cache data stream. */ - MVKPerformanceTracker writePipelineCache; /** Write MSL to pipeline cache data stream. */ - MVKPerformanceTracker readPipelineCache; /** Read MSL from pipeline cache data stream. */ -} MVKPipelineCachePerformance; - -/** MoltenVK performance of queue activities. */ -typedef struct { - MVKPerformanceTracker mtlQueueAccess; /** Create an MTLCommandQueue or access an existing cached instance. */ - MVKPerformanceTracker mtlCommandBufferCompletion; /** Completion of a MTLCommandBuffer on the GPU, from commit to completion callback. */ - MVKPerformanceTracker nextCAMetalDrawable; /** Retrieve next CAMetalDrawable from CAMetalLayer during presentation. */ - MVKPerformanceTracker frameInterval; /** Frame presentation interval (1000/FPS). */ -} MVKQueuePerformance; - -/** - * MoltenVK performance. You can retrieve a copy of this structure using the vkGetPerformanceStatisticsMVK() function. - * - * 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 VK_MVK_MOLTENVK_SPEC_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 vkGetPerformanceStatisticsMVK() function 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. - */ -typedef struct { - MVKShaderCompilationPerformance shaderCompilation; /** Shader compilations activities. */ - MVKPipelineCachePerformance pipelineCache; /** Pipeline cache activities. */ - MVKQueuePerformance queue; /** Queue activities. */ -} MVKPerformanceStatistics; - - -#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); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceMetalFeaturesMVK)(VkPhysicalDevice physicalDevice, MVKPhysicalDeviceMetalFeatures* pMetalFeatures, size_t* pMetalFeaturesSize); -typedef VkResult (VKAPI_PTR *PFN_vkGetPerformanceStatisticsMVK)(VkDevice device, MVKPerformanceStatistics* pPerf, size_t* pPerfSize); -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); -typedef void (VKAPI_PTR *PFN_vkGetIOSurfaceMVK)(VkImage image, IOSurfaceRef* pIOSurface); - -#ifdef __OBJC__ -typedef void (VKAPI_PTR *PFN_vkGetMTLDeviceMVK)(VkPhysicalDevice physicalDevice, id* pMTLDevice); -typedef VkResult (VKAPI_PTR *PFN_vkSetMTLTextureMVK)(VkImage image, id mtlTexture); -typedef void (VKAPI_PTR *PFN_vkGetMTLTextureMVK)(VkImage image, id* pMTLTexture); -typedef void (VKAPI_PTR *PFN_vkGetMTLBufferMVK)(VkBuffer buffer, id* pMTLBuffer); -typedef void (VKAPI_PTR *PFN_vkGetMTLCommandQueueMVK)(VkQueue queue, id* pMTLCommandQueue); -#endif // __OBJC__ - - -#pragma mark - -#pragma mark Function prototypes - -#ifndef VK_NO_PROTOTYPES - -/** - * Populates the pConfiguration structure with the current 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 - * VK_MVK_MOLTENVK_SPEC_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 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 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 - * VK_MVK_MOLTENVK_SPEC_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 ignored, - const MVKConfiguration* pConfiguration, - size_t* pConfigurationSize); - -/** - * Populates the pMetalFeatures structure with the Metal-specific features - * supported by the specified physical device. - * - * If you are linking to an implementation of MoltenVK that was compiled from a different - * VK_MVK_MOLTENVK_SPEC_VERSION than your app was, the size of the MVKPhysicalDeviceMetalFeatures - * 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 *pMetalFeaturesSize to sizeof(MVKPhysicalDeviceMetalFeatures), - * to tell MoltenVK the limit of the size of your MVKPhysicalDeviceMetalFeatures structure. Upon return from - * this function, the value of *pMetalFeaturesSize will hold the actual number of bytes copied into your - * passed MVKPhysicalDeviceMetalFeatures structure, which will be the smaller of what your app thinks is the - * size of MVKPhysicalDeviceMetalFeatures, 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 MVKPhysicalDeviceMetalFeatures is different than the value passed in - * *pMetalFeaturesSize, 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 MVKPhysicalDeviceMetalFeatures to be by setting the value of pMetalFeatures to NULL. - * In that case, this function will set *pMetalFeaturesSize to the size that MoltenVK expects - * MVKPhysicalDeviceMetalFeatures to be. - * - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceMetalFeaturesMVK( - VkPhysicalDevice physicalDevice, - MVKPhysicalDeviceMetalFeatures* pMetalFeatures, - size_t* pMetalFeaturesSize); - -/** - * Populates the pPerf structure with the current performance statistics for the device. - * - * If you are linking to an implementation of MoltenVK that was compiled from a different - * VK_MVK_MOLTENVK_SPEC_VERSION than your app was, the size of the MVKPerformanceStatistics - * 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 *pPerfSize to sizeof(MVKPerformanceStatistics), - * to tell MoltenVK the limit of the size of your MVKPerformanceStatistics structure. Upon return - * from this function, the value of *pPerfSize will hold the actual number of bytes copied into - * your passed MVKPerformanceStatistics structure, which will be the smaller of what your app - * thinks is the size of MVKPerformanceStatistics, 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 MVKPerformanceStatistics is different than the value passed - * in *pPerfSize, 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 MVKPerformanceStatistics to be by setting the value of - * pPerf to NULL. In that case, this function will set *pPerfSize to the size that MoltenVK - * expects MVKPerformanceStatistics to be. - * - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkGetPerformanceStatisticsMVK( - VkDevice device, - MVKPerformanceStatistics* pPerf, - size_t* pPerfSize); - -/** - * Returns a human readable version of the MoltenVK and Vulkan versions. - * - * This function is provided as a convenience for reporting. Use the MVK_VERSION, - * VK_API_VERSION_1_0, and VK_HEADER_VERSION macros for programmatically accessing - * the corresponding version numbers. - */ -VKAPI_ATTR void VKAPI_CALL vkGetVersionStringsMVK( - char* pMoltenVersionStringBuffer, - uint32_t moltenVersionStringBufferLength, - char* pVulkanVersionStringBuffer, - uint32_t vulkanVersionStringBufferLength); - -/** - * Sets the number of threads in a workgroup for a compute kernel. - * - * This needs to be called if you are creating compute shader modules from MSL source code - * or MSL compiled code. If you are using SPIR-V, workgroup size is determined automatically. - * - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. - */ -VKAPI_ATTR void VKAPI_CALL vkSetWorkgroupSizeMVK( - VkShaderModule shaderModule, - uint32_t x, - uint32_t y, - uint32_t z); - -#ifdef __OBJC__ - -/** - * Returns, in the pMTLDevice pointer, the MTLDevice used by the VkPhysicalDevice. - * - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. - */ -VKAPI_ATTR void VKAPI_CALL vkGetMTLDeviceMVK( - VkPhysicalDevice physicalDevice, - id* pMTLDevice); - -/** - * Sets the VkImage to use the specified MTLTexture. - * - * Any differences in the properties of mtlTexture and this image will modify the - * properties of this image. - * - * If a MTLTexture has already been created for this image, it will be destroyed. - * - * Returns VK_SUCCESS. - * - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkSetMTLTextureMVK( - VkImage image, - id mtlTexture); - -/** - * Returns, in the pMTLTexture pointer, the MTLTexture currently underlaying the VkImage. - * - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. - */ -VKAPI_ATTR void VKAPI_CALL vkGetMTLTextureMVK( - VkImage image, - id* pMTLTexture); - -/** -* Returns, in the pMTLBuffer pointer, the MTLBuffer currently underlaying the VkBuffer. -* - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. -*/ -VKAPI_ATTR void VKAPI_CALL vkGetMTLBufferMVK( - VkBuffer buffer, - id* pMTLBuffer); - -/** -* Returns, in the pMTLCommandQueue pointer, the MTLCommandQueue currently underlaying the VkQueue. -* - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. -*/ -VKAPI_ATTR void VKAPI_CALL vkGetMTLCommandQueueMVK( - VkQueue queue, - id* pMTLCommandQueue); - -#endif // __OBJC__ - -/** - * Indicates that a VkImage should use an IOSurface to underlay the Metal texture. - * - * If ioSurface is not null, it will be used as the IOSurface, and any differences - * in the properties of that IOSurface will modify the properties of this image. - * - * If ioSurface is null, this image will create and use an IOSurface - * whose properties are compatible with the properties of this image. - * - * If a MTLTexture has already been created for this image, it will be destroyed. - * - * IOSurfaces are supported on the following platforms: - * - macOS 10.11 and above - * - iOS 11.0 and above - * - * To enable IOSurface support, ensure the Deployment Target build setting - * (MACOSX_DEPLOYMENT_TARGET or IPHONEOS_DEPLOYMENT_TARGET) is set to at least - * one of the values above when compiling MoltenVK, and any app that uses MoltenVK. - * - * Returns: - * - VK_SUCCESS. - * - VK_ERROR_FEATURE_NOT_PRESENT if IOSurfaces are not supported on the platform. - * - VK_ERROR_INITIALIZATION_FAILED if ioSurface is specified and is not compatible with this VkImage. - * - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkUseIOSurfaceMVK( - VkImage image, - IOSurfaceRef ioSurface); - -/** - * Returns, in the pIOSurface pointer, the IOSurface currently underlaying the VkImage, - * as set by the useIOSurfaceMVK() function, or returns null if the VkImage is not using - * an IOSurface, or if the platform does not support IOSurfaces. - * - * This function is not supported by the Vulkan SDK Loader and Layers framework - * and is unavailable when using the Vulkan SDK Loader and Layers framework. - */ -VKAPI_ATTR void VKAPI_CALL vkGetIOSurfaceMVK( - VkImage image, - IOSurfaceRef* pIOSurface); - - -#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 - - -#ifdef __cplusplus -} -#endif // __cplusplus +#include "mvk_vulkan.h" +#include "mvk_config.h" -#endif +#include "mvk_private_api.h" +#include "mvk_deprecated_api.h" diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm index 2a818c635..d68d4f81c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm @@ -23,7 +23,6 @@ #include "MVKBuffer.h" #include "MVKPipeline.h" #include "MVKFoundation.h" -#include "MVKEnvironment.h" #include "mvk_datatypes.hpp" diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 88e0b562d..dff93dc74 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -25,7 +25,6 @@ #include "MVKFramebuffer.h" #include "MVKRenderPass.h" #include "MTLRenderPassDescriptor+MoltenVK.h" -#include "MVKEnvironment.h" #include "mvk_datatypes.hpp" #include #include diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm index 181b220c5..a99f4f0fc 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm @@ -19,7 +19,6 @@ #include "MVKBuffer.h" #include "MVKCommandBuffer.h" #include "MVKFoundation.h" -#include "MVKEnvironment.h" #include "mvk_datatypes.hpp" using namespace std; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 42921801e..db484823a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -18,7 +18,6 @@ #pragma once -#include "MVKEnvironment.h" #include "MVKFoundation.h" #include "MVKVulkanAPIObject.h" #include "MVKMTLResourceBindings.h" @@ -27,6 +26,7 @@ #include "MVKSmallVector.h" #include "MVKPixelFormats.h" #include "MVKOSExtensions.h" +#include "mvk_private_api.h" #include "mvk_datatypes.hpp" #include #include diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 8937b90a3..2872db17e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -32,7 +32,6 @@ #include "MVKCommandPool.h" #include "MVKFoundation.h" #include "MVKCodec.h" -#include "MVKEnvironment.h" #include #import "CAMetalLayer+MoltenVK.h" diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm index 76bc37c5a..08a6fb9f7 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm @@ -20,7 +20,6 @@ #include "MVKBuffer.h" #include "MVKImage.h" #include "MVKQueue.h" -#include "MVKEnvironment.h" #include "mvk_datatypes.hpp" #include "MVKFoundation.h" #include diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 3fa4dce76..a71d5edac 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -21,7 +21,6 @@ #include "MVKSwapchain.h" #include "MVKCommandBuffer.h" #include "MVKCmdDebug.h" -#include "MVKEnvironment.h" #include "MVKFoundation.h" #include "MVKOSExtensions.h" #include "MVKCodec.h" diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h index 6f9066402..9e41ac71c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h @@ -18,7 +18,6 @@ #pragma once -#include "MVKEnvironment.h" #include "MVKLayers.h" #include "MVKVulkanAPIObject.h" #include "MVKSmallVector.h" diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 8988f7763..3d60ba653 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -22,6 +22,7 @@ #include "MVKFoundation.h" #include "MVKSurface.h" #include "MVKOSExtensions.h" +#include "mvk_deprecated_api.h" using namespace std; @@ -695,6 +696,10 @@ ADD_INST_EXT_ENTRY_POINT(vkSetMoltenVKConfigurationMVK, MVK_MOLTENVK); ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceMetalFeaturesMVK, MVK_MOLTENVK); ADD_INST_EXT_ENTRY_POINT(vkGetPerformanceStatisticsMVK, MVK_MOLTENVK); + + // Suppress deprecation warning for deprecated functions. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ADD_INST_EXT_ENTRY_POINT(vkGetVersionStringsMVK, MVK_MOLTENVK); ADD_INST_EXT_ENTRY_POINT(vkGetMTLDeviceMVK, MVK_MOLTENVK); ADD_INST_EXT_ENTRY_POINT(vkSetMTLTextureMVK, MVK_MOLTENVK); @@ -703,6 +708,7 @@ ADD_INST_EXT_ENTRY_POINT(vkUseIOSurfaceMVK, MVK_MOLTENVK); ADD_INST_EXT_ENTRY_POINT(vkGetIOSurfaceMVK, MVK_MOLTENVK); ADD_INST_EXT_ENTRY_POINT(vkGetMTLCommandQueueMVK, MVK_MOLTENVK); +#pragma clang diagnostic pop // Device extension functions: ADD_DVC_EXT_ENTRY_POINT(vkMapMemory2KHR, KHR_MAP_MEMORY_2); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h index 37bbf10e6..03fc0f98a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h @@ -18,10 +18,9 @@ #pragma once -#include "mvk_datatypes.h" -#include "MVKEnvironment.h" -#include "MVKOSExtensions.h" #include "MVKBaseObject.h" +#include "MVKOSExtensions.h" +#include "mvk_datatypes.h" #include #include diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKResource.mm b/MoltenVK/MoltenVK/GPUObjects/MVKResource.mm index 0e2131dcd..51b438ae8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKResource.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKResource.mm @@ -18,7 +18,6 @@ #include "MVKResource.h" #include "MVKCommandBuffer.h" -#include "MVKEnvironment.h" #pragma mark MVKResource diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h b/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h index 544c8dfac..0bcceb5d1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h @@ -19,7 +19,6 @@ #pragma once #include "MVKVulkanAPIObject.h" -#include "MVKEnvironment.h" #include #import diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 60bafd8f8..3dc05cc17 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -134,7 +134,6 @@ MVK_EXTENSION(INTEL_shader_integer_functions2, INTEL_SHADER_INTEGER_FUNCTION MVK_EXTENSION(GOOGLE_display_timing, GOOGLE_DISPLAY_TIMING, DEVICE, 10.11, 8.0) MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, INSTANCE, MVK_NA, 8.0) MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, INSTANCE, 10.11, MVK_NA) -MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, INSTANCE, 10.11, 8.0) MVK_EXTENSION(NV_fragment_shader_barycentric, NV_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0) MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER, DEVICE, 10.11, 8.0) diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm index 596f5882a..b2dc175ef 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm @@ -19,7 +19,6 @@ #include "MVKExtensions.h" #include "MVKFoundation.h" #include "MVKOSExtensions.h" -#include "MVKEnvironment.h" #include #include @@ -53,9 +52,6 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { auto advExtns = mvkConfig().advertiseExtensions; if ( !mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL) ) { #define MVK_NA kMVKOSVersionUnsupported - if (mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_MOLTENVK)) { - MVK_EXTENSION_MIN_OS(MVK_MOLTENVK, 10.11, 8.0) - } if (mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_WSI)) { MVK_EXTENSION_MIN_OS(EXT_METAL_SURFACE, 10.11, 8.0) MVK_EXTENSION_MIN_OS(MVK_IOS_SURFACE, MVK_NA, 8.0) diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.mm b/MoltenVK/MoltenVK/Layers/MVKLayers.mm index 040712b31..875722b89 100644 --- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm +++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm @@ -17,7 +17,6 @@ */ #include "MVKLayers.h" -#include "MVKEnvironment.h" #include "MVKFoundation.h" #include diff --git a/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm b/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm index 785694cd2..309518334 100644 --- a/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm +++ b/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm @@ -17,9 +17,7 @@ */ #include "MVKGPUCapture.h" -#include "MVKQueue.h" #include "MVKOSExtensions.h" -#include "MVKEnvironment.h" #pragma mark - diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h index d71a37f89..7005e9850 100644 --- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h +++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h @@ -18,7 +18,7 @@ #pragma once -#include "vk_mvk_moltenvk.h" +#include "MVKEnvironment.h" #include #include diff --git a/MoltenVK/MoltenVK/Utility/MVKCodec.h b/MoltenVK/MoltenVK/Utility/MVKCodec.h index 595a50fa6..a366dd786 100644 --- a/MoltenVK/MoltenVK/Utility/MVKCodec.h +++ b/MoltenVK/MoltenVK/Utility/MVKCodec.h @@ -20,7 +20,6 @@ #pragma once #include "MVKEnvironment.h" - #include #include diff --git a/MoltenVK/MoltenVK/Utility/MVKCodec.mm b/MoltenVK/MoltenVK/Utility/MVKCodec.mm index 49a8e6607..d75578f7d 100644 --- a/MoltenVK/MoltenVK/Utility/MVKCodec.mm +++ b/MoltenVK/MoltenVK/Utility/MVKCodec.mm @@ -24,6 +24,8 @@ #include #include +#import + using namespace std; using simd::float3; diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h index 417a86f8b..a4411c44c 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h @@ -20,8 +20,9 @@ #pragma once #include "MVKCommonEnvironment.h" +#include "mvk_vulkan.h" +#include "mvk_config.h" #include "MVKLogging.h" -#include "vk_mvk_moltenvk.h" // Expose MoltenVK Apple surface extension functionality diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index a0c96742b..ba594b72f 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -20,8 +20,7 @@ #pragma once -#include "MVKCommonEnvironment.h" -#include "mvk_vulkan.h" +#include "MVKEnvironment.h" #include #include #include diff --git a/MoltenVK/MoltenVK/Utility/MVKWatermark.mm b/MoltenVK/MoltenVK/Utility/MVKWatermark.mm index a016f98fe..7542b9b75 100644 --- a/MoltenVK/MoltenVK/Utility/MVKWatermark.mm +++ b/MoltenVK/MoltenVK/Utility/MVKWatermark.mm @@ -17,10 +17,10 @@ */ +#include "MVKEnvironment.h" #include "MVKWatermark.h" #include "MVKOSExtensions.h" #include "MTLTextureDescriptor+MoltenVK.h" -#include "MVKEnvironment.h" /** The structure to hold shader uniforms. */ diff --git a/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm b/MoltenVK/MoltenVK/Vulkan/mvk_api.mm similarity index 96% rename from MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm rename to MoltenVK/MoltenVK/Vulkan/mvk_api.mm index c6f7844ce..a5e53f3e1 100644 --- a/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_api.mm @@ -1,5 +1,5 @@ /* - * vk_mvk_moltenvk.mm + * mvk_api.mm * * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) * @@ -17,9 +17,10 @@ */ -#include "MVKInstance.h" -#include "vk_mvk_moltenvk.h" #include "MVKEnvironment.h" +#include "mvk_private_api.h" +#include "mvk_deprecated_api.h" +#include "MVKInstance.h" #include "MVKSwapchain.h" #include "MVKImage.h" #include "MVKBuffer.h" @@ -49,6 +50,10 @@ VkResult mvkCopy(S* pDst, const S* pSrc, size_t* pCopySize) { } } + +#pragma mark - +#pragma mark mvk_config.h + MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMoltenVKConfigurationMVK( VkInstance ignored, MVKConfiguration* pConfiguration, @@ -69,6 +74,10 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkSetMoltenVKConfigurationMVK( return rslt; } + +#pragma mark - +#pragma mark mvk_private_api.h + MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPhysicalDeviceMetalFeaturesMVK( VkPhysicalDevice physicalDevice, MVKPhysicalDeviceMetalFeatures* pMetalFeatures, @@ -88,6 +97,10 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPerformanceStatisticsMVK( return mvkCopy(pPerf, &mvkPerf, pPerfSize); } + +#pragma mark - +#pragma mark mvk_deprecated_api.h + MVK_PUBLIC_VULKAN_SYMBOL void vkGetVersionStringsMVK( char* pMoltenVersionStringBuffer, uint32_t moltenVersionStringBufferLength, diff --git a/README.md b/README.md index 20249d647..e55b96e0a 100644 --- a/README.md +++ b/README.md @@ -268,14 +268,14 @@ 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 within *Xcode*. -When building from the command line, you can set any of the build settings documented in -the `vk_mvk_moltenvk.h` file for `MVKConfiguration`, by passing them in the command line, +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, as in the following examples: make MVK_CONFIG_LOG_LEVEL=0 or - make macos MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS=1 + make macos MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=2 ...etc. diff --git a/Scripts/runcts b/Scripts/runcts index 2349e75d0..8b956422b 100755 --- a/Scripts/runcts +++ b/Scripts/runcts @@ -39,7 +39,6 @@ # only Vulkan 1.0, and only the following extensions: # VK_KHR_get_physical_device_properties2 # VK_KHR_portability_subset -# VK_MVK_moltenvk # cts_vk_dir="../../VK-GL-CTS/build/external/vulkancts/modules/vulkan/Debug" @@ -85,7 +84,7 @@ 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 vk_mvk_moltenvk.h. +# 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). From f33e718da4ad014b4ab5432bb9c27abded009778 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 3 May 2023 10:15:53 -0400 Subject: [PATCH 11/74] Expose pointers to functions from removed VK_MVK_moltenvk extension. - MVKInstance reorganize list of entry points for visual clarity (unrelated). - Fixes to deprecation documentation (unrelated). - mvkStringsAreEqual() add small performance optimization (unrelated). --- MoltenVK/MoltenVK/API/mvk_config.h | 6 +- MoltenVK/MoltenVK/API/mvk_private_api.h | 8 +- MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 109 ++++++++++---------- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 7 +- 4 files changed, 68 insertions(+), 62 deletions(-) diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index bd4d03cb4..6237c5b81 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -171,7 +171,7 @@ typedef enum MVKConfigActivityPerformanceLoggingStyle { * 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 VK_MVK_MOLTENVK_SPEC_VERSION + * 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. @@ -944,7 +944,7 @@ typedef struct { * 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 - * VK_MVK_MOLTENVK_SPEC_VERSION than your app was, the size of the MVKConfiguration structure + * 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), @@ -982,7 +982,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( * 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 - * VK_MVK_MOLTENVK_SPEC_VERSION than your app was, the size of the MVKConfiguration structure + * 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), diff --git a/MoltenVK/MoltenVK/API/mvk_private_api.h b/MoltenVK/MoltenVK/API/mvk_private_api.h index dd79756de..87bc8ad99 100644 --- a/MoltenVK/MoltenVK/API/mvk_private_api.h +++ b/MoltenVK/MoltenVK/API/mvk_private_api.h @@ -70,7 +70,7 @@ typedef VkFlags MVKCounterSamplingFlags; * retrieve a copy of this structure using the vkGetPhysicalDeviceMetalFeaturesMVK() function. * * 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 VK_MVK_MOLTENVK_SPEC_VERSION + * an implementation of MoltenVK that was compiled from a different MVK_PRIVATE_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 vkGetPhysicalDeviceMetalFeaturesMVK() function * for information about how to handle this. @@ -196,7 +196,7 @@ typedef struct { * MoltenVK performance. You can retrieve a copy of this structure using the vkGetPerformanceStatisticsMVK() function. * * 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 VK_MVK_MOLTENVK_SPEC_VERSION + * an implementation of MoltenVK that was compiled from a different MVK_PRIVATE_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 vkGetPerformanceStatisticsMVK() function for * information about how to handle this. @@ -229,7 +229,7 @@ typedef VkResult (VKAPI_PTR *PFN_vkGetPerformanceStatisticsMVK)(VkDevice device, * supported by the specified physical device. * * If you are linking to an implementation of MoltenVK that was compiled from a different - * VK_MVK_MOLTENVK_SPEC_VERSION than your app was, the size of the MVKPhysicalDeviceMetalFeatures + * MVK_PRIVATE_API_VERSION than your app was, the size of the MVKPhysicalDeviceMetalFeatures * 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 *pMetalFeaturesSize to sizeof(MVKPhysicalDeviceMetalFeatures), @@ -259,7 +259,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceMetalFeaturesMVK( * Populates the pPerf structure with the current performance statistics for the device. * * If you are linking to an implementation of MoltenVK that was compiled from a different - * VK_MVK_MOLTENVK_SPEC_VERSION than your app was, the size of the MVKPerformanceStatistics + * MVK_PRIVATE_API_VERSION than your app was, the size of the MVKPerformanceStatistics * 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 *pPerfSize to sizeof(MVKPerformanceStatistics), diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 3d60ba653..7676fbe0e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -438,10 +438,14 @@ #define ADD_INST_EXT2_ENTRY_POINT(func, EXT1, EXT2) ADD_ENTRY_POINT(func, 0, VK_##EXT1##_EXTENSION_NAME, VK_##EXT2##_EXTENSION_NAME, false) #define ADD_DVC_EXT2_ENTRY_POINT(func, EXT1, EXT2) ADD_ENTRY_POINT(func, 0, VK_##EXT1##_EXTENSION_NAME, VK_##EXT2##_EXTENSION_NAME, true) +// Add an open function, not tied to core or an extension. +#define ADD_INST_OPEN_ENTRY_POINT(func) ADD_ENTRY_POINT(func, 0, nullptr, nullptr, false) +#define ADD_DVC_OPEN_ENTRY_POINT(func) ADD_ENTRY_POINT(func, 0, nullptr, nullptr, true) + // Initializes the function pointer map. void MVKInstance::initProcAddrs() { - // Instance functions + // Instance functions. ADD_INST_ENTRY_POINT(vkDestroyInstance); ADD_INST_ENTRY_POINT(vkEnumeratePhysicalDevices); ADD_INST_ENTRY_POINT(vkGetPhysicalDeviceFeatures); @@ -469,7 +473,57 @@ ADD_INST_1_3_PROMOTED_ENTRY_POINT(vkGetPhysicalDeviceToolProperties, EXT_TOOLING_INFO); - // Device functions: + // Instance extension functions. + ADD_INST_EXT_ENTRY_POINT(vkDestroySurfaceKHR, KHR_SURFACE); + ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceSupportKHR, KHR_SURFACE); + ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, KHR_SURFACE); + ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceFormatsKHR, KHR_SURFACE); + 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(vkCreateDebugReportCallbackEXT, EXT_DEBUG_REPORT); + ADD_INST_EXT_ENTRY_POINT(vkDestroyDebugReportCallbackEXT, EXT_DEBUG_REPORT); + ADD_INST_EXT_ENTRY_POINT(vkDebugReportMessageEXT, EXT_DEBUG_REPORT); + ADD_INST_EXT_ENTRY_POINT(vkSetDebugUtilsObjectNameEXT, EXT_DEBUG_UTILS); + ADD_INST_EXT_ENTRY_POINT(vkSetDebugUtilsObjectTagEXT, EXT_DEBUG_UTILS); + ADD_INST_EXT_ENTRY_POINT(vkQueueBeginDebugUtilsLabelEXT, EXT_DEBUG_UTILS); + ADD_INST_EXT_ENTRY_POINT(vkQueueEndDebugUtilsLabelEXT, EXT_DEBUG_UTILS); + ADD_INST_EXT_ENTRY_POINT(vkQueueInsertDebugUtilsLabelEXT, EXT_DEBUG_UTILS); + ADD_INST_EXT_ENTRY_POINT(vkCmdBeginDebugUtilsLabelEXT, EXT_DEBUG_UTILS); + ADD_INST_EXT_ENTRY_POINT(vkCmdEndDebugUtilsLabelEXT, EXT_DEBUG_UTILS); + ADD_INST_EXT_ENTRY_POINT(vkCmdInsertDebugUtilsLabelEXT, EXT_DEBUG_UTILS); + 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); +#endif +#ifdef VK_USE_PLATFORM_MACOS_MVK + ADD_INST_EXT_ENTRY_POINT(vkCreateMacOSSurfaceMVK, MVK_MACOS_SURFACE); +#endif + + // 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(vkGetVersionStringsMVK); + ADD_INST_OPEN_ENTRY_POINT(vkGetMTLDeviceMVK); + ADD_INST_OPEN_ENTRY_POINT(vkSetMTLTextureMVK); + ADD_INST_OPEN_ENTRY_POINT(vkGetMTLTextureMVK); + ADD_INST_OPEN_ENTRY_POINT(vkGetMTLBufferMVK); + ADD_INST_OPEN_ENTRY_POINT(vkUseIOSurfaceMVK); + ADD_INST_OPEN_ENTRY_POINT(vkGetIOSurfaceMVK); + ADD_INST_OPEN_ENTRY_POINT(vkGetMTLCommandQueueMVK); +#pragma clang diagnostic pop + + // Device functions. ADD_DVC_ENTRY_POINT(vkGetDeviceProcAddr); ADD_DVC_ENTRY_POINT(vkDestroyDevice); ADD_DVC_ENTRY_POINT(vkGetDeviceQueue); @@ -661,56 +715,7 @@ ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkQueueSubmit2, KHR, KHR_SYNCHRONIZATION_2); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkSetPrivateData, EXT, EXT_PRIVATE_DATA); - // Instance extension functions: - ADD_INST_EXT_ENTRY_POINT(vkDestroySurfaceKHR, KHR_SURFACE); - ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceSupportKHR, KHR_SURFACE); - ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, KHR_SURFACE); - ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceFormatsKHR, KHR_SURFACE); - 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(vkCreateDebugReportCallbackEXT, EXT_DEBUG_REPORT); - ADD_INST_EXT_ENTRY_POINT(vkDestroyDebugReportCallbackEXT, EXT_DEBUG_REPORT); - ADD_INST_EXT_ENTRY_POINT(vkDebugReportMessageEXT, EXT_DEBUG_REPORT); - ADD_INST_EXT_ENTRY_POINT(vkSetDebugUtilsObjectNameEXT, EXT_DEBUG_UTILS); - ADD_INST_EXT_ENTRY_POINT(vkSetDebugUtilsObjectTagEXT, EXT_DEBUG_UTILS); - ADD_INST_EXT_ENTRY_POINT(vkQueueBeginDebugUtilsLabelEXT, EXT_DEBUG_UTILS); - ADD_INST_EXT_ENTRY_POINT(vkQueueEndDebugUtilsLabelEXT, EXT_DEBUG_UTILS); - ADD_INST_EXT_ENTRY_POINT(vkQueueInsertDebugUtilsLabelEXT, EXT_DEBUG_UTILS); - ADD_INST_EXT_ENTRY_POINT(vkCmdBeginDebugUtilsLabelEXT, EXT_DEBUG_UTILS); - ADD_INST_EXT_ENTRY_POINT(vkCmdEndDebugUtilsLabelEXT, EXT_DEBUG_UTILS); - ADD_INST_EXT_ENTRY_POINT(vkCmdInsertDebugUtilsLabelEXT, EXT_DEBUG_UTILS); - 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); -#endif -#ifdef VK_USE_PLATFORM_MACOS_MVK - ADD_INST_EXT_ENTRY_POINT(vkCreateMacOSSurfaceMVK, MVK_MACOS_SURFACE); -#endif - - ADD_INST_EXT_ENTRY_POINT(vkGetMoltenVKConfigurationMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkSetMoltenVKConfigurationMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceMetalFeaturesMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkGetPerformanceStatisticsMVK, MVK_MOLTENVK); - - // Suppress deprecation warning for deprecated functions. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - ADD_INST_EXT_ENTRY_POINT(vkGetVersionStringsMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkGetMTLDeviceMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkSetMTLTextureMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkGetMTLTextureMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkGetMTLBufferMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkUseIOSurfaceMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkGetIOSurfaceMVK, MVK_MOLTENVK); - ADD_INST_EXT_ENTRY_POINT(vkGetMTLCommandQueueMVK, MVK_MOLTENVK); -#pragma clang diagnostic pop - - // Device extension functions: + // Device extension functions. ADD_DVC_EXT_ENTRY_POINT(vkMapMemory2KHR, KHR_MAP_MEMORY_2); ADD_DVC_EXT_ENTRY_POINT(vkUnmapMemory2KHR, KHR_MAP_MEMORY_2); ADD_DVC_EXT_ENTRY_POINT(vkCmdPushDescriptorSetKHR, KHR_PUSH_DESCRIPTOR); diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index ba594b72f..7c4af3da4 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -552,12 +552,13 @@ bool mvkAreEqual(const T* pV1, const T* pV2, size_t count = 1) { } /** - * If both pV1 and pV2 are not null, returns whether the contents of the two strings are equal, - * otherwise returns false. This functionality is different than the char version of mvkAreEqual(), + * Returns whether the contents of the two strings are equal, otherwise returns false. + * This functionality is different than the char version of mvkAreEqual(), * which works on individual chars or char arrays, not strings. + * Returns false if either string is null. */ static constexpr bool mvkStringsAreEqual(const char* pV1, const char* pV2, size_t count = 1) { - return (pV1 && pV2) ? (strcmp(pV1, pV2) == 0) : false; + return pV1 && pV2 && (pV1 == pV2 || strcmp(pV1, pV2) == 0); } /** From 789d432156101b117af3dc9cc7f8bc3794876304 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 3 May 2023 22:39:35 -0400 Subject: [PATCH 12/74] Avoid Metal validation warning when depth component swizzled away. - Set Metal depth store action to MTLStoreActionDontCare when depth attachment exists, but depth component has been swizzled away. --- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index af06d9b0b..762d72d9b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm @@ -705,23 +705,29 @@ bool storeOverride) { // For a combined depth-stencil format in an attachment with VK_IMAGE_ASPECT_STENCIL_BIT, // the attachment format may have been swizzled to a stencil-only format. In this case, - // we want to guard against an attempt to store the non-existent depth component. + // we must avoid either storing, or leaving unknown, the non-existent depth component. + // We check for depth swizzling by looking at the original image format as well. MTLPixelFormat mtlFmt = attachment->getMTLPixelFormat(); MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); - bool isDepthFormat = pixFmts->isDepthFormat(mtlFmt); bool isStencilFormat = pixFmts->isStencilFormat(mtlFmt); + bool isDepthFormat = pixFmts->isDepthFormat(mtlFmt); + bool isDepthSwizzled = false; + if (isStencilFormat && !isDepthFormat) { + isDepthFormat = pixFmts->isDepthFormat(attachment->getImage()->getMTLPixelFormat()); + isDepthSwizzled = isDepthFormat; + } bool isColorFormat = !(isDepthFormat || isStencilFormat); bool isMemorylessAttachment = false; #if MVK_APPLE_SILICON isMemorylessAttachment = attachment->getMTLTexture().storageMode == MTLStorageModeMemoryless; #endif - MTLStoreAction storeAction = getMTLStoreAction(subpass, isRenderingEntireAttachment, isMemorylessAttachment, hasResolveAttachment, canResolveFormat, isStencil, storeOverride); - + MTLStoreAction storeAction = getMTLStoreAction(subpass, isRenderingEntireAttachment, isMemorylessAttachment, + hasResolveAttachment, canResolveFormat, isStencil, storeOverride); if (isColorFormat) { [cmdEncoder->_mtlRenderEncoder setColorStoreAction: storeAction atIndex: caIdx]; } else if (isDepthFormat && !isStencil) { - [cmdEncoder->_mtlRenderEncoder setDepthStoreAction: storeAction]; + [cmdEncoder->_mtlRenderEncoder setDepthStoreAction: (isDepthSwizzled ? MTLStoreActionDontCare : storeAction)]; } else if (isStencilFormat && isStencil) { [cmdEncoder->_mtlRenderEncoder setStencilStoreAction: storeAction]; } From 3db62a1d7bbea0bbeddbb3830af2917a39cc54be Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 4 May 2023 11:08:16 -0400 Subject: [PATCH 13/74] Reinstate VK_MVK_moltenvk extension and add simplified config functions. - Reinstate VK_MVK_moltenvk extension, but log warning message when it is enabled. - Add vkGetMoltenVKConfiguration2MVK() and vkSetMoltenVKConfiguration2MVK() to set config without passing a dummy VkInstance, and deprecate vkGetMoltenVKConfigurationMVK() and vkSetMoltenVKConfigurationMVK(). --- Docs/Whats_New.md | 2 + MoltenVK/MoltenVK/API/mvk_config.h | 18 ++---- MoltenVK/MoltenVK/API/mvk_deprecated_api.h | 70 +++++++++++++++------ MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 8 ++- MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 34 +++++----- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Layers/MVKExtensions.mm | 6 ++ MoltenVK/MoltenVK/Vulkan/mvk_api.mm | 33 +++++++--- 8 files changed, 114 insertions(+), 58 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index add2a09e3..d679b3686 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -23,6 +23,8 @@ Released TBD - Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). - Support separate depth and stencil attachments during dynamic rendering. - Deprecate the obsolete and non-standard `VK_MVK_moltenvk` extension. +- Add `vkGetMoltenVKConfiguration2MVK()` and `vkGetMoltenVKConfiguration2MVK()` to clarify + MoltenVK config does not require any Vulkan objects. - Fix memory leak when waiting on timeline semaphores. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index 6237c5b81..b0777a14a 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -920,8 +920,8 @@ typedef struct { #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); + typedef VkResult (VKAPI_PTR *PFN_vkGetMoltenVKConfiguration2MVK)(MVKConfiguration* pConfiguration, size_t* pConfigurationSize); + typedef VkResult (VKAPI_PTR *PFN_vkSetMoltenVKConfiguration2MVK)(const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); #pragma mark - @@ -936,10 +936,6 @@ typedef struct { * 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. * @@ -962,8 +958,7 @@ typedef struct { * 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, +VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfiguration2MVK( MVKConfiguration* pConfiguration, size_t* pConfigurationSize); @@ -974,10 +969,6 @@ VKAPI_ATTR VkResult VKAPI_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. * @@ -1000,8 +991,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( * 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 ignored, +VKAPI_ATTR VkResult VKAPI_CALL vkSetMoltenVKConfiguration2MVK( const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); diff --git a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h index b7d7c6ff5..cf7f9a5ff 100644 --- a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h +++ b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h @@ -23,21 +23,17 @@ #ifdef __cplusplus extern "C" { #endif // __cplusplus - -#include + +#include #include - + #define VK_MVK_MOLTENVK_SPEC_VERSION 37 #define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk" -#define MVK_DEPRECATED VKAPI_ATTR [[deprecated]] -#define MVK_DEPRECATED_USE_MTL_OBJS VKAPI_ATTR [[deprecated("Use the VK_EXT_metal_objects extension instead.")]] - - /** - * This header contains obsolete and deprecated MoltenVK functions, that were origionally - * part of the obsolete and deprecated private VK_MVK_moltenvk extension. + * This header contains obsolete and deprecated MoltenVK functions, that were originally + * part of the obsolete and deprecated non-standard VK_MVK_moltenvk extension. * * 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. @@ -53,6 +49,8 @@ extern "C" { #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); 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,20 +70,41 @@ typedef void (VKAPI_PTR *PFN_vkGetMTLCommandQueueMVK)(VkQueue queue, id* pMTLDevice); /** + * DEPRECATED. Use the VK_EXT_metal_objects extension instead. * Sets the VkImage to use the specified MTLTexture. * * Any differences in the properties of mtlTexture and this image will modify the @@ -125,43 +148,51 @@ MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLDeviceMVK( * This function is not supported by the Vulkan SDK Loader and Layers framework * and is unavailable when using the Vulkan SDK Loader and Layers framework. */ -MVK_DEPRECATED_USE_MTL_OBJS VkResult VKAPI_CALL vkSetMTLTextureMVK( +MVK_DEPRECATED_USE_MTL_OBJS +VkResult VKAPI_CALL vkSetMTLTextureMVK( VkImage image, id mtlTexture); /** + * DEPRECATED. Use the VK_EXT_metal_objects extension instead. * Returns, in the pMTLTexture pointer, the MTLTexture currently underlaying the VkImage. * * This function is not supported by the Vulkan SDK Loader and Layers framework * and is unavailable when using the Vulkan SDK Loader and Layers framework. */ -MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLTextureMVK( +MVK_DEPRECATED_USE_MTL_OBJS +void VKAPI_CALL vkGetMTLTextureMVK( VkImage image, id* pMTLTexture); /** + * DEPRECATED. Use the VK_EXT_metal_objects extension instead. * Returns, in the pMTLBuffer pointer, the MTLBuffer currently underlaying the VkBuffer. * * This function is not supported by the Vulkan SDK Loader and Layers framework * and is unavailable when using the Vulkan SDK Loader and Layers framework. */ -MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLBufferMVK( +MVK_DEPRECATED_USE_MTL_OBJS +void VKAPI_CALL vkGetMTLBufferMVK( VkBuffer buffer, id* pMTLBuffer); /** + * DEPRECATED. Use the VK_EXT_metal_objects extension instead. * Returns, in the pMTLCommandQueue pointer, the MTLCommandQueue currently underlaying the VkQueue. * * This function is not supported by the Vulkan SDK Loader and Layers framework * and is unavailable when using the Vulkan SDK Loader and Layers framework. */ -MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLCommandQueueMVK( +MVK_DEPRECATED_USE_MTL_OBJS +void VKAPI_CALL vkGetMTLCommandQueueMVK( VkQueue queue, id* pMTLCommandQueue); #endif // __OBJC__ /** + * DEPRECATED. Use the VK_EXT_metal_objects extension instead. * Indicates that a VkImage should use an IOSurface to underlay the Metal texture. * * If ioSurface is not null, it will be used as the IOSurface, and any differences @@ -188,11 +219,13 @@ MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetMTLCommandQueueMVK( * This function is not supported by the Vulkan SDK Loader and Layers framework * and is unavailable when using the Vulkan SDK Loader and Layers framework. */ -MVK_DEPRECATED_USE_MTL_OBJS VkResult VKAPI_CALL vkUseIOSurfaceMVK( +MVK_DEPRECATED_USE_MTL_OBJS +VkResult VKAPI_CALL vkUseIOSurfaceMVK( VkImage image, IOSurfaceRef ioSurface); /** + * DEPRECATED. Use the VK_EXT_metal_objects extension instead. * Returns, in the pIOSurface pointer, the IOSurface currently underlaying the VkImage, * as set by the useIOSurfaceMVK() function, or returns null if the VkImage is not using * an IOSurface, or if the platform does not support IOSurfaces. @@ -200,7 +233,8 @@ MVK_DEPRECATED_USE_MTL_OBJS VkResult VKAPI_CALL vkUseIOSurfaceMVK( * This function is not supported by the Vulkan SDK Loader and Layers framework * and is unavailable when using the Vulkan SDK Loader and Layers framework. */ -MVK_DEPRECATED_USE_MTL_OBJS void VKAPI_CALL vkGetIOSurfaceMVK( +MVK_DEPRECATED_USE_MTL_OBJS +void VKAPI_CALL vkGetIOSurfaceMVK( VkImage image, IOSurfaceRef* pIOSurface); diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index b6cabcd57..a9b2d67d8 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -18,8 +18,9 @@ /** * This header is provided for legacy compatibility only. This header contains obsolete and - * deprecated MoltenVK functions, that were origionally part of the obsolete and deprecated - * private VK_MVK_moltenvk extension, and use of this header is not recommended. + * deprecated MoltenVK functions, that were originally part of the obsolete and deprecated + * non-standard VK_MVK_moltenvk extension, and use of this header is not recommended. + * * Instead, in your application, use the following header file: * * #include @@ -27,6 +28,9 @@ * And if you require the MoltenVK Configuration API, also include 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" diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 7676fbe0e..5087bf9e1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -341,11 +341,6 @@ initProcAddrs(); // Init function pointers - setConfigurationResult(verifyLayers(pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames)); - MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_enabledExtensions; - setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount, - pCreateInfo->ppEnabledExtensionNames, - getDriverLayer()->getSupportedInstanceExtensions())); logVersions(); // Log the MoltenVK and Vulkan versions // Populate the array of physical GPU devices. @@ -367,6 +362,13 @@ setConfigurationResult(reportError(VK_ERROR_INCOMPATIBLE_DRIVER, "To support Mac Catalyst, MoltenVK requires macOS 11.0 or above.")); } + // Enable extensions after logging the system and GPU info, for any logging done during extension enablement. + setConfigurationResult(verifyLayers(pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames)); + MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_enabledExtensions; + setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount, + pCreateInfo->ppEnabledExtensionNames, + getDriverLayer()->getSupportedInstanceExtensions())); + MVKLogInfo("Created VkInstance for Vulkan version %s, as requested by app, with the following %d Vulkan extensions enabled:%s", mvkGetVulkanVersionString(_appInfo.apiVersion).c_str(), _enabledExtensions.getEnabledCount(), @@ -505,22 +507,24 @@ #endif // 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(vkGetMoltenVKConfiguration2MVK); + ADD_INST_OPEN_ENTRY_POINT(vkSetMoltenVKConfiguration2MVK); 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(vkGetVersionStringsMVK); - ADD_INST_OPEN_ENTRY_POINT(vkGetMTLDeviceMVK); - ADD_INST_OPEN_ENTRY_POINT(vkSetMTLTextureMVK); - ADD_INST_OPEN_ENTRY_POINT(vkGetMTLTextureMVK); - ADD_INST_OPEN_ENTRY_POINT(vkGetMTLBufferMVK); - ADD_INST_OPEN_ENTRY_POINT(vkUseIOSurfaceMVK); - ADD_INST_OPEN_ENTRY_POINT(vkGetIOSurfaceMVK); - ADD_INST_OPEN_ENTRY_POINT(vkGetMTLCommandQueueMVK); + ADD_INST_EXT_ENTRY_POINT(vkGetMoltenVKConfigurationMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkSetMoltenVKConfigurationMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkGetVersionStringsMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkGetMTLDeviceMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkSetMTLTextureMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkGetMTLTextureMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkGetMTLBufferMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkUseIOSurfaceMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkGetIOSurfaceMVK, MVK_MOLTENVK); + ADD_INST_EXT_ENTRY_POINT(vkGetMTLCommandQueueMVK, MVK_MOLTENVK); #pragma clang diagnostic pop // Device functions. diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 3dc05cc17..60bafd8f8 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -134,6 +134,7 @@ MVK_EXTENSION(INTEL_shader_integer_functions2, INTEL_SHADER_INTEGER_FUNCTION MVK_EXTENSION(GOOGLE_display_timing, GOOGLE_DISPLAY_TIMING, DEVICE, 10.11, 8.0) MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, INSTANCE, MVK_NA, 8.0) MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, INSTANCE, 10.11, MVK_NA) +MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, INSTANCE, 10.11, 8.0) MVK_EXTENSION(NV_fragment_shader_barycentric, NV_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0) MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER, DEVICE, 10.11, 8.0) diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm index b2dc175ef..507dc92eb 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm @@ -19,6 +19,7 @@ #include "MVKExtensions.h" #include "MVKFoundation.h" #include "MVKOSExtensions.h" +#include "mvk_deprecated_api.h" #include #include @@ -164,6 +165,11 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { result = reportError(VK_ERROR_EXTENSION_NOT_PRESENT, "Vulkan extension %s is not supported.", extnName); } else { enable(extnName); + if (mvkStringsAreEqual(extnName, VK_MVK_MOLTENVK_EXTENSION_NAME)) { + reportMessage(MVK_CONFIG_LOG_LEVEL_WARNING, "Extension %s is deprecated. For access to Metal objects, use extension %s. " + "For MoltenVK configuration, use the global vkGetMoltenVKConfiguration2MVK() and vkSetMoltenVKConfiguration2MVK() functions.", + VK_MVK_MOLTENVK_EXTENSION_NAME, VK_EXT_METAL_OBJECTS_EXTENSION_NAME); + } } } return result; diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_api.mm b/MoltenVK/MoltenVK/Vulkan/mvk_api.mm index a5e53f3e1..ac901f8bf 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_api.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_api.mm @@ -31,6 +31,7 @@ using namespace std; +// Copies the contents of a struct that might grow larger across MoltenVK versions. // If pSrc and pDst are not null, copies at most *pCopySize bytes from the contents of the // source struct to the destination struct, and sets *pCopySize to the number of bytes copied, // which is the smaller of the original value of *pCopySize and the actual size of the struct. @@ -38,7 +39,7 @@ // the struct, or VK_INCOMPLETE otherwise. If either pSrc or pDst are null, sets the value // of *pCopySize to the size of the struct and returns VK_SUCCESS. template -VkResult mvkCopy(S* pDst, const S* pSrc, size_t* pCopySize) { +VkResult mvkCopyGrowingStruct(S* pDst, const S* pSrc, size_t* pCopySize) { if (pSrc && pDst) { size_t origSize = *pCopySize; *pCopySize = std::min(origSize, sizeof(S)); @@ -54,22 +55,20 @@ VkResult mvkCopy(S* pDst, const S* pSrc, size_t* pCopySize) { #pragma mark - #pragma mark mvk_config.h -MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMoltenVKConfigurationMVK( - VkInstance ignored, +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMoltenVKConfiguration2MVK( MVKConfiguration* pConfiguration, size_t* pConfigurationSize) { - return mvkCopy(pConfiguration, &mvkConfig(), pConfigurationSize); + return mvkCopyGrowingStruct(pConfiguration, &mvkConfig(), pConfigurationSize); } -MVK_PUBLIC_VULKAN_SYMBOL VkResult vkSetMoltenVKConfigurationMVK( - VkInstance ignored, +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkSetMoltenVKConfiguration2MVK( const MVKConfiguration* pConfiguration, size_t* pConfigurationSize) { // Start with copy of current config, in case incoming is not fully copied MVKConfiguration mvkCfg = mvkConfig(); - VkResult rslt = mvkCopy(&mvkCfg, pConfiguration, pConfigurationSize); + VkResult rslt = mvkCopyGrowingStruct(&mvkCfg, pConfiguration, pConfigurationSize); mvkSetConfig(mvkCfg); return rslt; } @@ -84,7 +83,7 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPhysicalDeviceMetalFeaturesMVK( size_t* pMetalFeaturesSize) { MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice); - return mvkCopy(pMetalFeatures, mvkPD->getMetalFeatures(), pMetalFeaturesSize); + return mvkCopyGrowingStruct(pMetalFeatures, mvkPD->getMetalFeatures(), pMetalFeaturesSize); } MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPerformanceStatisticsMVK( @@ -94,13 +93,29 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPerformanceStatisticsMVK( MVKPerformanceStatistics mvkPerf; MVKDevice::getMVKDevice(device)->getPerformanceStatistics(&mvkPerf); - return mvkCopy(pPerf, &mvkPerf, pPerfSize); + return mvkCopyGrowingStruct(pPerf, &mvkPerf, pPerfSize); } #pragma mark - #pragma mark mvk_deprecated_api.h +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMoltenVKConfigurationMVK( + VkInstance ignored, + MVKConfiguration* pConfiguration, + size_t* pConfigurationSize) { + + return vkGetMoltenVKConfiguration2MVK(pConfiguration, pConfigurationSize); +} + +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkSetMoltenVKConfigurationMVK( + VkInstance ignored, + const MVKConfiguration* pConfiguration, + size_t* pConfigurationSize) { + + return vkSetMoltenVKConfiguration2MVK(pConfiguration, pConfigurationSize); +} + MVK_PUBLIC_VULKAN_SYMBOL void vkGetVersionStringsMVK( char* pMoltenVersionStringBuffer, uint32_t moltenVersionStringBufferLength, From cde220a277599b489d629921e19a7c41805e8ca6 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Fri, 5 May 2023 11:41:06 -0400 Subject: [PATCH 14/74] Remove vkGetMoltenVKConfiguration2MVK() and vkSetMoltenVKConfiguration2MVK(). Also undeprecate the original vkGet/SetMoltenVKConfigurationMVK(). In expectation of the upcoming VK_EXT_layer_settings extension, it is felt that adding these additional functions at this time would be confusing to app devs. --- Docs/Whats_New.md | 2 -- MoltenVK/MoltenVK/API/mvk_config.h | 18 +++++++++++++---- MoltenVK/MoltenVK/API/mvk_deprecated_api.h | 16 --------------- MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 6 ++---- MoltenVK/MoltenVK/Layers/MVKExtensions.mm | 2 +- MoltenVK/MoltenVK/Vulkan/mvk_api.mm | 22 ++++----------------- 6 files changed, 21 insertions(+), 45 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index d679b3686..add2a09e3 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -23,8 +23,6 @@ Released TBD - Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). - Support separate depth and stencil attachments during dynamic rendering. - Deprecate the obsolete and non-standard `VK_MVK_moltenvk` extension. -- Add `vkGetMoltenVKConfiguration2MVK()` and `vkGetMoltenVKConfiguration2MVK()` to clarify - MoltenVK config does not require any Vulkan objects. - Fix memory leak when waiting on timeline semaphores. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index b0777a14a..6237c5b81 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -920,8 +920,8 @@ typedef struct { #pragma mark - #pragma mark Function types - typedef VkResult (VKAPI_PTR *PFN_vkGetMoltenVKConfiguration2MVK)(MVKConfiguration* pConfiguration, size_t* pConfigurationSize); - typedef VkResult (VKAPI_PTR *PFN_vkSetMoltenVKConfiguration2MVK)(const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); + 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 - @@ -936,6 +936,10 @@ typedef struct { * 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. * @@ -958,7 +962,8 @@ typedef struct { * to NULL. In that case, this function will set *pConfigurationSize to the size that MoltenVK * expects MVKConfiguration to be. */ -VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfiguration2MVK( +VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( + VkInstance ignored, MVKConfiguration* pConfiguration, size_t* pConfigurationSize); @@ -969,6 +974,10 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfiguration2MVK( * 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. * @@ -991,7 +1000,8 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfiguration2MVK( * to NULL. In that case, this function will set *pConfigurationSize to the size that MoltenVK * expects MVKConfiguration to be. */ -VKAPI_ATTR VkResult VKAPI_CALL vkSetMoltenVKConfiguration2MVK( +VKAPI_ATTR VkResult VKAPI_CALL vkSetMoltenVKConfigurationMVK( + VkInstance ignored, const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); diff --git a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h index cf7f9a5ff..d6fc4aadd 100644 --- a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h +++ b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h @@ -49,8 +49,6 @@ extern "C" { #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); 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); @@ -74,20 +72,6 @@ typedef void (VKAPI_PTR *PFN_vkGetMTLCommandQueueMVK)(VkQueue queue, id Date: Fri, 5 May 2023 14:45:43 -0400 Subject: [PATCH 15/74] Fix race condition when updating values in VkPastPresentationTimingGOOGLE. - MVKPresentableSwapchainImage::presentCAMetalDrawable() and addPresentedHandler() pass MVKImagePresentInfo by value instead of reference, to avoid callbacks colliding with tracked MVKImagePresentInfos being cleared when MVKQueuePresentSurfaceSubmission is destroyed after it is run. --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 4 ++-- MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 6 ++++-- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index add2a09e3..0dd33d021 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -24,6 +24,7 @@ Released TBD - Support separate depth and stencil attachments during dynamic rendering. - Deprecate the obsolete and non-standard `VK_MVK_moltenvk` extension. - Fix memory leak when waiting on timeline semaphores. +- Fix race condition when updating values in `VkPastPresentationTimingGOOGLE`. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index fadc2504f..db83c323c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -449,7 +449,7 @@ class MVKPresentableSwapchainImage : public MVKSwapchainImage { #pragma mark Metal /** Presents the contained drawable to the OS. */ - void presentCAMetalDrawable(id mtlCmdBuff, MVKImagePresentInfo& presentInfo); + void presentCAMetalDrawable(id mtlCmdBuff, MVKImagePresentInfo presentInfo); #pragma mark Construction @@ -463,7 +463,7 @@ class MVKPresentableSwapchainImage : public MVKSwapchainImage { friend MVKSwapchain; id getCAMetalDrawable() override; - void addPresentedHandler(id mtlDrawable, MVKImagePresentInfo& presentInfo); + void addPresentedHandler(id mtlDrawable, MVKImagePresentInfo presentInfo); void releaseMetalDrawable(); MVKSwapchainImageAvailability getAvailability(); void makeAvailable(const MVKSwapchainSignaler& signaler); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index a71d5edac..b8cfc68e8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1294,8 +1294,9 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { } // 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. void MVKPresentableSwapchainImage::presentCAMetalDrawable(id mtlCmdBuff, - MVKImagePresentInfo& presentInfo) { + MVKImagePresentInfo presentInfo) { lock_guard lock(_availabilityLock); _swapchain->willPresentSurface(getMTLTexture(0), mtlCmdBuff); @@ -1357,8 +1358,9 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { signalPresentationSemaphore(signaler, mtlCmdBuff); } +// Pass MVKImagePresentInfo by value because it may not exist when the callback runs. void MVKPresentableSwapchainImage::addPresentedHandler(id mtlDrawable, - MVKImagePresentInfo& presentInfo) { + MVKImagePresentInfo presentInfo) { #if !MVK_OS_SIMULATOR if ([mtlDrawable respondsToSelector: @selector(addPresentedHandler:)]) { retain(); // Ensure this image is not destroyed while awaiting presentation diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h index 47a26d2a7..95bcb1377 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h @@ -121,7 +121,7 @@ class MVKSwapchain : public MVKVulkanAPIDeviceObject { void willPresentSurface(id mtlTexture, id mtlCmdBuff); void renderWatermark(id mtlTexture, id mtlCmdBuff); void markFrameInterval(); - void recordPresentTime(MVKImagePresentInfo& presentInfo, uint64_t actualPresentTime = 0); + void recordPresentTime(const MVKImagePresentInfo& presentInfo, uint64_t actualPresentTime = 0); CAMetalLayer* _mtlLayer = nil; MVKWatermark* _licenseWatermark = nullptr; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 53aba660a..2f4c1d186 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -557,7 +557,7 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin return res; } -void MVKSwapchain::recordPresentTime(MVKImagePresentInfo& presentInfo, uint64_t actualPresentTime) { +void MVKSwapchain::recordPresentTime(const MVKImagePresentInfo& presentInfo, uint64_t actualPresentTime) { std::lock_guard lock(_presentHistoryLock); if (_presentHistoryCount < kMaxPresentationHistory) { _presentHistoryCount++; From ab5429b18cc2f82139224689b5858fa38959f9a4 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 8 May 2023 18:14:22 -0400 Subject: [PATCH 16/74] GitHub CI improvements. - Build one universal build, instead of per-platform. - Upload this single build artifact to GitHub. - Upgrade to v3 of action dependencies to remove Node.js deprecation warnings. - Avoid use of deprecated set-output GitHub action command. - Use macOS 13 and Xcode 14.3. - README.md document access to binary artifacts. --- .github/workflows/CI.yml | 20 ++++----- Docs/Whats_New.md | 1 + README.md | 87 +++++++++++++++++++++++----------------- 3 files changed, 61 insertions(+), 47 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index cb7921959..37e6b807f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,9 +15,9 @@ jobs: build: strategy: matrix: - xcode: [ "14.2" ] - platform: [ "macos", "maccat", "ios", "tvos" ] - os: [ "macos-latest" ] + xcode: [ "14.3" ] + platform: [ "all" ] + os: [ "macos-13" ] upload_artifacts: [ true ] # additional specific configurations include: @@ -41,7 +41,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Select Xcode version run: sudo xcode-select -switch "${XCODE_DEV_PATH}" @@ -54,12 +54,12 @@ jobs: echo "${XCODE_VERSION}" XCODE_VERSION="$(echo "${XCODE_VERSION}" | tr '\t\r\n ' '_')" echo "${XCODE_VERSION}" - echo "::set-output name=XCODE_VERSION::${XCODE_VERSION}" + echo "XCODE_VERSION=${XCODE_VERSION}" >> $GITHUB_OUTPUT - name: Cache Dependencies id: cache-dependencies if: success() && !(github.event_name == 'push' && contains(github.ref, 'refs/tags/')) # never cache dependencies for pushed tags - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | External/build @@ -94,11 +94,11 @@ jobs: - name: Tar Artifacts if: success() && matrix.upload_artifacts == true # See: https://github.com/actions/upload-artifact#maintaining-file-permissions-and-case-sensitive-files - run: tar -cvf "${{ matrix.platform }}.tar" Package/Release/ + run: tar -C Package -s/Release/MoltenVK/ -cvf "MoltenVK.tar" Release/ - name: Upload Artifacts if: success() && matrix.upload_artifacts == true - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: ${{ matrix.platform }} - path: "${{ matrix.platform }}.tar" + name: "MoltenVK" + path: "MoltenVK.tar" diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 0dd33d021..76f3b586e 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -31,6 +31,7 @@ Released TBD disable recent fixes to handling LOD for arrayed depth images in shaders, on Apple Silicon, when those fixes cause regression in rendering behavior. - For correctness, set `VkPhysicalDeviceLimits::lineWidthGranularity` to `1`. +- Modify GitHub CI to build and create a single universal binary artifact. diff --git a/README.md b/README.md index e55b96e0a..8349a8caa 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,10 @@ Copyright (c) 2015-2023 [The Brenwill Workshop Ltd.](http://www.brenwill.com) Table of Contents ----------------- -- [Developing Vulkan Applications on *macOS, iOS, and tvOS*](#developing_vulkan) - [Introduction to **MoltenVK**](#intro) +- [Developing Vulkan Applications on *macOS, iOS, and tvOS*](#developing_vulkan) + - [Using the *Vulkan SDK*](#sdk) + - [Using MoltenVK Directly](#download) - [Fetching **MoltenVK** Source Code](#install) - [Building **MoltenVK**](#building) - [Running **MoltenVK** Demo Applications](#demos) @@ -30,41 +32,6 @@ Table of Contents - -Developing Vulkan Applications for *macOS, iOS, and tvOS* ---------------------------------------------------------- - -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 -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*. -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)* -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 -`VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` flag. - -If you are developing a *Vulkan* application for *iOS* or *tvOS*, or are developing a *Vulkan* -application for *macOS* and want to use a different version of the **MoltenVK** runtime library -provided in the *macOS Vulkan SDK*, you can use this document to learn how to build a **MoltenVK** -runtime library from 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. - - - Introduction to MoltenVK ------------------------ @@ -99,6 +66,52 @@ The **MoltenVK** runtime package contains two products: + +Developing *Vulkan* Applications for *macOS, iOS, and tvOS* +--------------------------------------------------------- + + +### Using the *Vulkan SDK* + +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 +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*. +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)* +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 +`VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` flag. + + +### Using MoltenVK Directly + +If you are developing a *Vulkan* application for *iOS* or *tvOS*, 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. + +Finally, if you want a customized build of **MoltenVK**, you can follow the [instructions below](#install) +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. + + + Fetching **MoltenVK** Source Code --------------------------------- @@ -293,7 +306,7 @@ or it can be included in any of the `make` build commands. For example: or make macos MVK_HIDE_VULKAN_SYMBOLS=1 - + ...etc. From f19ac2c03da2d075a581745b9d06602c7f17d82e Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Tue, 9 May 2023 18:40:14 -0700 Subject: [PATCH 17/74] Add GitHub Actions workflow for automatically creating releases. --- .github/workflows/CI.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 37e6b807f..ae188be67 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -102,3 +102,25 @@ jobs: with: name: "MoltenVK" path: "MoltenVK.tar" + + release: + name: 'Release' + + needs: [build] + + runs-on: ubuntu-latest + + if: ${{ startsWith(github.ref, 'refs/tags/') }} + + permissions: + contents: write + + steps: + - name: Download Artifacts + uses: actions/download-artifact@v3 + + - name: Create Release + uses: ncipollo/release-action@v1 + with: + artifacts: "MoltenVK/*" + artifactErrorsFailBuild: true From 3247bd465d12c502e262ead8f97733210767cd0e Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 10 May 2023 16:46:41 -0400 Subject: [PATCH 18/74] GitHub CI streamline uploaded artifact sizes. - Reinstate per-platform upload artifacts. - Don't upload shader converter binaries. --- .github/workflows/CI.yml | 11 +++++++---- Docs/Whats_New.md | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ae188be67..5102796e3 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: xcode: [ "14.3" ] - platform: [ "all" ] + platform: [ "all", "macos", "ios" ] os: [ "macos-13" ] upload_artifacts: [ true ] # additional specific configurations @@ -94,14 +94,17 @@ jobs: - name: Tar Artifacts if: success() && matrix.upload_artifacts == true # See: https://github.com/actions/upload-artifact#maintaining-file-permissions-and-case-sensitive-files - run: tar -C Package -s/Release/MoltenVK/ -cvf "MoltenVK.tar" Release/ + # To reduce artifact size, don't include any stand-alone shader converter binaries. + run: | + rm -rf Package/Release/MoltenVKShaderConverter + tar -C Package -s/Release/MoltenVK/ -cvf "MoltenVK-${{ matrix.platform }}.tar" Release/ - name: Upload Artifacts if: success() && matrix.upload_artifacts == true uses: actions/upload-artifact@v3 with: - name: "MoltenVK" - path: "MoltenVK.tar" + name: "MoltenVK-${{ matrix.platform }}" + path: "MoltenVK-${{ matrix.platform }}.tar" release: name: 'Release' diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 76f3b586e..947cd308f 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -31,7 +31,7 @@ Released TBD disable recent fixes to handling LOD for arrayed depth images in shaders, on Apple Silicon, when those fixes cause regression in rendering behavior. - For correctness, set `VkPhysicalDeviceLimits::lineWidthGranularity` to `1`. -- Modify GitHub CI to build and create a single universal binary artifact. +- Improve GitHub CI production of binary artifacts on submission and release. From 0618c43070fca5582eeb562058d9373fedc35389 Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Wed, 10 May 2023 23:18:05 -0700 Subject: [PATCH 19/74] Update release action artifact glob. --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 5102796e3..95a074098 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -125,5 +125,5 @@ jobs: - name: Create Release uses: ncipollo/release-action@v1 with: - artifacts: "MoltenVK/*" + artifacts: "MoltenVK*/*" artifactErrorsFailBuild: true From 9c72022ac3ec923bdda0d92e85a2beca688ed52a Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Fri, 12 May 2023 10:11:11 -0700 Subject: [PATCH 20/74] Make the GitHub Actions release workflow more lenient. --- .github/workflows/CI.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 95a074098..2b59eab01 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -125,5 +125,15 @@ jobs: - name: Create Release uses: ncipollo/release-action@v1 with: + # Allow updating existing releases if the workflow is triggered by release creation or re-run. + allowUpdates: true + # When the release is updated, delete the existing artifacts for replacement. + removeArtifacts: true + # If a release is being replaced, omit updating the name and body. + # Allows for creating a release and filling these in before the workflow runs. + # Then, the workflow will populate the release with the artifacts. + omitNameDuringUpdate: true + omitBodyDuringUpdate: true + # Upload all MoltenVK CI artifacts as release assets. artifacts: "MoltenVK*/*" artifactErrorsFailBuild: true From 1b6750bef837377ce10f6d9cb19202c715d1d724 Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Wed, 10 May 2023 14:48:31 -0500 Subject: [PATCH 21/74] Respect the bind point supplied to vkCmdBindDescriptorSets --- MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h | 10 ++ MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm | 120 ++++++------------ .../MoltenVK/GPUObjects/MVKDescriptorSet.h | 5 + .../MoltenVK/GPUObjects/MVKDescriptorSet.mm | 10 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 1 + MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 3 +- 7 files changed, 64 insertions(+), 87 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm index d68d4f81c..3efcab53c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm @@ -393,7 +393,7 @@ } void MVKCmdPushDescriptorSet::encode(MVKCommandEncoder* cmdEncoder) { - _pipelineLayout->pushDescriptorSet(cmdEncoder, _descriptorWrites.contents(), _set); + _pipelineLayout->pushDescriptorSet(cmdEncoder, _pipelineBindPoint, _descriptorWrites.contents(), _set); } MVKCmdPushDescriptorSet::~MVKCmdPushDescriptorSet() { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h index 229b65dc8..d3851e6a9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h @@ -120,6 +120,7 @@ class MVKDescriptorSetLayoutBinding : public MVKBaseDeviceObject { /** Encodes the descriptors in the descriptor set that are specified by this layout, */ void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSet* descSet, MVKShaderResourceBinding& dslMTLRezIdxOffsets, MVKArrayRef dynamicOffsets, @@ -127,6 +128,7 @@ class MVKDescriptorSetLayoutBinding : public MVKBaseDeviceObject { /** Encodes this binding layout and the specified descriptor on the specified command encoder immediately. */ void push(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, uint32_t& dstArrayElement, uint32_t& descriptorCount, uint32_t& descriptorsPushed, @@ -207,6 +209,7 @@ class MVKDescriptor : public MVKBaseObject { /** Encodes this descriptor (based on its layout binding index) on the the command encoder. */ virtual void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -273,6 +276,7 @@ class MVKBufferDescriptor : public MVKDescriptor { public: void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -362,6 +366,7 @@ class MVKInlineUniformBlockDescriptor : public MVKDescriptor { VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT; } void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -411,6 +416,7 @@ class MVKImageDescriptor : public MVKDescriptor { public: void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -491,6 +497,7 @@ class MVKSamplerDescriptorMixin { protected: void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -538,6 +545,7 @@ class MVKSamplerDescriptor : public MVKDescriptor, public MVKSamplerDescriptorMi VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_SAMPLER; } void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -585,6 +593,7 @@ class MVKCombinedImageSamplerDescriptor : public MVKImageDescriptor, public MVKS VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; } void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -630,6 +639,7 @@ class MVKTexelBufferDescriptor : public MVKDescriptor { public: void bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm index c13296d20..a3f02ea89 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm @@ -20,6 +20,16 @@ #include "MVKDescriptorSet.h" #include "MVKBuffer.h" +#define BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bind, pipelineBindPoint, stage, ...) \ + do { \ + if ((stage) == kMVKShaderStageCompute) { \ + if ((cmdEncoder) && (pipelineBindPoint) == VK_PIPELINE_BIND_POINT_COMPUTE) \ + (cmdEncoder)->_computeResourcesState.bind(__VA_ARGS__); \ + } else { \ + if ((cmdEncoder) && (pipelineBindPoint) == VK_PIPELINE_BIND_POINT_GRAPHICS) \ + (cmdEncoder)->_graphicsResourcesState.bind(static_cast(stage), __VA_ARGS__); \ + } \ + } while (0) #pragma mark MVKShaderStageResourceBinding @@ -195,6 +205,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // A null cmdEncoder can be passed to perform a validation pass void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSet* descSet, MVKShaderResourceBinding& dslMTLRezIdxOffsets, MVKArrayRef dynamicOffsets, @@ -208,7 +219,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) { MVKDescriptor* mvkDesc = descSet->getDescriptor(getBinding(), descIdx); if (mvkDesc->getDescriptorType() == descType) { - mvkDesc->bind(cmdEncoder, this, descIdx, _applyToStage, mtlIdxs, dynamicOffsets, dynamicOffsetIndex); + mvkDesc->bind(cmdEncoder, pipelineBindPoint, this, descIdx, _applyToStage, mtlIdxs, dynamicOffsets, dynamicOffsetIndex); } } } @@ -220,6 +231,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // A null cmdEncoder can be passed to perform a validation pass void MVKDescriptorSetLayoutBinding::push(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, uint32_t& dstArrayElement, uint32_t& descriptorCount, uint32_t& descriptorsPushed, @@ -271,11 +283,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (_applyToStage[i]) { bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindBuffer, pipelineBindPoint, i, bb); } } break; @@ -289,11 +297,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (_applyToStage[i]) { bb.index = mtlIdxs.stages[i].bufferIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindBuffer, pipelineBindPoint, i, bb); } } break; @@ -318,18 +322,10 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (_applyToStage[i]) { tb.index = mtlIdxs.stages[i].textureIndex + rezIdx + planeIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindTexture, pipelineBindPoint, i, tb); if (_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindBuffer, pipelineBindPoint, i, bb); } } } @@ -351,18 +347,10 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (_applyToStage[i]) { tb.index = mtlIdxs.stages[i].textureIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindTexture, pipelineBindPoint, i, tb); if (_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindBuffer, pipelineBindPoint, i, bb); } } } @@ -381,11 +369,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (_applyToStage[i]) { sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindSamplerState, pipelineBindPoint, i, sb); } } break; @@ -410,13 +394,8 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s if (_applyToStage[i]) { tb.index = mtlIdxs.stages[i].textureIndex + rezIdx + planeIndex; sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindTexture, pipelineBindPoint, i, tb); + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindSamplerState, pipelineBindPoint, i, sb); } } } @@ -742,6 +721,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // A null cmdEncoder can be passed to perform a validation pass void MVKBufferDescriptor::bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -762,11 +742,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (stages[i]) { bb.index = mtlIndexes.stages[i].bufferIndex + elementIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindBuffer, pipelineBindPoint, i, bb); } } } @@ -834,6 +810,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // A null cmdEncoder can be passed to perform a validation pass void MVKInlineUniformBlockDescriptor::bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -850,11 +827,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (stages[i]) { bb.index = mtlIndexes.stages[i].bufferIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindBuffer, pipelineBindPoint, i, bb); } } } @@ -923,6 +896,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // A null cmdEncoder can be passed to perform a validation pass void MVKImageDescriptor::bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -952,18 +926,10 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (stages[i]) { tb.index = mtlIndexes.stages[i].textureIndex + elementIndex + planeIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindTexture, pipelineBindPoint, i, tb); if (descType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { bb.index = mtlIndexes.stages[i].bufferIndex + elementIndex + planeIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindBuffer, pipelineBindPoint, i, bb); } } } @@ -1048,6 +1014,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // Metal validation requires each sampler in an array of samplers to be populated, // even if not used, so populate a default if one hasn't been set. void MVKSamplerDescriptorMixin::bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -1065,11 +1032,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (stages[i]) { sb.index = mtlIndexes.stages[i].samplerIndex + elementIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindSamplerState, pipelineBindPoint, i, sb); } } } @@ -1136,13 +1099,14 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // A null cmdEncoder can be passed to perform a validation pass void MVKSamplerDescriptor::bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], MVKShaderResourceBinding& mtlIndexes, MVKArrayRef dynamicOffsets, uint32_t& dynamicOffsetIndex) { - MVKSamplerDescriptorMixin::bind(cmdEncoder, mvkDSLBind, elementIndex, stages, mtlIndexes, dynamicOffsets, dynamicOffsetIndex); + MVKSamplerDescriptorMixin::bind(cmdEncoder, pipelineBindPoint, mvkDSLBind, elementIndex, stages, mtlIndexes, dynamicOffsets, dynamicOffsetIndex); } void MVKSamplerDescriptor::encodeToMetalArgumentBuffer(MVKResourcesCommandEncoderState* rezEncState, @@ -1185,14 +1149,15 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // A null cmdEncoder can be passed to perform a validation pass void MVKCombinedImageSamplerDescriptor::bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], MVKShaderResourceBinding& mtlIndexes, MVKArrayRef dynamicOffsets, uint32_t& dynamicOffsetIndex) { - MVKImageDescriptor::bind(cmdEncoder, mvkDSLBind, elementIndex, stages, mtlIndexes, dynamicOffsets, dynamicOffsetIndex); - MVKSamplerDescriptorMixin::bind(cmdEncoder, mvkDSLBind, elementIndex, stages, mtlIndexes, dynamicOffsets, dynamicOffsetIndex); + MVKImageDescriptor::bind(cmdEncoder, pipelineBindPoint, mvkDSLBind, elementIndex, stages, mtlIndexes, dynamicOffsets, dynamicOffsetIndex); + MVKSamplerDescriptorMixin::bind(cmdEncoder, pipelineBindPoint, mvkDSLBind, elementIndex, stages, mtlIndexes, dynamicOffsets, dynamicOffsetIndex); } void MVKCombinedImageSamplerDescriptor::encodeToMetalArgumentBuffer(MVKResourcesCommandEncoderState* rezEncState, @@ -1238,6 +1203,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s // A null cmdEncoder can be passed to perform a validation pass void MVKTexelBufferDescriptor::bind(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKDescriptorSetLayoutBinding* mvkDSLBind, uint32_t elementIndex, bool stages[], @@ -1259,18 +1225,10 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) { if (stages[i]) { tb.index = mtlIndexes.stages[i].textureIndex + elementIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindTexture, pipelineBindPoint, i, tb); if (descType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { bb.index = mtlIndexes.stages[i].bufferIndex + elementIndex; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } + BIND_GRAPHICS_OR_COMPUTE(cmdEncoder, bindBuffer, pipelineBindPoint, i, bb); } } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h index 8964c9019..552ca1728 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h @@ -81,6 +81,7 @@ class MVKDescriptorSetLayout : public MVKVulkanAPIDeviceObject { /** Encodes this descriptor set layout and the specified descriptor updates on the specified command encoder immediately. */ void pushDescriptorSet(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKArrayRef descriptorWrites, MVKShaderResourceBinding& dslMTLRezIdxOffsets); @@ -338,6 +339,9 @@ class MVKDescriptorUpdateTemplate : public MVKVulkanAPIDeviceObject { /** Get the type of this template. */ VkDescriptorUpdateTemplateType getType() const; + /** Get the bind point of this template */ + VkPipelineBindPoint getBindPoint() const { return _pipelineBindPoint; } + /** Constructs an instance for the specified device. */ MVKDescriptorUpdateTemplate(MVKDevice* device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo); @@ -347,6 +351,7 @@ class MVKDescriptorUpdateTemplate : public MVKVulkanAPIDeviceObject { protected: void propagateDebugName() override {} + VkPipelineBindPoint _pipelineBindPoint; VkDescriptorUpdateTemplateType _type; MVKSmallVector _entries; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm index 5ebeed4b9..679e4005f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm @@ -43,7 +43,7 @@ dynamicOffsets, dynamicOffsetIndex); } if ( !isUsingMetalArgumentBuffers() ) { for (auto& dslBind : _bindings) { - dslBind.bind(cmdEncoder, descSet, dslMTLRezIdxOffsets, dynamicOffsets, dynamicOffsetIndex); + dslBind.bind(cmdEncoder, pipelineBindPoint, descSet, dslMTLRezIdxOffsets, dynamicOffsets, dynamicOffsetIndex); } } } @@ -91,6 +91,7 @@ // A null cmdEncoder can be passed to perform a validation pass void MVKDescriptorSetLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKArrayRef descriptorWrites, MVKShaderResourceBinding& dslMTLRezIdxOffsets) { @@ -127,7 +128,7 @@ pBufferInfo, pTexelBufferView, pInlineUniformBlock, stride); uint32_t descriptorsPushed = 0; uint32_t bindIdx = _bindingToIndex[dstBinding]; - _bindings[bindIdx].push(cmdEncoder, dstArrayElement, descriptorCount, + _bindings[bindIdx].push(cmdEncoder, pipelineBindPoint, dstArrayElement, descriptorCount, descriptorsPushed, descWrite.descriptorType, stride, pData, dslMTLRezIdxOffsets); pBufferInfo += descriptorsPushed; @@ -148,6 +149,7 @@ return; if (!cmdEncoder) { clearConfigurationResult(); } + VkPipelineBindPoint bindPoint = descUpdateTemplate->getBindPoint(); for (uint32_t i = 0; i < descUpdateTemplate->getNumberOfEntries(); i++) { const VkDescriptorUpdateTemplateEntry* pEntry = descUpdateTemplate->getEntry(i); uint32_t dstBinding = pEntry->dstBinding; @@ -161,7 +163,7 @@ if (!_bindingToIndex.count(dstBinding)) continue; uint32_t descriptorsPushed = 0; uint32_t bindIdx = _bindingToIndex[dstBinding]; - _bindings[bindIdx].push(cmdEncoder, dstArrayElement, descriptorCount, + _bindings[bindIdx].push(cmdEncoder, bindPoint, dstArrayElement, descriptorCount, descriptorsPushed, pEntry->descriptorType, pEntry->stride, pCurData, dslMTLRezIdxOffsets); pCurData = (const char*)pCurData + pEntry->stride * descriptorsPushed; @@ -876,7 +878,7 @@ MVKDescriptorUpdateTemplate::MVKDescriptorUpdateTemplate(MVKDevice* device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo) : - MVKVulkanAPIDeviceObject(device), _type(pCreateInfo->templateType) { + MVKVulkanAPIDeviceObject(device), _type(pCreateInfo->templateType), _pipelineBindPoint(pCreateInfo->pipelineBindPoint) { for (uint32_t i = 0; i < pCreateInfo->descriptorUpdateEntryCount; i++) _entries.push_back(pCreateInfo->pDescriptorUpdateEntries[i]); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index efb7c4926..0d763e266 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -63,6 +63,7 @@ class MVKPipelineLayout : public MVKVulkanAPIDeviceObject { /** Updates a descriptor set in a command encoder. */ void pushDescriptorSet(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKArrayRef descriptorWrites, uint32_t set); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 19d0d06c1..fb2880e7a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -64,11 +64,12 @@ // A null cmdEncoder can be passed to perform a validation pass void MVKPipelineLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder, + VkPipelineBindPoint pipelineBindPoint, MVKArrayRef descriptorWrites, uint32_t set) { if (!cmdEncoder) { clearConfigurationResult(); } MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[set]; - dsl->pushDescriptorSet(cmdEncoder, descriptorWrites, _dslMTLResourceIndexOffsets[set]); + dsl->pushDescriptorSet(cmdEncoder, pipelineBindPoint, descriptorWrites, _dslMTLResourceIndexOffsets[set]); if (!cmdEncoder) { setConfigurationResult(dsl->getConfigurationResult()); } } From 47ce47ad4c391ebd5900b00344c97c508bcb9828 Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Fri, 12 May 2023 14:10:14 -0500 Subject: [PATCH 22/74] Fix reorder-ctor warning --- MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm index 679e4005f..1406ab179 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm @@ -878,7 +878,7 @@ MVKDescriptorUpdateTemplate::MVKDescriptorUpdateTemplate(MVKDevice* device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo) : - MVKVulkanAPIDeviceObject(device), _type(pCreateInfo->templateType), _pipelineBindPoint(pCreateInfo->pipelineBindPoint) { + MVKVulkanAPIDeviceObject(device), _pipelineBindPoint(pCreateInfo->pipelineBindPoint), _type(pCreateInfo->templateType) { for (uint32_t i = 0; i < pCreateInfo->descriptorUpdateEntryCount; i++) _entries.push_back(pCreateInfo->pDescriptorUpdateEntries[i]); From 0139b95849d3b0acfc33d2762e9b06b66f4c4a0d Mon Sep 17 00:00:00 2001 From: ChibiDenDen Date: Fri, 12 May 2023 23:41:46 +0300 Subject: [PATCH 23/74] Fix simulator feature discovery Fix depth clamp and texture swizzle feature discovery on simulator builds Both of these features are not supported by the iphone simulator and leads to crashes when used --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 2872db17e..8ad6fd876 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1802,7 +1802,11 @@ if ( mvkOSVersionIsAtLeast(13.0) ) { _metalFeatures.mslVersionEnum = MTLLanguageVersion2_2; _metalFeatures.placementHeaps = mvkConfig().useMTLHeap; +#if MVK_OS_SIMULATOR + _metalFeatures.nativeTextureSwizzle = false; +#else _metalFeatures.nativeTextureSwizzle = true; +#endif if (supportsMTLGPUFamily(Apple3)) { _metalFeatures.native3DCompressedTextures = true; } @@ -2196,9 +2200,13 @@ _features.dualSrcBlend = true; } +#if MVK_OS_SIMULATOR + _features.depthClamp = false; +#else if (supportsMTLFeatureSet(iOS_GPUFamily2_v4)) { _features.depthClamp = true; } +#endif if (supportsMTLFeatureSet(iOS_GPUFamily3_v2)) { _features.tessellationShader = true; From 4893f78b29f838f8badff672255f3837fe1ff682 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 15 May 2023 14:32:22 -0400 Subject: [PATCH 24/74] Identify each unsupported device feature flag that the app attempts to be enable. - Make MVKDevice::enableFeatures() functions into templates to pass struct type. - Add mvkGetAddressOfFirstMember() to retrieve the address of the first member of a struct, taking into consideration whether the struct has a Vulkan pNext member. - Add mvk::getTypeName() and mvk::getOrdinalSuffix() string functions. --- Common/MVKStrings.h | 22 +++++ Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 4 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 105 +++++++++++++-------- MoltenVK/MoltenVK/Utility/MVKBaseObject.mm | 10 +- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 38 ++++++++ 6 files changed, 133 insertions(+), 47 deletions(-) diff --git a/Common/MVKStrings.h b/Common/MVKStrings.h index ec78d9ad7..d3ce5316a 100644 --- a/Common/MVKStrings.h +++ b/Common/MVKStrings.h @@ -21,6 +21,8 @@ #include #include +#include +#include namespace mvk { @@ -59,6 +61,26 @@ namespace mvk { return varName; } + /** Returns a string containing the ordinal suffix for a numeric value.*/ + inline const char* getOrdinalSuffix(int64_t val) { + static const char* suffixes[] = {"th", "st", "nd", "rd"}; + auto ord = val % 100; + if (ord > 10 && ord < 20) { return suffixes[0]; } // All teens end in th. + ord = ord % 10; + if (ord > 3) { return suffixes[0]; } // 4-9 end in th. + return suffixes[ord]; + } + + /** Returns the name of a C++ type. */ + template + inline std::string getTypeName(const T* pObj) { + int status; + char* demangledName = abi::__cxa_demangle(typeid(*pObj).name(), 0, 0, &status); + std::string tName = demangledName; + free(demangledName); + return tName; + } + #pragma mark - #pragma mark Streams diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 947cd308f..5e0c8460b 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -30,6 +30,7 @@ Released TBD - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively disable recent fixes to handling LOD for arrayed depth images in shaders, on Apple Silicon, when those fixes cause regression in rendering behavior. +- Identify each unsupported device feature flag that the app attempts to be enable. - For correctness, set `VkPhysicalDeviceLimits::lineWidthGranularity` to `1`. - Improve GitHub CI production of binary artifacts on submission and release. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index db484823a..e1f7e310d 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -886,8 +886,8 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { void initQueues(const VkDeviceCreateInfo* pCreateInfo); void reservePrivateData(const VkDeviceCreateInfo* pCreateInfo); void enableFeatures(const VkDeviceCreateInfo* pCreateInfo); - void enableFeatures(VkBaseInStructure* pEnabled, const VkBaseInStructure* pRequested, const VkBaseInStructure* pAvailable, uint32_t count); - void enableFeatures(VkBool32* pEnabledBools, const VkBool32* pRequestedBools, const VkBool32* pAvailableBools, uint32_t count); + template void enableFeatures(S* pEnabled, const S* pRequested, const S* pAvailable, uint32_t count); + template void enableFeatures(S* pRequested, VkBool32* pEnabledBools, const VkBool32* pRequestedBools, const VkBool32* pAvailableBools, uint32_t count); void enableExtensions(const VkDeviceCreateInfo* pCreateInfo); const char* getActivityPerformanceDescription(MVKPerformanceTracker& activity, MVKPerformanceStatistics& perfStats); void logActivityPerformance(MVKPerformanceTracker& activity, MVKPerformanceStatistics& perfStats, bool isInline = false); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 8ad6fd876..ba0c33103 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -32,6 +32,7 @@ #include "MVKCommandPool.h" #include "MVKFoundation.h" #include "MVKCodec.h" +#include "MVKStrings.h" #include #import "CAMetalLayer+MoltenVK.h" @@ -4590,7 +4591,8 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope //Enable device features based on requested and available features, // including extended features that are requested in the pNext chain. if (pCreateInfo->pEnabledFeatures) { - enableFeatures(&_enabledFeatures.robustBufferAccess, + enableFeatures(pCreateInfo->pEnabledFeatures, + &_enabledFeatures.robustBufferAccess, &pCreateInfo->pEnabledFeatures->robustBufferAccess, &pdFeats2.features.robustBufferAccess, 55); } @@ -4599,29 +4601,36 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope switch ((uint32_t)next->sType) { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: { auto* requestedFeatures = (VkPhysicalDeviceFeatures2*)next; - enableFeatures(&_enabledFeatures.robustBufferAccess, + enableFeatures(requestedFeatures, + &_enabledFeatures.robustBufferAccess, &requestedFeatures->features.robustBufferAccess, &pdFeats2.features.robustBufferAccess, 55); break; } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: { auto* requestedFeatures = (VkPhysicalDeviceVulkan11Features*)next; - enableFeatures(&_enabled16BitStorageFeatures.storageBuffer16BitAccess, + enableFeatures(requestedFeatures, + &_enabled16BitStorageFeatures.storageBuffer16BitAccess, &requestedFeatures->storageBuffer16BitAccess, &pd16BitStorageFeatures.storageBuffer16BitAccess, 4); - enableFeatures(&_enabledMultiviewFeatures.multiview, + enableFeatures(requestedFeatures, + &_enabledMultiviewFeatures.multiview, &requestedFeatures->multiview, &pdMultiviewFeatures.multiview, 3); - enableFeatures(&_enabledVariablePointerFeatures.variablePointersStorageBuffer, + enableFeatures(requestedFeatures, + &_enabledVariablePointerFeatures.variablePointersStorageBuffer, &requestedFeatures->variablePointersStorageBuffer, &pdVariablePointerFeatures.variablePointersStorageBuffer, 2); - enableFeatures(&_enabledProtectedMemoryFeatures.protectedMemory, + enableFeatures(requestedFeatures, + &_enabledProtectedMemoryFeatures.protectedMemory, &requestedFeatures->protectedMemory, &pdProtectedMemoryFeatures.protectedMemory, 1); - enableFeatures(&_enabledSamplerYcbcrConversionFeatures.samplerYcbcrConversion, + enableFeatures(requestedFeatures, + &_enabledSamplerYcbcrConversionFeatures.samplerYcbcrConversion, &requestedFeatures->samplerYcbcrConversion, &pdSamplerYcbcrConversionFeatures.samplerYcbcrConversion, 1); - enableFeatures(&_enabledShaderDrawParametersFeatures.shaderDrawParameters, + enableFeatures(requestedFeatures, + &_enabledShaderDrawParametersFeatures.shaderDrawParameters, &requestedFeatures->shaderDrawParameters, &pdShaderDrawParametersFeatures.shaderDrawParameters, 1); break; @@ -4629,55 +4638,72 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: { auto& pdvulkan12FeaturesNoExt = _physicalDevice->_vulkan12FeaturesNoExt; auto* requestedFeatures = (VkPhysicalDeviceVulkan12Features*)next; - enableFeatures(&_enabledVulkan12FeaturesNoExt.samplerMirrorClampToEdge, + enableFeatures(requestedFeatures, + &_enabledVulkan12FeaturesNoExt.samplerMirrorClampToEdge, &requestedFeatures->samplerMirrorClampToEdge, &pdvulkan12FeaturesNoExt.samplerMirrorClampToEdge, 2); - enableFeatures(&_enabled8BitStorageFeatures.storageBuffer8BitAccess, + enableFeatures(requestedFeatures, + &_enabled8BitStorageFeatures.storageBuffer8BitAccess, &requestedFeatures->storageBuffer8BitAccess, &pd8BitStorageFeatures.storageBuffer8BitAccess, 3); - enableFeatures(&_enabledShaderAtomicInt64Features.shaderBufferInt64Atomics, + enableFeatures(requestedFeatures, + &_enabledShaderAtomicInt64Features.shaderBufferInt64Atomics, &requestedFeatures->shaderBufferInt64Atomics, &pdShaderAtomicInt64Features.shaderBufferInt64Atomics, 2); - enableFeatures(&_enabledShaderFloat16Int8Features.shaderFloat16, + enableFeatures(requestedFeatures, + &_enabledShaderFloat16Int8Features.shaderFloat16, &requestedFeatures->shaderFloat16, &pdShaderFloat16Int8Features.shaderFloat16, 2); - enableFeatures(&_enabledVulkan12FeaturesNoExt.descriptorIndexing, + enableFeatures(requestedFeatures, + &_enabledVulkan12FeaturesNoExt.descriptorIndexing, &requestedFeatures->descriptorIndexing, &pdvulkan12FeaturesNoExt.descriptorIndexing, 1); - enableFeatures(&_enabledDescriptorIndexingFeatures.shaderInputAttachmentArrayDynamicIndexing, + enableFeatures(requestedFeatures, + &_enabledDescriptorIndexingFeatures.shaderInputAttachmentArrayDynamicIndexing, &requestedFeatures->shaderInputAttachmentArrayDynamicIndexing, &pdDescriptorIndexingFeatures.shaderInputAttachmentArrayDynamicIndexing, 20); - enableFeatures(&_enabledVulkan12FeaturesNoExt.samplerFilterMinmax, + enableFeatures(requestedFeatures, + &_enabledVulkan12FeaturesNoExt.samplerFilterMinmax, &requestedFeatures->samplerFilterMinmax, &pdvulkan12FeaturesNoExt.samplerFilterMinmax, 1); - enableFeatures(&_enabledScalarBlockLayoutFeatures.scalarBlockLayout, + enableFeatures(requestedFeatures, + &_enabledScalarBlockLayoutFeatures.scalarBlockLayout, &requestedFeatures->scalarBlockLayout, &pdScalarBlockLayoutFeatures.scalarBlockLayout, 1); - enableFeatures(&_enabledImagelessFramebufferFeatures.imagelessFramebuffer, + enableFeatures(requestedFeatures, + &_enabledImagelessFramebufferFeatures.imagelessFramebuffer, &requestedFeatures->imagelessFramebuffer, &pdImagelessFramebufferFeatures.imagelessFramebuffer, 1); - enableFeatures(&_enabledUniformBufferStandardLayoutFeatures.uniformBufferStandardLayout, + enableFeatures(requestedFeatures, + &_enabledUniformBufferStandardLayoutFeatures.uniformBufferStandardLayout, &requestedFeatures->uniformBufferStandardLayout, &pdUniformBufferStandardLayoutFeatures.uniformBufferStandardLayout, 1); - enableFeatures(&_enabledShaderSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes, + enableFeatures(requestedFeatures, + &_enabledShaderSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes, &requestedFeatures->shaderSubgroupExtendedTypes, &pdShaderSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes, 1); - enableFeatures(&_enabledSeparateDepthStencilLayoutsFeatures.separateDepthStencilLayouts, + enableFeatures(requestedFeatures, + &_enabledSeparateDepthStencilLayoutsFeatures.separateDepthStencilLayouts, &requestedFeatures->separateDepthStencilLayouts, &pdSeparateDepthStencilLayoutsFeatures.separateDepthStencilLayouts, 1); - enableFeatures(&_enabledHostQueryResetFeatures.hostQueryReset, + enableFeatures(requestedFeatures, + &_enabledHostQueryResetFeatures.hostQueryReset, &requestedFeatures->hostQueryReset, &pdHostQueryResetFeatures.hostQueryReset, 1); - enableFeatures(&_enabledTimelineSemaphoreFeatures.timelineSemaphore, + enableFeatures(requestedFeatures, + &_enabledTimelineSemaphoreFeatures.timelineSemaphore, &requestedFeatures->timelineSemaphore, &pdTimelineSemaphoreFeatures.timelineSemaphore, 1); - enableFeatures(&_enabledBufferDeviceAddressFeatures.bufferDeviceAddress, + enableFeatures(requestedFeatures, + &_enabledBufferDeviceAddressFeatures.bufferDeviceAddress, &requestedFeatures->bufferDeviceAddress, &pdBufferDeviceAddressFeatures.bufferDeviceAddress, 3); - enableFeatures(&_enabledVulkanMemoryModelFeatures.vulkanMemoryModel, + enableFeatures(requestedFeatures, + &_enabledVulkanMemoryModelFeatures.vulkanMemoryModel, &requestedFeatures->vulkanMemoryModel, &pdVulkanMemoryModelFeatures.vulkanMemoryModel, 3); - enableFeatures(&_enabledVulkan12FeaturesNoExt.shaderOutputViewportIndex, + enableFeatures(requestedFeatures, + &_enabledVulkan12FeaturesNoExt.shaderOutputViewportIndex, &requestedFeatures->shaderOutputViewportIndex, &pdvulkan12FeaturesNoExt.shaderOutputViewportIndex, 3); break; @@ -4685,17 +4711,17 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope #define MVK_DEVICE_FEATURE(structName, enumName, flagCount) \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##enumName##_FEATURES: { \ - enableFeatures((VkBaseInStructure*)&_enabled##structName##Features, \ - next, \ - (VkBaseInStructure*)&pd##structName##Features, \ + enableFeatures(&_enabled##structName##Features, \ + (VkPhysicalDevice##structName##Features*)next, \ + &pd##structName##Features, \ flagCount); \ break; \ } #define MVK_DEVICE_FEATURE_EXTN(structName, enumName, extnSfx, flagCount) \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##enumName##_FEATURES_##extnSfx: { \ - enableFeatures((VkBaseInStructure*)&_enabled##structName##Features, \ - next, \ - (VkBaseInStructure*)&pd##structName##Features, \ + enableFeatures(&_enabled##structName##Features, \ + (VkPhysicalDevice##structName##Features##extnSfx*)next, \ + &pd##structName##Features, \ flagCount); \ break; \ } @@ -4707,18 +4733,23 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope } } -void MVKDevice::enableFeatures(VkBaseInStructure* pEnabled, const VkBaseInStructure* pRequested, const VkBaseInStructure* pAvailable, uint32_t count) { - enableFeatures((VkBool32*)(&(pEnabled->pNext) + 1), - (VkBool32*)(&(pRequested->pNext) + 1), - (VkBool32*)(&(pAvailable->pNext) + 1), +template +void MVKDevice::enableFeatures(S* pEnabled, const S* pRequested, const S* pAvailable, uint32_t count) { + enableFeatures(pRequested, + (VkBool32*)mvkGetAddressOfFirstMember(pEnabled), + (VkBool32*)mvkGetAddressOfFirstMember(pRequested), + (VkBool32*)mvkGetAddressOfFirstMember(pAvailable), count); } -void MVKDevice::enableFeatures(VkBool32* pEnabledBools, const VkBool32* pRequestedBools, const VkBool32* pAvailableBools, uint32_t count) { +template +void MVKDevice::enableFeatures(S* pRequested, VkBool32* pEnabledBools, const VkBool32* pRequestedBools, const VkBool32* pAvailableBools, uint32_t count) { for (uint32_t i = 0; i < count; i++) { pEnabledBools[i] = pRequestedBools[i] && pAvailableBools[i]; if (pRequestedBools[i] && !pAvailableBools[i]) { - setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateDevice(): Requested feature is not available on this device.")); + uintptr_t mbrOffset = (uintptr_t)&pRequestedBools[i] - (uintptr_t)mvkGetAddressOfFirstMember(pRequested); + size_t mbrIdxOrd = (mbrOffset / sizeof(VkBool32)) + 1; + setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateDevice(): Requested physical device feature specified by the %zu%s flag in %s is not available on this device.", mbrIdxOrd, mvk::getOrdinalSuffix(mbrIdxOrd), mvk::getTypeName(pRequested).c_str())); } } } diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm index d2dc3c91f..427c32278 100644 --- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm +++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm @@ -21,7 +21,7 @@ #include "MVKInstance.h" #include "MVKFoundation.h" #include "MVKOSExtensions.h" -#include +#include "MVKStrings.h" using namespace std; @@ -44,13 +44,7 @@ #pragma mark - #pragma mark MVKBaseObject -string MVKBaseObject::getClassName() { - int status; - char* demangled = abi::__cxa_demangle(typeid(*this).name(), 0, 0, &status); - string clzName = demangled; - free(demangled); - return clzName; -} +string MVKBaseObject::getClassName() { return mvk::getTypeName(this); } void MVKBaseObject::reportMessage(MVKConfigLogLevel logLevel, const char* format, ...) { va_list args; diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index 7c4af3da4..269cc9f4c 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -217,6 +217,44 @@ static constexpr uint64_t mvkAlignByteCount(uint64_t byteCount, uint64_t byteAli return mvkAlignByteRef(byteCount, byteAlignment, alignDown); } +/** + * Compile time indication if the struct contains a specific member. + * + * If S::mbr is well-formed because the struct contains that member, the decltype() and + * comma operator together trigger a true_type, otherwise it falls back to a false_type. + * + * Credit to: https://fekir.info/post/detect-member-variables/ + */ +#define mvk_define_has_member(mbr) \ + template struct mvk_has_##mbr : std::false_type {}; \ + template struct mvk_has_##mbr : std::true_type {}; + +mvk_define_has_member(pNext); // Defines the mvk_has_pNext() function. + +/** Returns the address of the first member of a structure, which is just the address of the structure. */ +template +void* mvkGetAddressOfFirstMember(const S* pStruct, std::false_type){ + return (void*)pStruct; +} + +/** + * Returns the address of the first member of a Vulkan structure containing a pNext member. + * The first member is the one after the pNext member. + */ +template +void* mvkGetAddressOfFirstMember(const S* pStruct, std::true_type){ + return (void*)(&(pStruct->pNext) + 1); +} + +/** + * Returns the address of the first member of a structure. If the structure is a Vulkan + * structure containing a pNext member, the first member is the one after the pNext member. + */ +template +void* mvkGetAddressOfFirstMember(const S* pStruct){ + return mvkGetAddressOfFirstMember(pStruct, mvk_has_pNext{}); +} + /** * Reverses the order of the rows in the specified data block. * The transformation is performed in-place. From 65ce195a6f7f4ad5ae7e9a20538e79af22b8de20 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 15 May 2023 18:47:22 -0400 Subject: [PATCH 25/74] Ensure swapchain image presented time is always populated when requested. If Metal reports zero presentedTime, and desired presentation time has not been set by app, use the current time. --- Docs/Whats_New.md | 3 ++- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 5e0c8460b..e45bb308a 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -24,7 +24,8 @@ Released TBD - Support separate depth and stencil attachments during dynamic rendering. - Deprecate the obsolete and non-standard `VK_MVK_moltenvk` extension. - Fix memory leak when waiting on timeline semaphores. -- Fix race condition when updating values in `VkPastPresentationTimingGOOGLE`. +- Fix race condition when updating values in `VkPastPresentationTimingGOOGLE`, + and ensure swapchain image presented time is always populated when requested. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 2f4c1d186..5ff5d0cfb 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -565,8 +565,11 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin _presentHistoryHeadIndex = (_presentHistoryHeadIndex + 1) % kMaxPresentationHistory; } - // If actual time not supplied, use desired time instead + // 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; From d29092ab7819a17f0f7525d653a03d66120dd235 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 16 May 2023 17:26:26 -0400 Subject: [PATCH 26/74] Do not fail on request for timestamp query pool that is too large. - Report error, but do not fail on request for timestamp query pool that is too large for MTLCounterSampleBuffer. - Change reported error to VK_ERROR_OUT_OF_DEVICE_MEMORY and clarify text of error reported when timestamp query pool is too large. - Clarify error reported for occlusion query pool errors (unrelated). --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index e45bb308a..e9b43973c 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -26,6 +26,7 @@ Released TBD - Fix memory leak when waiting on timeline semaphores. - Fix race condition when updating values in `VkPastPresentationTimingGOOGLE`, and ensure swapchain image presented time is always populated when requested. +- Report error, but do not fail on request for timestamp query pool that is too large for `MTLCounterSampleBuffer`. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm index 1f6470063..b3b139a6b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm @@ -316,7 +316,9 @@ VkDeviceSize newBuffLen = min(reqBuffLen, maxBuffLen); if (reqBuffLen > maxBuffLen) { - reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "vkCreateQueryPool(): Each query pool can support a maximum of %d queries.", uint32_t(newBuffLen / kMVKQuerySlotSizeInBytes)); + reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, + "vkCreateQueryPool(): Each occlusion query pool can support a maximum of %d queries.", + uint32_t(newBuffLen / kMVKQuerySlotSizeInBytes)); } NSUInteger mtlBuffLen = mvkAlignByteCount(newBuffLen, _device->_pMetalFeatures->mtlBufferAlignment); @@ -356,9 +358,9 @@ NSError* err = nil; _mtlCounterBuffer = [getMTLDevice() newCounterSampleBufferWithDescriptor: tsDesc error: &err]; if (err) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, - "Could not create MTLCounterSampleBuffer for query pool of type %s. Reverting to emulated behavior. (Error code %li): %s", - queryTypeName, (long)err.code, err.localizedDescription.UTF8String)); + reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, + "Could not create MTLCounterSampleBuffer of size %llu, for %d queries, in query pool of type %s. Reverting to emulated behavior. (Error code %li): %s", + (VkDeviceSize)pCreateInfo->queryCount * kMVKQuerySlotSizeInBytes, pCreateInfo->queryCount, queryTypeName, (long)err.code, err.localizedDescription.UTF8String); } } }; From 665ef6df1396b31d642a435c45ca0d265b39dc42 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 16 May 2023 10:39:16 -0400 Subject: [PATCH 27/74] Improve support for deviceUUID and deviceLUID. - MTLDevice registryID is not constant across OS reboots, which is not conformant with deviceUUID requirements. - Replace with combination of MTLDevice location, locationNumber, peerGroupID, and peerIndex, which should define uniqueness, and should be constant across OS reboots. - Populate deviceLUID from MTLDevice registryID. --- Docs/Whats_New.md | 3 ++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 8 ++++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 52 +++++++++++++++++++---- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index e45bb308a..85de3e6cf 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -32,6 +32,9 @@ Released TBD disable recent fixes to handling LOD for arrayed depth images in shaders, on Apple Silicon, when those fixes cause regression in rendering behavior. - Identify each unsupported device feature flag that the app attempts to be enable. +- Populate `deviceUUID` from `MTLDevice` location and peer group info, + which should be unique, and constant across OS reboots. +- Populate `deviceLUID` from `MTLDevice.registryID`. - For correctness, set `VkPhysicalDeviceLimits::lineWidthGranularity` to `1`. - Improve GitHub CI production of binary artifacts on submission and release. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index e1f7e310d..037d70173 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -1064,6 +1064,14 @@ class MVKDeviceObjectPool : public MVKObjectPool, public MVKDeviceTrackingMix /** Returns the registry ID of the specified device, or zero if the device does not have a registry ID. */ uint64_t mvkGetRegistryID(id mtlDevice); +/** + * Returns a value identifying the physical location of the specified device. + * The returned value is a hash of the location, locationNumber, peerGroupID, + * and peerIndex properties of the device. On devices with only one built-in GPU, + * the returned value will be zero. + */ +uint64_t mvkGetLocationID(id mtlDevice); + /** Returns whether the MTLDevice supports BC texture compression. */ bool mvkSupportsBCTextureCompression(id mtlDevice); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index ba0c33103..6adabc31c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -727,15 +727,21 @@ } } +// Since these are uint8_t arrays, use Big-Endian byte ordering, +// so a hex dump of the array is human readable in its parts. void MVKPhysicalDevice::populateDeviceIDProperties(VkPhysicalDeviceVulkan11Properties* pVk11Props) { uint8_t* uuid; size_t uuidComponentOffset; - // ---- Device ID ---------------------------------------------- + // ---- Device UUID ---------------------------------------------- uuid = pVk11Props->deviceUUID; uuidComponentOffset = 0; mvkClear(uuid, VK_UUID_SIZE); + // From Vulkan spec: deviceUUID must be universally unique for the device, + // AND must be immutable for a given device across instances, processes, + // driver APIs, driver versions, and system reboots. + // First 4 bytes contains GPU vendor ID uint32_t vendorID = _properties.vendorID; *(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(vendorID); @@ -746,10 +752,10 @@ *(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(deviceID); uuidComponentOffset += sizeof(deviceID); - // Last 8 bytes contain the GPU registry ID - uint64_t regID = mvkGetRegistryID(_mtlDevice); - *(uint64_t*)&uuid[uuidComponentOffset] = NSSwapHostLongLongToBig(regID); - uuidComponentOffset += sizeof(regID); + // Last 8 bytes contain the GPU location identifier + uint64_t locID = mvkGetLocationID(_mtlDevice); + *(uint64_t*)&uuid[uuidComponentOffset] = NSSwapHostLongLongToBig(locID); + uuidComponentOffset += sizeof(locID); // ---- Driver ID ---------------------------------------------- uuid = pVk11Props->driverUUID; @@ -772,10 +778,10 @@ *(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(gpuCap); uuidComponentOffset += sizeof(gpuCap); - // ---- LUID ignored for Metal devices ------------------------ - mvkClear(pVk11Props->deviceLUID, VK_LUID_SIZE); - pVk11Props->deviceNodeMask = 0; - pVk11Props->deviceLUIDValid = VK_FALSE; + // ---- Device LUID ------------------------ + *(uint64_t*)pVk11Props->deviceLUID = NSSwapHostLongLongToBig(mvkGetRegistryID(_mtlDevice)); + pVk11Props->deviceNodeMask = 1; // Per Vulkan spec + pVk11Props->deviceLUIDValid = VK_TRUE; } void MVKPhysicalDevice::populateSubgroupProperties(VkPhysicalDeviceVulkan11Properties* pVk11Props) { @@ -2732,6 +2738,8 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope } #endif //MVK_IOS_OR_TVOS +// Since this is a uint8_t array, use Big-Endian byte ordering, +// so a hex dump of the array is human readable in its parts. void MVKPhysicalDevice::initPipelineCacheUUID() { // Clear the UUID @@ -4835,6 +4843,32 @@ uint64_t mvkGetRegistryID(id mtlDevice) { return [mtlDevice respondsToSelector: @selector(registryID)] ? mtlDevice.registryID : 0; } +uint64_t mvkGetLocationID(id mtlDevice) { + uint64_t hash = 0; + +#if MVK_MACOS && !MVK_MACCAT + // All of these device properties were added at the same time, + // so only need to check for the presence of one of them. + if ([mtlDevice respondsToSelector: @selector(location)]) { + uint64_t val; + + val = mtlDevice.location; + hash = mvkHash(&val, 1, hash); + + val = mtlDevice.locationNumber; + hash = mvkHash(&val, 1, hash); + + val = mtlDevice.peerGroupID; + hash = mvkHash(&val, 1, hash); + + val = mtlDevice.peerIndex; + hash = mvkHash(&val, 1, hash); + } +#endif + + return hash; +} + // If the supportsBCTextureCompression query is available, use it. // Otherwise only macOS supports BC compression. bool mvkSupportsBCTextureCompression(id mtlDevice) { From 75b4d26fbcccc610a26a929da7a2983c8b7d943c Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Wed, 17 May 2023 15:45:22 -0500 Subject: [PATCH 28/74] Check if shader compiled before adding it to a pipeline Prevents Metal from aborting when you try to set a null function on the descriptor --- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index fb2880e7a..39b684892 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -1050,8 +1050,8 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 MVKMTLFunction func = getMTLFunction(shaderConfig, _pTessCtlSS, "Tessellation control"); id mtlFunc = func.getMTLFunction(); - plDesc.computeFunction = mtlFunc; if ( !mtlFunc ) { return false; } + plDesc.computeFunction = mtlFunc; auto& funcRslts = func.shaderConversionResults; _needsTessCtlSwizzleBuffer = funcRslts.needsSwizzleBuffer; From 6c633a7a18925d4643ea2be97e93b7e5f2b7d32b Mon Sep 17 00:00:00 2001 From: Italo Mandara Date: Sun, 21 May 2023 00:26:44 +0100 Subject: [PATCH 29/74] update SPIRV-Cross revision to include explicit LOD workaround regression fix --- ExternalRevisions/SPIRV-Cross_repo_revision | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision index 623b20930..902626656 100644 --- a/ExternalRevisions/SPIRV-Cross_repo_revision +++ b/ExternalRevisions/SPIRV-Cross_repo_revision @@ -1 +1 @@ -3550a54ae01b295c40ce972d951b420b388b9401 +34cd230e5e22d08869be878055a2267ba66cc601 From 0125e5b7397f89eb58e0db9bf4e17def1051c487 Mon Sep 17 00:00:00 2001 From: Italo Mandara Date: Sun, 21 May 2023 00:27:16 +0100 Subject: [PATCH 30/74] Revert "Allow to disable Explicit LOD Workaround" This reverts commit 6f3a2b709fbfcfdf7dc077b80b12f02463cc07b1. --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 +- MoltenVK/MoltenVK/Utility/MVKEnvironment.h | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 6adabc31c..bd3aad8bc 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1651,7 +1651,7 @@ break; case kAppleVendorId: // TODO: Other GPUs? - MVK_SET_FROM_ENV_OR_BUILD_BOOL(_metalFeatures.needsSampleDrefLodArrayWorkaround, MVK_ENABLE_EXPLICIT_LOD_WORKAROUND); + _metalFeatures.needsSampleDrefLodArrayWorkaround = true; // fallthrough case kIntelVendorId: case kNVVendorId: diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h index a4411c44c..68ef83a9d 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h @@ -295,8 +295,3 @@ void mvkSetConfig(const MVKConfiguration& mvkConfig); #ifndef MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM # define MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM MVK_CONFIG_COMPRESSION_ALGORITHM_NONE #endif - -/** Enables Explicit LOD workaround defaults to true. */ -#ifndef MVK_ENABLE_EXPLICIT_LOD_WORKAROUND -# define MVK_ENABLE_EXPLICIT_LOD_WORKAROUND 1 -#endif From c231c90dd4b2e210c84ab498cd2a0fe92c770ec1 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 22 May 2023 20:00:14 -0400 Subject: [PATCH 31/74] Update dependency libraries to match Vulkan SDK 1.3.250. - Update Whats New document. --- Docs/Whats_New.md | 25 +++++++++++++----- ExternalRevisions/SPIRV-Cross_repo_revision | 2 +- .../Vulkan-Headers_repo_revision | 2 +- ExternalRevisions/Vulkan-Tools_repo_revision | 2 +- ExternalRevisions/glslang_repo_revision | 2 +- Templates/spirv-tools/build.zip | Bin 53465 -> 53948 bytes 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 3c698a629..0eb10282d 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -16,28 +16,39 @@ Copyright (c) 2015-2023 [The Brenwill Workshop Ltd.](http://www.brenwill.com) MoltenVK 1.2.4 -------------- -Released TBD +Released 2023/05/23 - Add support for extensions: - `VK_KHR_map_memory2` +- Deprecate the obsolete and non-standard `VK_MVK_moltenvk` extension. + - Add `mvk_config.h`, `mvk_private_api.h`, and `mvk_deprecated_api.h`, and deprecate `vk_mvk_moltenvk.h`. - Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). - Support separate depth and stencil attachments during dynamic rendering. -- Deprecate the obsolete and non-standard `VK_MVK_moltenvk` extension. - Fix memory leak when waiting on timeline semaphores. - Fix race condition when updating values in `VkPastPresentationTimingGOOGLE`, and ensure swapchain image presented time is always populated when requested. -- Report error, but do not fail on request for timestamp query pool that is too large for `MTLCounterSampleBuffer`. +- Report error, but do not fail on request for timestamp query pool that is too + large for `MTLCounterSampleBuffer`, and fall back to emulation via CPU timestamps. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. -- Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively - disable recent fixes to handling LOD for arrayed depth images in shaders, - on Apple Silicon, when those fixes cause regression in rendering behavior. -- Identify each unsupported device feature flag that the app attempts to be enable. +- Respect the bind point supplied to `vkCmdBindDescriptorSets()` / `vkCmdPushDescriptorSets()`. +- Check if shader compiled before adding it to a pipeline, to avoid Metal validation error. +- Identify each unsupported device feature flag that the app attempts to enable. - Populate `deviceUUID` from `MTLDevice` location and peer group info, which should be unique, and constant across OS reboots. - Populate `deviceLUID` from `MTLDevice.registryID`. +- Avoid Metal validation warning when depth component swizzled away. +- Fix depth clamp and texture swizzle feature discovery on simulator builds. - For correctness, set `VkPhysicalDeviceLimits::lineWidthGranularity` to `1`. - Improve GitHub CI production of binary artifacts on submission and release. +- Update dependency libraries to match _Vulkan SDK 1.3.250_. +- Update to latest SPIRV-Cross: + - MSL: Fix for argument buffer index compare when invalid. + - MSL: Fix dref lod workaround on combined texture/samplers. + - MSL: Do not override variable name with v_ identifier. + - MSL: Use name_id consistently in argument declaration. + - MSL: Don't hit array copy path for pointer to array. + - MSL: Use templated array type when emitting BDA to arrays. diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision index 902626656..d2ea9c606 100644 --- a/ExternalRevisions/SPIRV-Cross_repo_revision +++ b/ExternalRevisions/SPIRV-Cross_repo_revision @@ -1 +1 @@ -34cd230e5e22d08869be878055a2267ba66cc601 +12542fc6fc05000e04742daf93892a0b10edbe80 diff --git a/ExternalRevisions/Vulkan-Headers_repo_revision b/ExternalRevisions/Vulkan-Headers_repo_revision index c0981ee2e..e48127cb9 100644 --- a/ExternalRevisions/Vulkan-Headers_repo_revision +++ b/ExternalRevisions/Vulkan-Headers_repo_revision @@ -1 +1 @@ -fa204df59c6caea6b9be3cf0754a88cd89056a87 +9e61870ecbd32514113b467e0a0c46f60ed222c7 diff --git a/ExternalRevisions/Vulkan-Tools_repo_revision b/ExternalRevisions/Vulkan-Tools_repo_revision index a36355f59..4359b342d 100644 --- a/ExternalRevisions/Vulkan-Tools_repo_revision +++ b/ExternalRevisions/Vulkan-Tools_repo_revision @@ -1 +1 @@ -f196c8d3cafcaf7e628b7b76a799c940999ee984 +695887a994ef9cc00a7aa3f9c00b31a56ea79534 diff --git a/ExternalRevisions/glslang_repo_revision b/ExternalRevisions/glslang_repo_revision index 4ec3c5381..d336b0428 100644 --- a/ExternalRevisions/glslang_repo_revision +++ b/ExternalRevisions/glslang_repo_revision @@ -1 +1 @@ -14e5a04e70057972eef8a40df422e30a3b70e4b5 +d1517d64cfca91f573af1bf7341dc3a5113349c0 diff --git a/Templates/spirv-tools/build.zip b/Templates/spirv-tools/build.zip index c78f151c340a212042a4167694c1a2818e4feb8e..ee4797c80b3a8674043025bf4afff4bfb9b8082a 100644 GIT binary patch delta 38581 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 Q+&}?XLHn@n>rLx_02!TstpET3 delta 37932 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 C+bN9z From b863ecef4d5c23df84942804ac4a207cbe923c55 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 23 May 2023 13:13:19 -0400 Subject: [PATCH 32/74] Accumulate render stages when a resource is used by multiple descriptor bindings. --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h | 3 +++ MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm | 12 +++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 0eb10282d..1bf16f4ab 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -31,6 +31,7 @@ Released 2023/05/23 large for `MTLCounterSampleBuffer`, and fall back to emulation via CPU timestamps. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0. +- Accumulate render stages when a resource is used by multiple descriptor bindings. - Respect the bind point supplied to `vkCmdBindDescriptorSets()` / `vkCmdPushDescriptorSets()`. - Check if shader compiled before adding it to a pipeline, to avoid Metal validation error. - Identify each unsupported device feature flag that the app attempts to enable. diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index b47cc22e2..d8cf26ca5 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -565,6 +565,8 @@ class MVKGraphicsResourcesCommandEncoderState : public MVKResourcesCommandEncode /** Marks any overridden buffer indexes as dirty. */ void markOverriddenBufferIndexesDirty(); + void endMetalRenderPass() override; + void markDirty() override; #pragma mark Construction @@ -577,6 +579,7 @@ class MVKGraphicsResourcesCommandEncoderState : public MVKResourcesCommandEncode void bindMetalArgumentBuffer(MVKShaderStage stage, MVKMTLBufferBinding& buffBind) override; ResourceBindings<8> _shaderStageResourceBindings[kMVKShaderStageFragment + 1]; + std::unordered_map, MTLRenderStages> _renderUsageStages; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index 0262d47db..4ad5fa532 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -757,6 +757,11 @@ } } +void MVKGraphicsResourcesCommandEncoderState::endMetalRenderPass() { + MVKResourcesCommandEncoderState::endMetalRenderPass(); + _renderUsageStages.clear(); +} + // Mark everything as dirty void MVKGraphicsResourcesCommandEncoderState::markDirty() { MVKResourcesCommandEncoderState::markDirty(); @@ -976,7 +981,12 @@ } else { auto* mtlRendEnc = _cmdEncoder->_mtlRenderEncoder; if ([mtlRendEnc respondsToSelector: @selector(useResource:usage:stages:)]) { - [mtlRendEnc useResource: mtlResource usage: mtlUsage stages: mtlStages]; + // Within a renderpass, a resource may be used by multiple descriptor bindings, + // each of which may assign a different usage stage. Dynamically accumulate + // usage stages across all descriptor bindings using the resource. + auto& accumStages = _renderUsageStages[mtlResource]; + accumStages |= mtlStages; + [mtlRendEnc useResource: mtlResource usage: mtlUsage stages: accumStages]; } else { [mtlRendEnc useResource: mtlResource usage: mtlUsage]; } From b26ce32a60bcf8f6a662cb09fdf19943426eec4a Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 23 May 2023 19:01:31 -0400 Subject: [PATCH 33/74] Advertise VK_KHR_depth_stencil_resolve extension on all devices. Advertise VK_KHR_depth_stencil_resolve extension on early iOS devices, since VK_RESOLVE_MODE_SAMPLE_ZERO_BIT is supported on all devices, even if other resolve modes are not, and makes it consistent with Vulkan 1.2 mandatory support for VK_RESOLVE_MODE_SAMPLE_ZERO_BIT. --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 1bf16f4ab..d845d80fc 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -40,6 +40,7 @@ Released 2023/05/23 - Populate `deviceLUID` from `MTLDevice.registryID`. - Avoid Metal validation warning when depth component swizzled away. - Fix depth clamp and texture swizzle feature discovery on simulator builds. +- Advertise `VK_KHR_depth_stencil_resolve` extension on all devices. - For correctness, set `VkPhysicalDeviceLimits::lineWidthGranularity` to `1`. - Improve GitHub CI production of binary artifacts on submission and release. - Update dependency libraries to match _Vulkan SDK 1.3.250_. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index bd3aad8bc..8f043f41d 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -3050,11 +3050,6 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_supportedExtensions; pWritableExtns->disableAllButEnabledDeviceExtensions(); -#if MVK_IOS_OR_TVOS - if (!_metalFeatures.depthResolve) { - pWritableExtns->vk_KHR_depth_stencil_resolve.enabled = false; - } -#endif if (!_metalFeatures.samplerMirrorClampToEdge) { pWritableExtns->vk_KHR_sampler_mirror_clamp_to_edge.enabled = false; } From 83a18112307b3287bd3e5a976f693d0e163b17f4 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Fri, 26 May 2023 00:06:40 -0400 Subject: [PATCH 34/74] Ensure compute encoding state is marked dirty for non-dispatch commands. The same compute encoder is used across dispatches and other commands, which may override compute state, and end up breaking subsequent dispatches. - Mark compute encoding state dirty when following commands, which use Metal compute encoders, are issued: - vkCmdCopyBuffer() - vkCmdClearColorImage() - vkCmdClearDepthStencilImage() - vkCmdFillBuffer() - vkCmdCopyQueryPoolResults() - MVKCommandEncoder move marking compute state dirty from endCurrentMetalEncoding() to getMTLComputeEncoder(). - For efficiency, don't prematurely force end of query copy compute encoder used on renderpass end, in case compute dispatches follow. - Update MoltenVK to 1.2.5 (unrelated). --- Docs/Whats_New.md | 9 +++++++++ MoltenVK/MoltenVK/API/mvk_config.h | 2 +- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 8 ++++---- MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h | 8 +++++--- MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm | 12 +++++++----- MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm | 3 +-- MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm | 6 +++--- 7 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index d845d80fc..1ef0385a4 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -13,6 +13,15 @@ Copyright (c) 2015-2023 [The Brenwill Workshop Ltd.](http://www.brenwill.com) +MoltenVK 1.2.5 +-------------- + +Released TBD + +- Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. + + + MoltenVK 1.2.4 -------------- diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index 6237c5b81..c224fa106 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -45,7 +45,7 @@ extern "C" { */ #define MVK_VERSION_MAJOR 1 #define MVK_VERSION_MINOR 2 -#define MVK_VERSION_PATCH 4 +#define MVK_VERSION_PATCH 5 #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) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index dff93dc74..816dbc3ff 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -955,7 +955,7 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma copyInfo.dstOffset = (uint32_t)cpyRgn.dstOffset; copyInfo.size = (uint32_t)cpyRgn.size; - id mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseCopyBuffer); + id mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseCopyBuffer, true); [mtlComputeEnc pushDebugGroup: @"vkCmdCopyBuffer"]; [mtlComputeEnc setComputePipelineState: cmdEncoder->getCommandEncodingPool()->getCmdCopyBufferBytesMTLComputePipelineState()]; [mtlComputeEnc setBuffer:srcMTLBuff offset: srcMTLBuffOffset atIndex: 0]; @@ -1141,7 +1141,7 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma info.offset = cpyRgn.imageOffset; info.extent = cpyRgn.imageExtent; bool needsTempBuff = mipLevel != 0; - id mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(cmdUse); + id mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(cmdUse, false); // Compute state will be marked dirty on next compute encoder after Blit encoder below. id mtlComputeState = cmdEncoder->getCommandEncodingPool()->getCmdCopyBufferToImage3DDecompressMTLComputePipelineState(needsTempBuff); [mtlComputeEnc pushDebugGroup: @"vkCmdCopyBufferToImage"]; [mtlComputeEnc setComputePipelineState: mtlComputeState]; @@ -1580,7 +1580,7 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma // Luckily for us, linear images only have one mip and one array layer under Metal. assert( !isDS ); id mtlClearState = cmdEncoder->getCommandEncodingPool()->getCmdClearColorImageMTLComputePipelineState(pixFmts->getFormatType(_image->getVkFormat())); - id mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseClearColorImage); + id mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseClearColorImage, true); [mtlComputeEnc pushDebugGroup: @"vkCmdClearColorImage"]; [mtlComputeEnc setComputePipelineState: mtlClearState]; [mtlComputeEnc setTexture: imgMTLTex atIndex: 0]; @@ -1747,7 +1747,7 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma NSUInteger tgWidth = std::min(cps.maxTotalThreadsPerThreadgroup, cmdEncoder->getMTLDevice().maxThreadsPerThreadgroup.width); NSUInteger tgCount = _wordCount / tgWidth; - id mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseFillBuffer); + id mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseFillBuffer, true); [mtlComputeEnc pushDebugGroup: @"vkCmdFillBuffer"]; [mtlComputeEnc setComputePipelineState: cps]; [mtlComputeEnc setBytes: &_dataValue length: sizeof(_dataValue) atIndex: 1]; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 1a7a7d5cc..76274dad8 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -337,10 +337,12 @@ class MVKCommandEncoder : public MVKBaseDeviceObject { * Returns the current Metal compute encoder for the specified use, * which determines the label assigned to the returned encoder. * - * If the current encoder is not a compute encoder, this function ends current before - * beginning compute encoding. + * If the current encoder is a compute encoder, the compute state being tracked can + * optionally be marked dirty. Otherwise, if the current encoder is not a compute + * encoder, this function ends the current encoder before beginning compute encoding. */ - id getMTLComputeEncoder(MVKCommandUse cmdUse); + id getMTLComputeEncoder(MVKCommandUse cmdUse, + bool markCurrentComputeStateDirty = false); /** * Returns the current Metal BLIT encoder for the specified use, diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 5155a141e..8ae3031d3 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -839,10 +839,6 @@ void MVKCommandEncoder::endCurrentMetalEncoding() { endMetalRenderEncoding(); - _computePipelineState.markDirty(); - _computeResourcesState.markDirty(); - _computePushConstants.markDirty(); - if (_mtlComputeEncoder && _cmdBuffer->_hasStageCounterTimestampCommand) { [_mtlComputeEncoder updateFence: getStageCountersMTLFence()]; } endMetalEncoding(_mtlComputeEncoder); _mtlComputeEncoderUse = kMVKCommandUseNone; @@ -854,12 +850,18 @@ encodeTimestampStageCounterSamples(); } -id MVKCommandEncoder::getMTLComputeEncoder(MVKCommandUse cmdUse) { +id MVKCommandEncoder::getMTLComputeEncoder(MVKCommandUse cmdUse, bool markCurrentComputeStateDirty) { if ( !_mtlComputeEncoder ) { endCurrentMetalEncoding(); _mtlComputeEncoder = [_mtlCmdBuffer computeCommandEncoder]; retainIfImmediatelyEncoding(_mtlComputeEncoder); beginMetalComputeEncoding(cmdUse); + markCurrentComputeStateDirty = true; // Always mark current compute state dirty for new encoder + } + if(markCurrentComputeStateDirty) { + _computePipelineState.markDirty(); + _computePushConstants.markDirty(); + _computeResourcesState.markDirty(); } if (_mtlComputeEncoderUse != cmdUse) { _mtlComputeEncoderUse = cmdUse; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index 4ad5fa532..044dd96e3 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -1160,7 +1160,7 @@ if ( !_hasRasterized || !vizBuff || _mtlRenderPassQueries.empty() ) { return; } // Nothing to do. id mtlAccumState = _cmdEncoder->getCommandEncodingPool()->getAccumulateOcclusionQueryResultsMTLComputePipelineState(); - id mtlAccumEncoder = _cmdEncoder->getMTLComputeEncoder(kMVKCommandUseAccumOcclusionQuery); + id mtlAccumEncoder = _cmdEncoder->getMTLComputeEncoder(kMVKCommandUseAccumOcclusionQuery, true); [mtlAccumEncoder setComputePipelineState: mtlAccumState]; for (auto& qryLoc : _mtlRenderPassQueries) { // Accumulate the current results to the query pool's buffer. @@ -1173,7 +1173,6 @@ [mtlAccumEncoder dispatchThreadgroups: MTLSizeMake(1, 1, 1) threadsPerThreadgroup: MTLSizeMake(1, 1, 1)]; } - _cmdEncoder->endCurrentMetalEncoding(); _mtlRenderPassQueries.clear(); _hasRasterized = false; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm index b3b139a6b..2e0e13682 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm @@ -284,7 +284,7 @@ } id MVKOcclusionQueryPool::encodeComputeCopyResults(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t, uint32_t index) { - id mtlCmdEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseCopyQueryPoolResults); + id mtlCmdEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseCopyQueryPoolResults, true); [mtlCmdEnc setBuffer: getVisibilityResultMTLBuffer() offset: getVisibilityResultOffset(firstQuery) atIndex: index]; return mtlCmdEnc; } @@ -434,12 +434,12 @@ destinationBuffer: tempBuff->_mtlBuffer destinationOffset: tempBuff->_offset]; - id mtlCmdEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseCopyQueryPoolResults); + id mtlCmdEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseCopyQueryPoolResults, true); [mtlCmdEnc setBuffer: tempBuff->_mtlBuffer offset: tempBuff->_offset atIndex: index]; return mtlCmdEnc; } else { // We can set the timestamp bytes into the compute encoder. - id mtlCmdEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseCopyQueryPoolResults); + id mtlCmdEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseCopyQueryPoolResults, true); cmdEncoder->setComputeBytes(mtlCmdEnc, &_timestamps[firstQuery], queryCount * _queryElementCount * sizeof(uint64_t), index); return mtlCmdEnc; } From 107be116b73793dda636419011277ae836a9074a Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 30 May 2023 21:11:02 -0400 Subject: [PATCH 35/74] Add support for VK_PRESENT_MODE_IMMEDIATE_KHR to macOS Cube demo. - Only log performance stats on FPS logging if logging style is explicitly set to MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT (unrelated). --- Demos/Cube/macOS/DemoViewController.m | 24 ++++++++++++++++---- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 1 - MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 4 +++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Demos/Cube/macOS/DemoViewController.m b/Demos/Cube/macOS/DemoViewController.m index 9586fa670..d8468bdc3 100644 --- a/Demos/Cube/macOS/DemoViewController.m +++ b/Demos/Cube/macOS/DemoViewController.m @@ -43,13 +43,29 @@ -(void) viewDidLoad { self.view.wantsLayer = YES; // Back the view with a layer created by the makeBackingLayer method. - const char* argv[] = { "cube" }; + // Enabling this will sync the rendering loop with the natural display link (60 fps). + // Disabling this will allow the rendering loop to run flat out, limited only by the rendering speed. + bool useDisplayLink = true; + + VkPresentModeKHR vkPresentMode = useDisplayLink ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR; + char vkPresentModeStr[64]; + sprintf(vkPresentModeStr, "%d", vkPresentMode); + + const char* argv[] = { "cube", "--present_mode", vkPresentModeStr }; int argc = sizeof(argv)/sizeof(char*); demo_main(&demo, self.view.layer, argc, argv); - CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); - CVDisplayLinkSetOutputCallback(_displayLink, &DisplayLinkCallback, &demo); - CVDisplayLinkStart(_displayLink); + if (useDisplayLink) { + CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); + CVDisplayLinkSetOutputCallback(_displayLink, &DisplayLinkCallback, &demo); + CVDisplayLinkStart(_displayLink); + } else { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + while(true) { + demo_draw(&demo); + } + }); + } } diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 1ef0385a4..514d270ec 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -19,6 +19,7 @@ MoltenVK 1.2.5 Released TBD - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. +- Add support for `VK_PRESENT_MODE_IMMEDIATE_KHR` to macOS Cube demo. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 8f043f41d..fa8fd1d80 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -4114,7 +4114,6 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope } void MVKDevice::logPerformanceSummary() { - if (_activityPerformanceLoggingStyle == MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_IMMEDIATE) { return; } // Get a copy to minimize time under lock MVKPerformanceStatistics perfStats; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 5ff5d0cfb..c52896d05 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -175,7 +175,9 @@ perfLogCntLimit, (1000.0 / _device->_performanceStatistics.queue.frameInterval.averageDuration), mvkGetElapsedMilliseconds() / 1000.0); - _device->logPerformanceSummary(); + if (mvkConfig().activityPerformanceLoggingStyle == MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT) { + _device->logPerformanceSummary(); + } } } From 6fb53471b119c2e59e1c8c9b593ac3df1c16cdc9 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 5 Jun 2023 19:17:10 -0400 Subject: [PATCH 36/74] Support VK_PRESENT_MODE_IMMEDIATE_KHR if VkPresentTimeGOOGLE::desiredPresentTime is zero. - [MTLDrawable presentAtTime:] syncs to display vsync. To support VK_PRESENT_MODE_IMMEDIATE_KHR while using VkPresentTimeGOOGLE::presentID, only call presentAtTime: if VkPresentTimeGOOGLE::desiredPresentTime has been explicitly set to a non-zero value. - Clarify initially clearing MVKImagePresentInfo to all zeros. --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 3 ++- MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm | 4 +--- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 514d270ec..a64a3a505 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -19,6 +19,7 @@ MoltenVK 1.2.5 Released TBD - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. +- Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. - Add support for `VK_PRESENT_MODE_IMMEDIATE_KHR` to macOS Cube demo. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index b8cfc68e8..cc8a1601f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1313,8 +1313,9 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { mtlDrwbl.layer.displaySyncEnabledMVK = (presentInfo.presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR); } if (presentInfo.hasPresentTime) { - // Convert from nsecs to seconds for Metal addPresentedHandler(mtlDrwbl, presentInfo); + } + if (presentInfo.desiredPresentTime) { [mtlDrwbl presentAtTime: (double)presentInfo.desiredPresentTime * 1.0e-9]; } else { [mtlDrwbl present]; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index fc234c010..c60cb011c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -621,7 +621,7 @@ _presentInfo.reserve(scCnt); for (uint32_t scIdx = 0; scIdx < scCnt; scIdx++) { MVKSwapchain* mvkSC = (MVKSwapchain*)pPresentInfo->pSwapchains[scIdx]; - MVKImagePresentInfo presentInfo = {}; + MVKImagePresentInfo presentInfo = {}; // Start with everything zeroed presentInfo.presentableImage = mvkSC->getPresentableImage(pPresentInfo->pImageIndices[scIdx]); presentInfo.presentMode = pPresentModes ? pPresentModes[scIdx] : VK_PRESENT_MODE_MAX_ENUM_KHR; presentInfo.fence = pFences ? (MVKFence*)pFences[scIdx] : nullptr; @@ -629,8 +629,6 @@ presentInfo.hasPresentTime = true; presentInfo.presentID = pPresentTimes[scIdx].presentID; presentInfo.desiredPresentTime = pPresentTimes[scIdx].desiredPresentTime; - } else { - presentInfo.hasPresentTime = false; } _presentInfo.push_back(presentInfo); VkResult scRslt = mvkSC->getSurfaceStatus(); From 3fbde1615ded02af4a93e45b03811408360fa9ad Mon Sep 17 00:00:00 2001 From: rcombs Date: Tue, 6 Jun 2023 14:26:29 -0500 Subject: [PATCH 37/74] update SPIRV-Cross revision to include function constant fix; closes #1941 --- ExternalRevisions/SPIRV-Cross_repo_revision | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision index d2ea9c606..6f1034c89 100644 --- a/ExternalRevisions/SPIRV-Cross_repo_revision +++ b/ExternalRevisions/SPIRV-Cross_repo_revision @@ -1 +1 @@ -12542fc6fc05000e04742daf93892a0b10edbe80 +55750be7886a96008b964e75e1eb4a5a6c369a2a From 750adcaae2eb49b5c395d537053e71987b9edbcb Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Thu, 29 Oct 2020 00:45:31 -0500 Subject: [PATCH 38/74] Advertise the VK_EXT_shader_demote_to_helper_invocation extension. As of macOS Big Sur and iOS/tvOS 14, the `discard_fragment()` function in MSL is defined to have demote semantics; that is, fragment shader output is discarded, but the fragment shader thread continues to run as a helper invocation. This is very useful for Direct3D emulation, since this is the semantic that HLSL `discard` has. Signed-off-by: Chip Davis --- Docs/MoltenVK_Runtime_UserGuide.md | 1 + Docs/Whats_New.md | 2 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 5 + MoltenVK/MoltenVK/Layers/MVKExtensions.def | 193 +++++++++++---------- 4 files changed, 105 insertions(+), 96 deletions(-) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 98abf8f91..0148448bf 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -373,6 +373,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_scalar_block_layout` - `VK_EXT_separate_stencil_usage` - `VK_EXT_shader_atomic_float` *(requires Metal 3.0)* +- `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_viewport_index_layer` - `VK_EXT_subgroup_size_control` *(requires Metal 2.1 on Mac or Metal 2.2 and Apple family 4 on iOS)* diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 514d270ec..584128bd3 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -18,6 +18,8 @@ MoltenVK 1.2.5 Released TBD +- Add support for extensions: + - `VK_EXT_shader_demote_to_helper_invocation` - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. - Add support for `VK_PRESENT_MODE_IMMEDIATE_KHR` to macOS Cube demo. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index fa8fd1d80..810ad8918 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -407,6 +407,11 @@ atomicFloatFeatures->sparseImageFloat32AtomicAdd = false; break; } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT: { + auto* demoteFeatures = (VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT*)next; + demoteFeatures->shaderDemoteToHelperInvocation = mvkOSVersionIsAtLeast(11.0, 14.0); + break; + } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: { auto* swapchainMaintenance1Features = (VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT*)next; swapchainMaintenance1Features->swapchainMaintenance1 = true; diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 60bafd8f8..a50b3bb58 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -41,102 +41,103 @@ #define MVK_EXTENSION_LAST(var, EXT, type, macos, ios) MVK_EXTENSION(var, EXT, type, macos, ios) #endif -MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_bind_memory2, KHR_BIND_MEMORY_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_buffer_device_address, KHR_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) -MVK_EXTENSION(KHR_copy_commands2, KHR_COPY_COMMANDS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_create_renderpass2, KHR_CREATE_RENDERPASS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_dedicated_allocation, KHR_DEDICATED_ALLOCATION, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_depth_stencil_resolve, KHR_DEPTH_STENCIL_RESOLVE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_draw_indirect_count, KHR_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(KHR_driver_properties, KHR_DRIVER_PROPERTIES, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_dynamic_rendering, KHR_DYNAMIC_RENDERING, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_fence, KHR_EXTERNAL_FENCE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_fence_capabilities, KHR_EXTERNAL_FENCE_CAPABILITIES, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_memory, KHR_EXTERNAL_MEMORY, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_memory_capabilities, KHR_EXTERNAL_MEMORY_CAPABILITIES, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_semaphore, KHR_EXTERNAL_SEMAPHORE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_semaphore_capabilities, KHR_EXTERNAL_SEMAPHORE_CAPABILITIES, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_fragment_shader_barycentric, KHR_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0) -MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_imageless_framebuffer, KHR_IMAGELESS_FRAMEBUFFER, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_map_memory2, KHR_MAP_MEMORY_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_portability_subset, KHR_PORTABILITY_SUBSET, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_relaxed_block_layout, KHR_RELAXED_BLOCK_LAYOUT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_sampler_mirror_clamp_to_edge, KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, DEVICE, 10.11, 14.0) -MVK_EXTENSION(KHR_sampler_ycbcr_conversion, KHR_SAMPLER_YCBCR_CONVERSION, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_separate_depth_stencil_layouts, KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_shader_atomic_int64, KHR_SHADER_ATOMIC_INT64, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(KHR_shader_draw_parameters, KHR_SHADER_DRAW_PARAMETERS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_shader_float_controls, KHR_SHADER_FLOAT_CONTROLS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_shader_float16_int8, KHR_SHADER_FLOAT16_INT8, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_shader_subgroup_extended_types, KHR_SHADER_SUBGROUP_EXTENDED_TYPES, DEVICE, 10.14, 13.0) -MVK_EXTENSION(KHR_spirv_1_4, KHR_SPIRV_1_4, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_storage_buffer_storage_class, KHR_STORAGE_BUFFER_STORAGE_CLASS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_surface, KHR_SURFACE, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_swapchain, KHR_SWAPCHAIN, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_swapchain_mutable_format, KHR_SWAPCHAIN_MUTABLE_FORMAT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_timeline_semaphore, KHR_TIMELINE_SEMAPHORE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) -MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0) -MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA) -MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, DEVICE, 10.13, 11.0) -MVK_EXTENSION(EXT_metal_objects, EXT_METAL_OBJECTS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(EXT_pipeline_creation_cache_control, EXT_PIPELINE_CREATION_CACHE_CONTROL, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE, 11.0, 11.0) -MVK_EXTENSION(EXT_private_data, EXT_PRIVATE_DATA, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_robustness2, EXT_ROBUSTNESS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_sample_locations, EXT_SAMPLE_LOCATIONS, DEVICE, 10.13, 11.0) -MVK_EXTENSION(EXT_sampler_filter_minmax, EXT_SAMPLER_FILTER_MINMAX, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_separate_stencil_usage, EXT_SEPARATE_STENCIL_USAGE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_shader_atomic_float, EXT_SHADER_ATOMIC_FLOAT, DEVICE, 13.0, 16.0) -MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE, 10.14, 12.0) -MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_subgroup_size_control, EXT_SUBGROUP_SIZE_CONTROL, DEVICE, 10.14, 13.0) -MVK_EXTENSION(EXT_surface_maintenance1, EXT_SURFACE_MAINTENANCE_1, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE, INSTANCE, 10.11, 9.0) -MVK_EXTENSION(EXT_swapchain_maintenance1, EXT_SWAPCHAIN_MAINTENANCE_1, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT, DEVICE, 10.13, 11.0) -MVK_EXTENSION(EXT_texture_compression_astc_hdr, EXT_TEXTURE_COMPRESSION_ASTC_HDR, DEVICE, 11.0, 13.0) -MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR, DEVICE, 10.11, 8.0) -MVK_EXTENSION(AMD_draw_indirect_count, AMD_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(AMD_gpu_shader_half_float, AMD_GPU_SHADER_HALF_FLOAT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(AMD_negative_viewport_height, AMD_NEGATIVE_VIEWPORT_HEIGHT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(AMD_shader_image_load_store_lod, AMD_SHADER_IMAGE_LOAD_STORE_LOD, DEVICE, 11.0, 8.0) -MVK_EXTENSION(AMD_shader_trinary_minmax, AMD_SHADER_TRINARY_MINMAX, DEVICE, 10.14, 12.0) -MVK_EXTENSION(IMG_format_pvrtc, IMG_FORMAT_PVRTC, DEVICE, 11.0, 8.0) -MVK_EXTENSION(INTEL_shader_integer_functions2, INTEL_SHADER_INTEGER_FUNCTIONS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(GOOGLE_display_timing, GOOGLE_DISPLAY_TIMING, DEVICE, 10.11, 8.0) -MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, INSTANCE, MVK_NA, 8.0) -MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, INSTANCE, 10.11, MVK_NA) -MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(NV_fragment_shader_barycentric, NV_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0) -MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_bind_memory2, KHR_BIND_MEMORY_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_buffer_device_address, KHR_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) +MVK_EXTENSION(KHR_copy_commands2, KHR_COPY_COMMANDS_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_create_renderpass2, KHR_CREATE_RENDERPASS_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_dedicated_allocation, KHR_DEDICATED_ALLOCATION, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_depth_stencil_resolve, KHR_DEPTH_STENCIL_RESOLVE, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(KHR_draw_indirect_count, KHR_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA) +MVK_EXTENSION(KHR_driver_properties, KHR_DRIVER_PROPERTIES, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_dynamic_rendering, KHR_DYNAMIC_RENDERING, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_external_fence, KHR_EXTERNAL_FENCE, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_external_fence_capabilities, KHR_EXTERNAL_FENCE_CAPABILITIES, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(KHR_external_memory, KHR_EXTERNAL_MEMORY, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_external_memory_capabilities, KHR_EXTERNAL_MEMORY_CAPABILITIES, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(KHR_external_semaphore, KHR_EXTERNAL_SEMAPHORE, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_external_semaphore_capabilities, KHR_EXTERNAL_SEMAPHORE_CAPABILITIES, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(KHR_fragment_shader_barycentric, KHR_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0) +MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(KHR_imageless_framebuffer, KHR_IMAGELESS_FRAMEBUFFER, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_map_memory2, KHR_MAP_MEMORY_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_portability_subset, KHR_PORTABILITY_SUBSET, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_relaxed_block_layout, KHR_RELAXED_BLOCK_LAYOUT, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_sampler_mirror_clamp_to_edge, KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, DEVICE, 10.11, 14.0) +MVK_EXTENSION(KHR_sampler_ycbcr_conversion, KHR_SAMPLER_YCBCR_CONVERSION, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_separate_depth_stencil_layouts, KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_shader_atomic_int64, KHR_SHADER_ATOMIC_INT64, DEVICE, MVK_NA, MVK_NA) +MVK_EXTENSION(KHR_shader_draw_parameters, KHR_SHADER_DRAW_PARAMETERS, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_shader_float_controls, KHR_SHADER_FLOAT_CONTROLS, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_shader_float16_int8, KHR_SHADER_FLOAT16_INT8, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_shader_subgroup_extended_types, KHR_SHADER_SUBGROUP_EXTENDED_TYPES, DEVICE, 10.14, 13.0) +MVK_EXTENSION(KHR_spirv_1_4, KHR_SPIRV_1_4, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_storage_buffer_storage_class, KHR_STORAGE_BUFFER_STORAGE_CLASS, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_surface, KHR_SURFACE, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(KHR_swapchain, KHR_SWAPCHAIN, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_swapchain_mutable_format, KHR_SWAPCHAIN_MUTABLE_FORMAT, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_timeline_semaphore, KHR_TIMELINE_SEMAPHORE, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA) +MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) +MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0) +MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA) +MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, DEVICE, 10.13, 11.0) +MVK_EXTENSION(EXT_metal_objects, EXT_METAL_OBJECTS, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(EXT_pipeline_creation_cache_control, EXT_PIPELINE_CREATION_CACHE_CONTROL, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE, 11.0, 11.0) +MVK_EXTENSION(EXT_private_data, EXT_PRIVATE_DATA, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_robustness2, EXT_ROBUSTNESS_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_sample_locations, EXT_SAMPLE_LOCATIONS, DEVICE, 10.13, 11.0) +MVK_EXTENSION(EXT_sampler_filter_minmax, EXT_SAMPLER_FILTER_MINMAX, DEVICE, MVK_NA, MVK_NA) +MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_separate_stencil_usage, EXT_SEPARATE_STENCIL_USAGE, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_shader_atomic_float, EXT_SHADER_ATOMIC_FLOAT, DEVICE, 13.0, 16.0) +MVK_EXTENSION(EXT_shader_demote_to_helper_invocation, EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, DEVICE, 11.0, 14.0) +MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE, 10.14, 12.0) +MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_subgroup_size_control, EXT_SUBGROUP_SIZE_CONTROL, DEVICE, 10.14, 13.0) +MVK_EXTENSION(EXT_surface_maintenance1, EXT_SURFACE_MAINTENANCE_1, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE, INSTANCE, 10.11, 9.0) +MVK_EXTENSION(EXT_swapchain_maintenance1, EXT_SWAPCHAIN_MAINTENANCE_1, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT, DEVICE, 10.13, 11.0) +MVK_EXTENSION(EXT_texture_compression_astc_hdr, EXT_TEXTURE_COMPRESSION_ASTC_HDR, DEVICE, 11.0, 13.0) +MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR, DEVICE, 10.11, 8.0) +MVK_EXTENSION(AMD_draw_indirect_count, AMD_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA) +MVK_EXTENSION(AMD_gpu_shader_half_float, AMD_GPU_SHADER_HALF_FLOAT, DEVICE, 10.11, 8.0) +MVK_EXTENSION(AMD_negative_viewport_height, AMD_NEGATIVE_VIEWPORT_HEIGHT, DEVICE, 10.11, 8.0) +MVK_EXTENSION(AMD_shader_image_load_store_lod, AMD_SHADER_IMAGE_LOAD_STORE_LOD, DEVICE, 11.0, 8.0) +MVK_EXTENSION(AMD_shader_trinary_minmax, AMD_SHADER_TRINARY_MINMAX, DEVICE, 10.14, 12.0) +MVK_EXTENSION(IMG_format_pvrtc, IMG_FORMAT_PVRTC, DEVICE, 11.0, 8.0) +MVK_EXTENSION(INTEL_shader_integer_functions2, INTEL_SHADER_INTEGER_FUNCTIONS_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(GOOGLE_display_timing, GOOGLE_DISPLAY_TIMING, DEVICE, 10.11, 8.0) +MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, INSTANCE, MVK_NA, 8.0) +MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, INSTANCE, 10.11, MVK_NA) +MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, INSTANCE, 10.11, 8.0) +MVK_EXTENSION(NV_fragment_shader_barycentric, NV_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0) +MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER, DEVICE, 10.11, 8.0) #undef MVK_EXTENSION #undef MVK_EXTENSION_LAST From e7243572d77125b825c00867aa71ba1c74c65a0c Mon Sep 17 00:00:00 2001 From: Raafat Akkad Date: Sat, 10 Jun 2023 14:30:19 +0100 Subject: [PATCH 39/74] Allows maximizing the concurrent executing compilation tasks. https://developer.apple.com/videos/play/wwdc2023/10127/?time=540 On an M1 Pro Macbook Pro 16" maximumConcurrentCompilationTaskCount goes from 2 to 8 --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/API/mvk_config.h | 10 ++++++++++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 10 ++++++++++ MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp | 1 + MoltenVK/MoltenVK/Utility/MVKEnvironment.h | 8 ++++++++ 6 files changed, 31 insertions(+) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 389eebd87..532de997e 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -23,6 +23,7 @@ Released TBD - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. - Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. - Add support for `VK_PRESENT_MODE_IMMEDIATE_KHR` to macOS Cube demo. +- Allows maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index c224fa106..360007e16 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -913,6 +913,16 @@ typedef struct { */ MVKConfigCompressionAlgorithm shaderSourceCompressionAlgorithm; + /** + * Maximize the concurrent executing compilation tasks. + * + * 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; + } MVKConfiguration; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 037d70173..9fa474941 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -404,6 +404,7 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { MTLFeatureSet getMaximalMTLFeatureSet(); void initMetalFeatures(); void initFeatures(); + void initMTLDevice(); void initProperties(); void initLimits(); void initGPUInfoProperties(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 810ad8918..4decedf21 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1596,6 +1596,7 @@ _supportedExtensions(this, true), _pixelFormats(this) { // Set after _mtlDevice + initMTLDevice(); initProperties(); // Call first. initMetalFeatures(); // Call second. initFeatures(); // Call third. @@ -1608,6 +1609,15 @@ logGPUInfo(); } +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); + } +#endif +} + // Initializes the physical device properties (except limits). void MVKPhysicalDevice::initProperties() { mvkClear(&_properties); // Start with everything cleared diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp index 1381c616b..5aa6f7dbc 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp @@ -63,6 +63,7 @@ static void mvkInitConfigFromEnvVars() { MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.resumeLostDevice, MVK_CONFIG_RESUME_LOST_DEVICE); MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.useMetalArgumentBuffers, MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS); MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.shaderSourceCompressionAlgorithm, MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM); + MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.shouldMaximizeConcurrentCompilation, MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION); // 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, diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h index 68ef83a9d..86215bf9f 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h @@ -295,3 +295,11 @@ void mvkSetConfig(const MVKConfiguration& mvkConfig); #ifndef MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM # define MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM MVK_CONFIG_COMPRESSION_ALGORITHM_NONE #endif + +/** + * Maximize the concurrent executing compilation tasks. + * This functionality requires macOS 13.3. Disabled by default. + */ +#ifndef MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION +# define MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION 0 +#endif From b94553dbb3d731f7b61d98e2ee91f6465469326a Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 14 Jun 2023 18:49:40 -0400 Subject: [PATCH 40/74] Allow both renderPass and VkPipelineRenderingCreateInfo to be missing. This avoids crashes in CTS when creating a graphics pipeline. --- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 39b684892..f8142936c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -378,7 +378,10 @@ #pragma mark Construction -// Extracts and returns a VkPipelineRenderingCreateInfo from the renderPass or pNext chain of pCreateInfo, or returns null if not found +// Extracts and returns a VkPipelineRenderingCreateInfo from the renderPass or pNext +// chain of pCreateInfo, or returns an empty struct if neither of those are found. +// Although the Vulkan spec is vague and unclear, there are CTS that set both renderPass +// and VkPipelineRenderingCreateInfo to null in VkGraphicsPipelineCreateInfo. static const VkPipelineRenderingCreateInfo* getRenderingCreateInfo(const VkGraphicsPipelineCreateInfo* pCreateInfo) { if (pCreateInfo->renderPass) { return ((MVKRenderPass*)pCreateInfo->renderPass)->getSubpass(pCreateInfo->subpass)->getPipelineRenderingCreateInfo(); @@ -389,7 +392,8 @@ default: break; } } - return nullptr; + static VkPipelineRenderingCreateInfo emptyRendInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO }; + return &emptyRendInfo; } MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, From 425505da47d2d999a1697dfc4011570113181ebc Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 15 Jun 2023 17:24:50 -0400 Subject: [PATCH 41/74] Don't call MTLCreateSystemDefaultDevice() on every swapchain creation. - When forcing the window system to use the same high-power GPU as the app, move the call to MTLCreateSystemDefaultDevice() to MVKDevice constructor, instead of MVKDevice::createSwapchain(), and test whether the VK_KHR_swapchain extension is enabled to determine the need to swap GPUs. - After calling MTLCreateSystemDefaultDevice() the GPU will already be the same high-power GPU, so remove attempting to replace the MTLDevice. - Remove MVKPhysicalDevice::replaceMTLDevice() as no longer used. - Remove many unnecessary inline declarations in MVKDevice.h (unrelated). --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 50 ++++++++++------------- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 26 ++++++------ 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 9fa474941..e14320bd0 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -138,7 +138,7 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { void getProperties(VkPhysicalDeviceProperties2* properties); /** Returns the name of this device. */ - inline const char* getName() { return _properties.deviceName; } + const char* getName() { return _properties.deviceName; } /** Populates the specified structure with the format properties of this device. */ void getFormatProperties(VkFormat format, VkFormatProperties* pFormatProperties); @@ -285,7 +285,7 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { #pragma mark Memory models /** Returns a pointer to the memory characteristics of this device. */ - inline const VkPhysicalDeviceMemoryProperties* getMemoryProperties() { return &_memoryProperties; } + const VkPhysicalDeviceMemoryProperties* getMemoryProperties() { return &_memoryProperties; } /** Populates the specified memory properties with the memory characteristics of this device. */ VkResult getMemoryProperties(VkPhysicalDeviceMemoryProperties* pMemoryProperties); @@ -297,31 +297,31 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { * Returns a bit mask of all memory type indices. * Each bit [0..31] in the returned bit mask indicates a distinct memory type. */ - inline uint32_t getAllMemoryTypes() { return _allMemoryTypes; } + uint32_t getAllMemoryTypes() { return _allMemoryTypes; } /** * Returns a bit mask of all memory type indices that allow host visibility to the memory. * Each bit [0..31] in the returned bit mask indicates a distinct memory type. */ - inline uint32_t getHostVisibleMemoryTypes() { return _hostVisibleMemoryTypes; } + uint32_t getHostVisibleMemoryTypes() { return _hostVisibleMemoryTypes; } /** * Returns a bit mask of all memory type indices that are coherent between host and device. * Each bit [0..31] in the returned bit mask indicates a distinct memory type. */ - inline uint32_t getHostCoherentMemoryTypes() { return _hostCoherentMemoryTypes; } + uint32_t getHostCoherentMemoryTypes() { return _hostCoherentMemoryTypes; } /** * Returns a bit mask of all memory type indices that do NOT allow host visibility to the memory. * Each bit [0..31] in the returned bit mask indicates a distinct memory type. */ - inline uint32_t getPrivateMemoryTypes() { return _privateMemoryTypes; } + uint32_t getPrivateMemoryTypes() { return _privateMemoryTypes; } /** * Returns a bit mask of all memory type indices that are lazily allocated. * Each bit [0..31] in the returned bit mask indicates a distinct memory type. */ - inline uint32_t getLazilyAllocatedMemoryTypes() { return _lazilyAllocatedMemoryTypes; } + uint32_t getLazilyAllocatedMemoryTypes() { return _lazilyAllocatedMemoryTypes; } /** Returns whether this is a unified memory device. */ bool getHasUnifiedMemory(); @@ -336,21 +336,13 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { #pragma mark Metal /** Populates the specified structure with the Metal-specific features of this device. */ - inline const MVKPhysicalDeviceMetalFeatures* getMetalFeatures() { return &_metalFeatures; } + const MVKPhysicalDeviceMetalFeatures* getMetalFeatures() { return &_metalFeatures; } /** Returns whether or not vertex instancing can be used to implement multiview. */ - inline bool canUseInstancingForMultiview() { return _metalFeatures.layeredRendering && _metalFeatures.deferredStoreActions; } + bool canUseInstancingForMultiview() { return _metalFeatures.layeredRendering && _metalFeatures.deferredStoreActions; } /** Returns the underlying Metal device. */ - inline id getMTLDevice() { return _mtlDevice; } - - /*** Replaces the underlying Metal device .*/ - inline void replaceMTLDevice(id mtlDevice) { - if (mtlDevice != _mtlDevice) { - [_mtlDevice release]; - _mtlDevice = [mtlDevice retain]; - } - } + id getMTLDevice() { return _mtlDevice; } /** Returns whether the MSL version is supported on this device. */ bool mslVersionIsAtLeast(MTLLanguageVersion minVer) { return _metalFeatures.mslVersionEnum >= minVer; } @@ -387,7 +379,7 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { * Returns a reference to this object suitable for use as a Vulkan API handle. * This is the compliment of the getMVKPhysicalDevice() method. */ - inline VkPhysicalDevice getVkPhysicalDevice() { return (VkPhysicalDevice)getVkHandle(); } + VkPhysicalDevice getVkPhysicalDevice() { return (VkPhysicalDevice)getVkHandle(); } /** * Retrieves the MVKPhysicalDevice instance referenced by the VkPhysicalDevice handle. @@ -475,16 +467,16 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { MVKInstance* getInstance() override { return _physicalDevice->getInstance(); } /** Returns the physical device underlying this logical device. */ - inline MVKPhysicalDevice* getPhysicalDevice() { return _physicalDevice; } + MVKPhysicalDevice* getPhysicalDevice() { return _physicalDevice; } /** Returns info about the pixel format supported by the physical device. */ - inline MVKPixelFormats* getPixelFormats() { return &_physicalDevice->_pixelFormats; } + MVKPixelFormats* getPixelFormats() { return &_physicalDevice->_pixelFormats; } /** Returns the name of this device. */ - inline const char* getName() { return _pProperties->deviceName; } + const char* getName() { return _pProperties->deviceName; } /** Returns the common resource factory for creating command resources. */ - inline MVKCommandResourceFactory* getCommandResourceFactory() { return _commandResourceFactory; } + MVKCommandResourceFactory* getCommandResourceFactory() { return _commandResourceFactory; } /** Returns the function pointer corresponding to the specified named entry point. */ PFN_vkVoidFunction getProcAddr(const char* pName); @@ -699,7 +691,7 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { * number of nanoseconds between the two calls. The convenience function mvkGetElapsedMilliseconds() * can be used to perform this calculation. */ - inline uint64_t getPerformanceTimestamp() { return _isPerformanceTracking ? mvkGetTimestamp() : 0; } + uint64_t getPerformanceTimestamp() { return _isPerformanceTracking ? mvkGetTimestamp() : 0; } /** * If performance is being tracked, adds the performance for an activity with a duration @@ -707,8 +699,8 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { * * If endTime is zero or not supplied, the current time is used. */ - inline void addActivityPerformance(MVKPerformanceTracker& activityTracker, - uint64_t startTime, uint64_t endTime = 0) { + void addActivityPerformance(MVKPerformanceTracker& activityTracker, + uint64_t startTime, uint64_t endTime = 0) { if (_isPerformanceTracking) { updateActivityPerformance(activityTracker, startTime, endTime); @@ -742,7 +734,7 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { #pragma mark Metal /** Returns the underlying Metal device. */ - inline id getMTLDevice() { return _physicalDevice->getMTLDevice(); } + id getMTLDevice() { return _physicalDevice->getMTLDevice(); } /** Returns whether this device is using Metal argument buffers. */ bool isUsingMetalArgumentBuffers() { return _isUsingMetalArgumentBuffers; }; @@ -818,7 +810,7 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { void stopAutoGPUCapture(MVKConfigAutoGPUCaptureScope autoGPUCaptureScope); /** Returns whether this instance is currently automatically capturing a GPU trace. */ - inline bool isCurrentlyAutoGPUCapturing() { return _isCurrentlyAutoGPUCapturing; } + bool isCurrentlyAutoGPUCapturing() { return _isCurrentlyAutoGPUCapturing; } /** Returns the Metal objects underpinning the Vulkan objects indicated in the pNext chain of pMetalObjectsInfo. */ void getMetalObjects(VkExportMetalObjectsInfoEXT* pMetalObjectsInfo); @@ -866,7 +858,7 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { * Returns a reference to this object suitable for use as a Vulkan API handle. * This is the compliment of the getMVKDevice() method. */ - inline VkDevice getVkDevice() { return (VkDevice)getVkHandle(); } + VkDevice getVkDevice() { return (VkDevice)getVkHandle(); } /** * Retrieves the MVKDevice instance referenced by the VkDevice handle. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 4decedf21..93adca539 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -3629,20 +3629,6 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope MVKSwapchain* MVKDevice::createSwapchain(const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator) { -#if MVK_MACOS - // If we have selected a high-power GPU and want to force the window system - // to use it, force the window system to use a high-power GPU by calling the - // MTLCreateSystemDefaultDevice function, and if that GPU is the same as the - // selected GPU, update the MTLDevice instance used by the MVKPhysicalDevice. - id mtlDevice = _physicalDevice->getMTLDevice(); - if (mvkConfig().switchSystemGPU && !(mtlDevice.isLowPower || mtlDevice.isHeadless) ) { - id sysMTLDevice = MTLCreateSystemDefaultDevice(); - if (mvkGetRegistryID(sysMTLDevice) == mvkGetRegistryID(mtlDevice)) { - _physicalDevice->replaceMTLDevice(sysMTLDevice); - } - } -#endif - return new MVKSwapchain(this, pCreateInfo); } @@ -4488,6 +4474,18 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope initQueues(pCreateInfo); reservePrivateData(pCreateInfo); +#if MVK_MACOS + // After enableExtensions + // If the VK_KHR_swapchain extension is enabled, we expect to render to the screen. + // 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 && + !(_physicalDevice->_mtlDevice.isLowPower || _physicalDevice->_mtlDevice.isHeadless) ) { + MTLCreateSystemDefaultDevice(); + } +#endif + // After enableExtensions && enableFeatures // 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. From e69c249348d82351689fdcfbb32e4af58e924a2b Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 15 Jun 2023 19:56:36 -0400 Subject: [PATCH 42/74] Log more info about SPIR-V to MSL conversion errors. Remove unhelpful "Shader module does not contain an entry point named 'main0'" error message. --- Docs/Whats_New.md | 3 ++- MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm | 2 -- .../MoltenVKShaderConverter/SPIRVToMSLConverter.cpp | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 532de997e..e96a4d081 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -22,8 +22,9 @@ Released TBD - `VK_EXT_shader_demote_to_helper_invocation` - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. - Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. +- Support maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` - Add support for `VK_PRESENT_MODE_IMMEDIATE_KHR` to macOS Cube demo. -- Allows maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` +- Log more info about SPIR-V to MSL conversion errors. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm index 2eb57ebb4..12ddbf4c5 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm @@ -111,8 +111,6 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD mtlFunc = [fs.newMTLFunction(_mtlLibrary, mtlFuncName, mtlFCVals) autorelease]; } } - } else { - reportError(VK_ERROR_INVALID_SHADER_NV, "Shader module does not contain an entry point named '%s'.", mtlFuncName.UTF8String); } // Set the debug name. First try name of shader module, otherwise try name of owner. diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp index b95b704db..ced660aa8 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp +++ b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp @@ -344,7 +344,7 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConversionConfigur #ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS } catch (CompilerError& ex) { - string errMsg("MSL conversion error: "); + string errMsg("SPIR-V to MSL conversion error: "); errMsg += ex.what(); logError(conversionResult.resultLog, errMsg.data()); if (shouldLogMSL && pMSLCompiler) { @@ -446,6 +446,7 @@ void SPIRVToMSLConverter::logMsg(string& log, const char* logMsg) { // Appends the error text to the result log, and returns false to indicate an error. bool SPIRVToMSLConverter::logError(string& log, const char* errMsg) { logMsg(log, errMsg); + fprintf(stderr, "[mvk-error] %s\n", errMsg); return false; } From 33cd6f24c4a1bf6f8250189253bb852290377fb3 Mon Sep 17 00:00:00 2001 From: Antarctic Coder Date: Mon, 19 Jun 2023 15:18:15 -0400 Subject: [PATCH 43/74] Implemented Deferred Host Operations Implemented deferred host operations in this commit. It was pretty simple with nothing Metal specific. I am a bit concerned on the return types of MVKDeferredOperation::join and about how to store the operation to be executed for later. --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 5 ++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 9 +++ MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 5 ++ MoltenVK/MoltenVK/GPUObjects/MVKSync.h | 53 ++++++++++++++++++ MoltenVK/MoltenVK/GPUObjects/MVKSync.mm | 18 ++++++ MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Vulkan/vulkan.mm | 61 +++++++++++++++++++++ 7 files changed, 152 insertions(+) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index e14320bd0..f4b4660aa 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -50,6 +50,7 @@ class MVKSwapchain; class MVKDeviceMemory; class MVKFence; class MVKSemaphore; +class MVKDeferredOperation; class MVKTimelineSemaphore; class MVKEvent; class MVKSemaphoreImpl; @@ -557,6 +558,10 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { const VkAllocationCallbacks* pAllocator); void destroySemaphore(MVKSemaphore* mvkSem4, const VkAllocationCallbacks* pAllocator); + + MVKDeferredOperation* createDeferredOperation(const VkAllocationCallbacks* pAllocator); + void destroyDeferredOperation(MVKDeferredOperation* mvkDeferredOperation, + const VkAllocationCallbacks* pAllocator); MVKEvent* createEvent(const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 93adca539..49efde1ac 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -3699,6 +3699,15 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope } } +MVKDeferredOperation* MVKDevice::createDeferredOperation(const VkAllocationCallbacks* pAllocator) { + return new MVKDeferredOperation(this); +} + +void MVKDevice::destroyDeferredOperation(MVKDeferredOperation* mvkDeferredOperation, + const VkAllocationCallbacks* pAllocator) { + if(mvkDeferredOperation) { mvkDeferredOperation->destroy(); } +} + void MVKDevice::destroySemaphore(MVKSemaphore* mvkSem4, const VkAllocationCallbacks* pAllocator) { if (mvkSem4) { mvkSem4->destroy(); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 6b5d2df87..902f767a9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -731,6 +731,11 @@ ADD_DVC_EXT2_ENTRY_POINT(vkGetDeviceGroupSurfacePresentModesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); ADD_DVC_EXT2_ENTRY_POINT(vkGetPhysicalDevicePresentRectanglesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); ADD_DVC_EXT2_ENTRY_POINT(vkAcquireNextImage2KHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); + ADD_DVC_EXT_ENTRY_POINT(vkCreateDeferredOperationKHR, KHR_DEFERRED_HOST_OPERATIONS); + ADD_DVC_EXT_ENTRY_POINT(vkDeferredOperationJoinKHR, KHR_DEFERRED_HOST_OPERATIONS); + ADD_DVC_EXT_ENTRY_POINT(vkDestroyDeferredOperationKHR, KHR_DEFERRED_HOST_OPERATIONS); + ADD_DVC_EXT_ENTRY_POINT(vkGetDeferredOperationMaxConcurrencyKHR, KHR_DEFERRED_HOST_OPERATIONS); + ADD_DVC_EXT_ENTRY_POINT(vkGetDeferredOperationResultKHR, KHR_DEFERRED_HOST_OPERATIONS); ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectTagEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectNameEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerBeginEXT, EXT_DEBUG_MARKER); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h index 5dfe1d29c..5e964c316 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h @@ -636,3 +636,56 @@ class MVKMetalCompiler : public MVKBaseObject { std::string _compilerType = "Unknown"; MVKPerformanceTracker* _pPerformanceTracker = nullptr; }; + +#pragma mark - +#pragma mark MVKDeferredOperation + +/** Defines the function pointer for each dependent function*/ +union MVKDeferredOperationFunctionPointer +{ + // Empty until deferred functions from other extensions have been defined + // Planning to use std::functions +}; + +/** Manages what function is being deferred*/ +enum MVKDeferredOperationFunctionType +{ + // Empty until deferred functions from other extensions have been defined +}; + +class MVKDeferredOperation : public MVKVulkanAPIDeviceObject { +public: + /** Returns the Vulkan type of this object. */ + VkObjectType getVkObjectType() override { return VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR; } + + /** Returns the debug report object type of this object. */ + VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; } + + /** Joins the deferred operation */ + VkResult join(); + + /** Gets the max number of threads that can execute the deferred operation concurrently*/ + uint32_t getMaxConcurrency() { return 1; } // Perhaps the number of CPU cores + + /** Gets the result of the execution of the deferred operation */ + VkResult getResult() { return operationResult; } + + /** Sets all the variables needed for a deferred operation, however should never be called manually and only from other functions that take deferred operations*/ + void deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, std::vector parameters); +#pragma mark Construction + MVKDeferredOperation(MVKDevice* device) : MVKVulkanAPIDeviceObject(device) {} +protected: + /** Stores the result of the operation*/ + VkResult operationResult = VK_SUCCESS; + + /** Stores a pointer to the function*/ + MVKDeferredOperationFunctionPointer functionPointer; + + /** Stores what functions is being deferred*/ + MVKDeferredOperationFunctionType functionType; + + /** The parameters in the operation being deferred*/ + std::vector functionParameters = {}; + + void propagateDebugName() override {} +}; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index 47bf78a23..98eaae84c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -620,5 +620,23 @@ VkResult mvkWaitSemaphores(MVKDevice* device, [_compileError release]; } +#pragma mark - +#pragma mark MVKDeferredOperation +VkResult MVKDeferredOperation::join() { + VkResult opResult; + switch(functionType) + { + // Set operation result here by calling operation + default: return VK_THREAD_DONE_KHR; + }; + operationResult = opResult; + return VK_SUCCESS; +} +void MVKDeferredOperation::deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, std::vector parameters) +{ + functionPointer = pointer; + functionType = type; + functionParameters = parameters; +} diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index a50b3bb58..6a8bf8f03 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -48,6 +48,7 @@ MVK_EXTENSION(KHR_buffer_device_address, KHR_BUFFER_DEVICE_ADDRESS, MVK_EXTENSION(KHR_copy_commands2, KHR_COPY_COMMANDS_2, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_create_renderpass2, KHR_CREATE_RENDERPASS_2, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_dedicated_allocation, KHR_DEDICATED_ALLOCATION, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_deferred_host_operations, KHR_DEFERRED_HOST_OPERATIONS, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_depth_stencil_resolve, KHR_DEPTH_STENCIL_RESOLVE, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, DEVICE, 10.11, 8.0) diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index be2307cbb..5fe0958f5 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -2653,6 +2653,67 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdResolveImage2( MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdNextSubpass2, KHR); MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdEndRenderPass2, KHR); +#pragma mark - +#pragma mark VK_KHR_deferred_host_operations extension + +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCreateDeferredOperationKHR( + VkDevice device, + const VkAllocationCallbacks* pAllocator, + VkDeferredOperationKHR* pDeferredOperation) { + + MVKTraceVulkanCallStart(); + MVKDevice* mvkDev = MVKDevice::getMVKDevice(device); + MVKDeferredOperation* mvkDeferredOperation = mvkDev->createDeferredOperation(pAllocator); + *pDeferredOperation = (VkDeferredOperationKHR)mvkDeferredOperation; + VkResult rslt = mvkDeferredOperation->getConfigurationResult(); + MVKTraceVulkanCallEnd(); + return rslt; +} + +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetDeferredOperationResultKHR( + VkDevice device, + VkDeferredOperationKHR operation) { + + MVKTraceVulkanCallStart(); + MVKDeferredOperation* mvkDeferredOperation = (MVKDeferredOperation*)operation; + VkResult rslt = mvkDeferredOperation->getResult(); + MVKTraceVulkanCallEnd(); + return rslt; +} + +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkDeferredOperationJoinKHR( + VkDevice device, + VkDeferredOperationKHR operation) { + + MVKTraceVulkanCallStart(); + MVKDeferredOperation* mvkDeferredOperation = (MVKDeferredOperation*)operation; + VkResult rslt = mvkDeferredOperation->join(); + MVKTraceVulkanCallEnd(); + return rslt; +} + +MVK_PUBLIC_VULKAN_SYMBOL uint32_t vkGetDeferredOperationMaxConcurrencyKHR( + VkDevice device, + VkDeferredOperationKHR operation) { + + MVKTraceVulkanCallStart(); + MVKDeferredOperation* mvkDeferredOperation = (MVKDeferredOperation*)operation; + uint32_t getMaxConcurrencyKHR = mvkDeferredOperation->getMaxConcurrency(); + MVKTraceVulkanCallEnd(); + return getMaxConcurrencyKHR; +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkDestroyDeferredOperationKHR( + VkDevice device, + VkDeferredOperationKHR operation, + const VkAllocationCallbacks* pAllocator) { + + MVKTraceVulkanCallStart(); + MVKDevice* mvkDev = MVKDevice::getMVKDevice(device); + MVKDeferredOperation* mvkDeferredOperation = (MVKDeferredOperation*)operation; + mvkDev->destroyDeferredOperation(mvkDeferredOperation, pAllocator); + MVKTraceVulkanCallEnd(); +} #pragma mark - #pragma mark VK_KHR_dynamic_rendering extension From ab7087165af5e765b83353ac5365cab1598409bd Mon Sep 17 00:00:00 2001 From: Antarctic Coder <79386484+AntarticCoder@users.noreply.github.com> Date: Tue, 20 Jun 2023 08:28:59 -0400 Subject: [PATCH 44/74] Fixed comments for deferred operations Co-authored-by: Chip Davis --- MoltenVK/MoltenVK/GPUObjects/MVKSync.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h index 5e964c316..10735d039 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h @@ -640,14 +640,14 @@ class MVKMetalCompiler : public MVKBaseObject { #pragma mark - #pragma mark MVKDeferredOperation -/** Defines the function pointer for each dependent function*/ +/** Defines the function pointer for each dependent function. */ union MVKDeferredOperationFunctionPointer { // Empty until deferred functions from other extensions have been defined // Planning to use std::functions }; -/** Manages what function is being deferred*/ +/** Indicates what kind of function is being deferred. */ enum MVKDeferredOperationFunctionType { // Empty until deferred functions from other extensions have been defined @@ -661,7 +661,7 @@ class MVKDeferredOperation : public MVKVulkanAPIDeviceObject { /** Returns the debug report object type of this object. */ VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; } - /** Joins the deferred operation */ + /** Begins executing the deferred operation on the current thread. */ VkResult join(); /** Gets the max number of threads that can execute the deferred operation concurrently*/ From c0705c8f7dbcb6150ee2d4eb92d482a89c9d9734 Mon Sep 17 00:00:00 2001 From: Antarctic Coder Date: Tue, 20 Jun 2023 10:19:29 -0400 Subject: [PATCH 45/74] Made some fixes for Deferred Operations The changes are as follows: * Moved the code around to fit with the ordering system * Added a function to get available cpu cores * Renamed variables with _ in front of them * Added mutexes and lock guards for the getters and setters of the max concurrency and result variables * Made max concurrency dynamic by returning 0 when the operation is finished --- Common/MVKOSExtensions.h | 6 +++++ Common/MVKOSExtensions.mm | 7 ++++++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 10 ++++---- MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 10 ++++---- MoltenVK/MoltenVK/GPUObjects/MVKSync.h | 27 +++++++++++++++------ MoltenVK/MoltenVK/GPUObjects/MVKSync.mm | 24 +++++++++++++----- MoltenVK/MoltenVK/Vulkan/vulkan.mm | 12 ++++----- 8 files changed, 67 insertions(+), 31 deletions(-) diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h index fde73c5c1..237083258 100644 --- a/Common/MVKOSExtensions.h +++ b/Common/MVKOSExtensions.h @@ -164,3 +164,9 @@ 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(); diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 6c023086a..ef98f0b5e 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -138,3 +138,10 @@ uint64_t mvkGetUsedMemorySize() { uint64_t mvkGetHostMemoryPageSize() { return sysconf(_SC_PAGESIZE); } +#pragma mark - +#pragma mark Threading + +/** Returns the amount of avaliable CPU cores. */ +uint32_t mvkGetAvaliableCPUCores() { + return (uint32_t)[[NSProcessInfo processInfo] activeProcessorCount]; +} diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index f4b4660aa..d136d7d58 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -50,8 +50,8 @@ class MVKSwapchain; class MVKDeviceMemory; class MVKFence; class MVKSemaphore; -class MVKDeferredOperation; class MVKTimelineSemaphore; +class MVKDeferredOperation; class MVKEvent; class MVKSemaphoreImpl; class MVKQueryPool; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 49efde1ac..23109a225 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -3699,6 +3699,11 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope } } +void MVKDevice::destroySemaphore(MVKSemaphore* mvkSem4, + const VkAllocationCallbacks* pAllocator) { + if (mvkSem4) { mvkSem4->destroy(); } +} + MVKDeferredOperation* MVKDevice::createDeferredOperation(const VkAllocationCallbacks* pAllocator) { return new MVKDeferredOperation(this); } @@ -3708,11 +3713,6 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope if(mvkDeferredOperation) { mvkDeferredOperation->destroy(); } } -void MVKDevice::destroySemaphore(MVKSemaphore* mvkSem4, - const VkAllocationCallbacks* pAllocator) { - if (mvkSem4) { mvkSem4->destroy(); } -} - MVKEvent* MVKDevice::createEvent(const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator) { const VkExportMetalObjectCreateInfoEXT* pExportInfo = nullptr; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 902f767a9..240e1cfe3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -718,6 +718,11 @@ ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkSetPrivateData, EXT, EXT_PRIVATE_DATA); // Device extension functions. + ADD_DVC_EXT_ENTRY_POINT(vkCreateDeferredOperationKHR, KHR_DEFERRED_HOST_OPERATIONS); + ADD_DVC_EXT_ENTRY_POINT(vkDeferredOperationJoinKHR, KHR_DEFERRED_HOST_OPERATIONS); + ADD_DVC_EXT_ENTRY_POINT(vkDestroyDeferredOperationKHR, KHR_DEFERRED_HOST_OPERATIONS); + ADD_DVC_EXT_ENTRY_POINT(vkGetDeferredOperationMaxConcurrencyKHR, KHR_DEFERRED_HOST_OPERATIONS); + ADD_DVC_EXT_ENTRY_POINT(vkGetDeferredOperationResultKHR, KHR_DEFERRED_HOST_OPERATIONS); ADD_DVC_EXT_ENTRY_POINT(vkMapMemory2KHR, KHR_MAP_MEMORY_2); ADD_DVC_EXT_ENTRY_POINT(vkUnmapMemory2KHR, KHR_MAP_MEMORY_2); ADD_DVC_EXT_ENTRY_POINT(vkCmdPushDescriptorSetKHR, KHR_PUSH_DESCRIPTOR); @@ -731,11 +736,6 @@ ADD_DVC_EXT2_ENTRY_POINT(vkGetDeviceGroupSurfacePresentModesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); ADD_DVC_EXT2_ENTRY_POINT(vkGetPhysicalDevicePresentRectanglesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); ADD_DVC_EXT2_ENTRY_POINT(vkAcquireNextImage2KHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); - ADD_DVC_EXT_ENTRY_POINT(vkCreateDeferredOperationKHR, KHR_DEFERRED_HOST_OPERATIONS); - ADD_DVC_EXT_ENTRY_POINT(vkDeferredOperationJoinKHR, KHR_DEFERRED_HOST_OPERATIONS); - ADD_DVC_EXT_ENTRY_POINT(vkDestroyDeferredOperationKHR, KHR_DEFERRED_HOST_OPERATIONS); - ADD_DVC_EXT_ENTRY_POINT(vkGetDeferredOperationMaxConcurrencyKHR, KHR_DEFERRED_HOST_OPERATIONS); - ADD_DVC_EXT_ENTRY_POINT(vkGetDeferredOperationResultKHR, KHR_DEFERRED_HOST_OPERATIONS); ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectTagEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectNameEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerBeginEXT, EXT_DEBUG_MARKER); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h index 10735d039..646fed894 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h @@ -665,27 +665,40 @@ class MVKDeferredOperation : public MVKVulkanAPIDeviceObject { VkResult join(); /** Gets the max number of threads that can execute the deferred operation concurrently*/ - uint32_t getMaxConcurrency() { return 1; } // Perhaps the number of CPU cores + uint32_t getMaxConcurrency() { + std::lock_guard lock(_maxConcurrencyLock); + return _maxConcurrency; + } /** Gets the result of the execution of the deferred operation */ - VkResult getResult() { return operationResult; } + VkResult getResult() { + std::lock_guard lock(_resultLock); + return _operationResult; + } /** Sets all the variables needed for a deferred operation, however should never be called manually and only from other functions that take deferred operations*/ - void deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, std::vector parameters); + void deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, std::vector&& parameters); #pragma mark Construction MVKDeferredOperation(MVKDevice* device) : MVKVulkanAPIDeviceObject(device) {} protected: /** Stores the result of the operation*/ - VkResult operationResult = VK_SUCCESS; + VkResult _operationResult = VK_SUCCESS; + /** The mutex for the operation result being used to ensure thread safety. */ + std::mutex _resultLock; /** Stores a pointer to the function*/ - MVKDeferredOperationFunctionPointer functionPointer; + MVKDeferredOperationFunctionPointer _functionPointer; /** Stores what functions is being deferred*/ - MVKDeferredOperationFunctionType functionType; + MVKDeferredOperationFunctionType _functionType; /** The parameters in the operation being deferred*/ - std::vector functionParameters = {}; + std::vector _functionParameters = {}; + + /** Stores the max amount of threads that should be used.. */ + uint32_t _maxConcurrency = 0; + /** The mutex for the max concurrency being used to ensure thread safety. */ + std::mutex _maxConcurrencyLock; void propagateDebugName() override {} }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index 98eaae84c..4ab8375bf 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -625,18 +625,30 @@ VkResult mvkWaitSemaphores(MVKDevice* device, VkResult MVKDeferredOperation::join() { VkResult opResult; - switch(functionType) + switch(_functionType) { // Set operation result here by calling operation default: return VK_THREAD_DONE_KHR; }; - operationResult = opResult; + + _resultLock.lock(); + _operationResult = opResult; + _resultLock.unlock(); + + _maxConcurrencyLock.lock(); + _maxConcurrency = 0; + _maxConcurrencyLock.unlock(); + return VK_SUCCESS; } -void MVKDeferredOperation::deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, std::vector parameters) +void MVKDeferredOperation::deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, std::vector&& parameters) { - functionPointer = pointer; - functionType = type; - functionParameters = parameters; + _functionPointer = pointer; + _functionType = type; + _functionParameters = parameters; + + _maxConcurrencyLock.lock(); + _maxConcurrency = mvkGetAvaliableCPUCores(); + _maxConcurrencyLock.unlock(); } diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index 5fe0958f5..39f8b02e1 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -2715,13 +2715,6 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkDestroyDeferredOperationKHR( MVKTraceVulkanCallEnd(); } -#pragma mark - -#pragma mark VK_KHR_dynamic_rendering extension - -MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdBeginRendering, KHR); -MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdEndRendering, KHR); - - #pragma mark - #pragma mark VK_KHR_descriptor_update_template extension @@ -2750,6 +2743,11 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkDestroyDeferredOperationKHR( MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdDrawIndexedIndirectCount, KHR); MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdDrawIndirectCount, KHR); +#pragma mark - +#pragma mark VK_KHR_dynamic_rendering extension + +MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdBeginRendering, KHR); +MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdEndRendering, KHR); #pragma mark - #pragma mark VK_KHR_external_fence_capabilities extension From fa19fcc962e258527408e1f733df0a67881d2b77 Mon Sep 17 00:00:00 2001 From: Antarctic Coder Date: Tue, 20 Jun 2023 13:11:54 -0400 Subject: [PATCH 46/74] Push to Compile MVKSmallVector with void* Pushing to Github to compile with Github Actions to see if MVKVectors with void* can work --- MoltenVK/MoltenVK/GPUObjects/MVKSync.h | 4 ++-- MoltenVK/MoltenVK/GPUObjects/MVKSync.mm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h index 646fed894..416f4585d 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h @@ -677,7 +677,7 @@ class MVKDeferredOperation : public MVKVulkanAPIDeviceObject { } /** Sets all the variables needed for a deferred operation, however should never be called manually and only from other functions that take deferred operations*/ - void deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, std::vector&& parameters); + void deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, MVKSmallVector&& parameters); #pragma mark Construction MVKDeferredOperation(MVKDevice* device) : MVKVulkanAPIDeviceObject(device) {} protected: @@ -693,7 +693,7 @@ class MVKDeferredOperation : public MVKVulkanAPIDeviceObject { MVKDeferredOperationFunctionType _functionType; /** The parameters in the operation being deferred*/ - std::vector _functionParameters = {}; + MVKSmallVector _functionParameters = {}; /** Stores the max amount of threads that should be used.. */ uint32_t _maxConcurrency = 0; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index 4ab8375bf..855e525fd 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -642,7 +642,7 @@ VkResult mvkWaitSemaphores(MVKDevice* device, return VK_SUCCESS; } -void MVKDeferredOperation::deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, std::vector&& parameters) +void MVKDeferredOperation::deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, MVKSmallVector&& parameters) { _functionPointer = pointer; _functionType = type; From e5bfc2d66eadb12a52bb411f90b3359196113cc7 Mon Sep 17 00:00:00 2001 From: Antarctic Coder Date: Wed, 21 Jun 2023 11:00:15 -0400 Subject: [PATCH 47/74] C-Style Arrays instead of MVKSmallVector This commit changes the MVKSmallVector to a C-Style array because the parameters array will not have to resize, and it seems that a C-Style array is just as capable of doing the job. --- MoltenVK/MoltenVK/GPUObjects/MVKSync.h | 6 ++++-- MoltenVK/MoltenVK/GPUObjects/MVKSync.mm | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h index 416f4585d..a345b4c69 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h @@ -676,8 +676,10 @@ class MVKDeferredOperation : public MVKVulkanAPIDeviceObject { return _operationResult; } + static const int kMVKMaxDeferredFunctionParameters = 3; + /** Sets all the variables needed for a deferred operation, however should never be called manually and only from other functions that take deferred operations*/ - void deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, MVKSmallVector&& parameters); + void deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, void* parameters[kMVKMaxDeferredFunctionParameters]); #pragma mark Construction MVKDeferredOperation(MVKDevice* device) : MVKVulkanAPIDeviceObject(device) {} protected: @@ -693,7 +695,7 @@ class MVKDeferredOperation : public MVKVulkanAPIDeviceObject { MVKDeferredOperationFunctionType _functionType; /** The parameters in the operation being deferred*/ - MVKSmallVector _functionParameters = {}; + void* _functionParameters[kMVKMaxDeferredFunctionParameters] = {}; /** Stores the max amount of threads that should be used.. */ uint32_t _maxConcurrency = 0; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index 855e525fd..9ad3456aa 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -642,11 +642,14 @@ VkResult mvkWaitSemaphores(MVKDevice* device, return VK_SUCCESS; } -void MVKDeferredOperation::deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, MVKSmallVector&& parameters) +void MVKDeferredOperation::deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, void* parameters[kMVKMaxDeferredFunctionParameters]) { _functionPointer = pointer; _functionType = type; - _functionParameters = parameters; + + for(int i = 0; i < kMVKMaxDeferredFunctionParameters; i++) { + _functionParameters[i] = parameters[i]; + } _maxConcurrencyLock.lock(); _maxConcurrency = mvkGetAvaliableCPUCores(); From 5d173d0e093eed2b42994332ab2c735ff0c8eb8a Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Wed, 7 Jun 2023 12:58:28 -0700 Subject: [PATCH 48/74] Support the `VK_EXT_4444_formats` extension. This turned out to be a little bit more involved than I had hoped. But, with this, we can now use the `VK_FORMAT_A4R4G4B4_UNORM_PACK16` and `VK_FORMAT_A4B4G4R4_UNORM_PACK16` formats from shaders, use them as blit sources, and even clear them. Storage images and render targets of these formats aren't supported, however. To support the latter would require the insertion of a swizzle into the fragment shader before returning. The former cannot be reasonably supported. --- Docs/MoltenVK_Runtime_UserGuide.md | 1 + Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/API/mvk_datatypes.h | 9 ++ MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 20 +++- .../Commands/MVKCommandResourceFactory.h | 48 ++++++-- .../Commands/MVKCommandResourceFactory.mm | 29 ++++- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 9 ++ .../GPUObjects/MVKDeviceFeatureStructs.def | 1 + MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 3 + MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 38 ++++++ .../MoltenVK/GPUObjects/MVKPixelFormats.h | 23 ++++ .../MoltenVK/GPUObjects/MVKPixelFormats.mm | 111 +++++++++++++++--- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 39 ++++++ 14 files changed, 302 insertions(+), 31 deletions(-) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 0148448bf..3775a7493 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -350,6 +350,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_KHR_timeline_semaphore` - `VK_KHR_uniform_buffer_standard_layout` - `VK_KHR_variable_pointers` +- `VK_EXT_4444_formats` *(requires 16-bit formats and either native texture swizzling or manual swizzling to be enabled)* - `VK_EXT_buffer_device_address` *(requires GPU Tier 2 argument buffers support)* - `VK_EXT_debug_marker` - `VK_EXT_debug_report` diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index e96a4d081..1a1284e06 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -19,6 +19,7 @@ MoltenVK 1.2.5 Released TBD - Add support for extensions: + - `VK_EXT_4444_formats` - `VK_EXT_shader_demote_to_helper_invocation` - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. - Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h index c5c2e182f..f5c103b49 100644 --- a/MoltenVK/MoltenVK/API/mvk_datatypes.h +++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h @@ -227,6 +227,15 @@ MTLTextureSwizzle mvkMTLTextureSwizzleFromVkComponentSwizzle(VkComponentSwizzle /** Returns all four Metal texture swizzles from the Vulkan component mapping. */ MTLTextureSwizzleChannels mvkMTLTextureSwizzleChannelsFromVkComponentMapping(VkComponentMapping vkMapping); +/** Maps a clear color according to the specified VkComponentSwizzle. */ +float mvkVkClearColorFloatValueFromVkComponentSwizzle(float *colors, uint32_t index, VkComponentSwizzle vkSwizzle); + +/** Maps a clear color according to the specified VkComponentSwizzle. */ +uint32_t mvkVkClearColorUIntValueFromVkComponentSwizzle(uint32_t *colors, uint32_t index, VkComponentSwizzle vkSwizzle); + +/** Maps a clear color according to the specified VkComponentSwizzle. */ +int32_t mvkVkClearColorIntValueFromVkComponentSwizzle(int32_t *colors, uint32_t index, VkComponentSwizzle vkSwizzle); + #pragma mark Mipmaps diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 816dbc3ff..2c0ef5465 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -374,6 +374,7 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(region.srcSubresource.aspectMask); uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(region.dstSubresource.aspectMask); return ((_srcImage->getMTLPixelFormat(srcPlaneIndex) == _dstImage->getMTLPixelFormat(dstPlaneIndex)) && + !_srcImage->needsSwizzle() && (_dstImage->getSampleCount() == _srcImage->getSampleCount())); } @@ -456,7 +457,7 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma uint32_t copyCnt = 0; uint32_t blitCnt = 0; - // Separate BLITs into those that are really just simple texure region copies, + // Separate BLITs into those that are really just simple texture region copies, // and those that require rendering for (auto& vkIB : _vkImageBlits) { if (canCopyFormats(vkIB) && canCopy(vkIB)) { @@ -500,6 +501,15 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma id srcMTLTex = _srcImage->getMTLTexture(srcPlaneIndex); id dstMTLTex = _dstImage->getMTLTexture(dstPlaneIndex); if (blitCnt && srcMTLTex && dstMTLTex) { + if (cmdEncoder->getDevice()->_pMetalFeatures->nativeTextureSwizzle && + _srcImage->needsSwizzle()) { + // Use a view that has a swizzle on it. + srcMTLTex = [[srcMTLTex newTextureViewWithPixelFormat:srcMTLTex.pixelFormat + textureType:srcMTLTex.textureType + levels:NSMakeRange(0, srcMTLTex.mipmapLevelCount) + slices:NSMakeRange(0, srcMTLTex.arrayLength) + swizzle:_srcImage->getPixelFormats()->getMTLTextureSwizzleChannels(_srcImage->getVkFormat())] autorelease]; + } cmdEncoder->endCurrentMetalEncoding(); MTLRenderPassDescriptor* mtlRPD = [MTLRenderPassDescriptor renderPassDescriptor]; @@ -549,6 +559,14 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(_filter); blitKey.srcAspect = mvkIBR.region.srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); blitKey.dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_dstImage->getSampleCount()); + if (!cmdEncoder->getDevice()->_pMetalFeatures->nativeTextureSwizzle && + _srcImage->needsSwizzle()) { + VkComponentMapping vkMapping = _srcImage->getPixelFormats()->getVkComponentMapping(_srcImage->getVkFormat()); + blitKey.srcSwizzleR = vkMapping.r; + blitKey.srcSwizzleG = vkMapping.g; + blitKey.srcSwizzleB = vkMapping.b; + blitKey.srcSwizzleA = vkMapping.a; + } id mtlRPS = cmdEncoder->getCommandEncodingPool()->getCmdBlitImageMTLRenderPipelineState(blitKey); bool isBlittingDepth = mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_DEPTH_BIT)); bool isBlittingStencil = mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_STENCIL_BIT)); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index 1e37844f9..b7f679c7c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -37,20 +37,31 @@ class MVKQueryPool; * This structure can be used as a key in a std::map and std::unordered_map. */ typedef struct MVKRPSKeyBlitImg { - uint16_t srcMTLPixelFormat = 0; /**< as MTLPixelFormat */ - uint16_t dstMTLPixelFormat = 0; /**< as MTLPixelFormat */ - uint8_t srcMTLTextureType = 0; /**< as MTLTextureType */ + uint16_t srcMTLPixelFormat : 12; /**< as MTLPixelFormat */ + uint16_t dstMTLPixelFormat : 12; /**< as MTLPixelFormat */ + uint8_t srcMTLTextureType : 4; /**< as MTLTextureType */ + uint8_t srcFilter : 4; /**< as MTLSamplerMinMagFilter */ uint8_t srcAspect = 0; /**< as VkImageAspectFlags */ - uint8_t srcFilter = 0; /**< as MTLSamplerMinMagFilter */ uint8_t dstSampleCount = 0; + uint8_t srcSwizzleR : 4; /**< as VkComponentSwizzle */ + uint8_t srcSwizzleG : 4; /**< as VkComponentSwizzle */ + uint8_t srcSwizzleB : 4; /**< as VkComponentSwizzle */ + uint8_t srcSwizzleA : 4; /**< as VkComponentSwizzle */ + + MVKRPSKeyBlitImg() : srcMTLPixelFormat(0), dstMTLPixelFormat(0), srcMTLTextureType(0), srcFilter(0), + srcSwizzleR(0), srcSwizzleG(0), srcSwizzleB(0), srcSwizzleA(0) {} bool operator==(const MVKRPSKeyBlitImg& rhs) const { if (srcMTLPixelFormat != rhs.srcMTLPixelFormat) { return false; } if (dstMTLPixelFormat != rhs.dstMTLPixelFormat) { return false; } if (srcMTLTextureType != rhs.srcMTLTextureType) { return false; } - if (srcAspect != rhs.srcAspect) { return false; } if (srcFilter != rhs.srcFilter) { return false; } + if (srcAspect != rhs.srcAspect) { return false; } if (dstSampleCount != rhs.dstSampleCount) { return false; } + if (srcSwizzleR != rhs.srcSwizzleR) { return false; } + if (srcSwizzleG != rhs.srcSwizzleG) { return false; } + if (srcSwizzleB != rhs.srcSwizzleB) { return false; } + if (srcSwizzleA != rhs.srcSwizzleA) { return false; } return true; } @@ -70,23 +81,40 @@ typedef struct MVKRPSKeyBlitImg { srcMTLTextureType == MTLTextureType1DArray); } + VkComponentMapping getSrcSwizzle() { + return { (VkComponentSwizzle)srcSwizzleR, (VkComponentSwizzle)srcSwizzleG, + (VkComponentSwizzle)srcSwizzleB, (VkComponentSwizzle)srcSwizzleA }; + } + std::size_t hash() const { std::size_t hash = srcMTLPixelFormat; - hash <<= 16; + hash <<= 12; hash |= dstMTLPixelFormat; - hash <<= 8; + hash <<= 4; hash |= srcMTLTextureType; - hash <<= 8; - hash |= srcAspect; + hash <<= 4; + hash |= srcFilter; hash <<= 8; - hash |= srcFilter; + hash |= srcAspect; hash <<= 8; hash |= dstSampleCount; + + hash <<= 4; + hash |= srcSwizzleR; + + hash <<= 4; + hash |= srcSwizzleG; + + hash <<= 4; + hash |= srcSwizzleB; + + hash <<= 4; + hash |= srcSwizzleA; return hash; } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index 36fb03b7c..4e1ed93c0 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -167,6 +167,25 @@ return rps; } +static char getSwizzleChar(char defaultChar, VkComponentSwizzle vkSwizzle) { + switch (vkSwizzle) { + case VK_COMPONENT_SWIZZLE_IDENTITY: return defaultChar; + // FIXME: 0 and 1 (currently not used in any default swizzles) + case VK_COMPONENT_SWIZZLE_R: return 'x'; + case VK_COMPONENT_SWIZZLE_G: return 'y'; + case VK_COMPONENT_SWIZZLE_B: return 'z'; + case VK_COMPONENT_SWIZZLE_A: return 'w'; + default: return defaultChar; + } +} + +static void getSwizzleString(char swizzleStr[4], VkComponentMapping vkMapping) { + swizzleStr[0] = getSwizzleChar('x', vkMapping.r); + swizzleStr[1] = getSwizzleChar('y', vkMapping.g); + swizzleStr[2] = getSwizzleChar('z', vkMapping.b); + swizzleStr[3] = getSwizzleChar('w', vkMapping.a); +} + id MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg& blitKey) { @autoreleasepool { bool isLayeredBlit = blitKey.dstSampleCount > 1 ? _device->_pMetalFeatures->multisampleLayeredRendering : _device->_pMetalFeatures->layeredRendering; @@ -177,6 +196,7 @@ NSString* typePrefix = @"texture"; NSString* typeSuffix; NSString* coordArg; + char swizzleArg[4] = { 'x', 'y', 'z', 'w' }; if (mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_DEPTH_BIT))) { typePrefix = @"depth"; } @@ -208,6 +228,9 @@ } NSString* sliceArg = isArrayType ? (isLayeredBlit ? @", subRez.slice + varyings.v_layer" : @", subRez.slice") : @""; NSString* srcFilter = isLinearFilter ? @"linear" : @"nearest"; + if (!getDevice()->_pMetalFeatures->nativeTextureSwizzle) { + getSwizzleString(swizzleArg, blitKey.getSrcSwizzle()); + } NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ]; [msl appendLineMVK: @"#include "]; @@ -263,15 +286,15 @@ [msl appendLineMVK: @" constant TexSubrez& subRez [[buffer(0)]]) {"]; [msl appendLineMVK: @" FragmentOutputs out;"]; if (mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_DEPTH_BIT))) { - [msl appendFormat: @" out.depth = tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod));", coordArg, sliceArg]; + [msl appendFormat: @" out.depth = tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod)).%c;", coordArg, sliceArg, swizzleArg[0]]; [msl appendLineMVK]; } if (mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_STENCIL_BIT))) { - [msl appendFormat: @" out.stencil = stencilTex.sample(ce_stencil_sampler, varyings.v_texCoord%@%@, level(subRez.lod)).x;", coordArg, sliceArg]; + [msl appendFormat: @" out.stencil = stencilTex.sample(ce_stencil_sampler, varyings.v_texCoord%@%@, level(subRez.lod)).%c;", coordArg, sliceArg, swizzleArg[0]]; [msl appendLineMVK]; } if (!mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) { - [msl appendFormat: @" out.color = tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod));", coordArg, sliceArg]; + [msl appendFormat: @" out.color = tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod)).%.4s;", coordArg, sliceArg, swizzleArg]; [msl appendLineMVK]; } [msl appendLineMVK: @" return out;"]; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 93adca539..12f1514ce 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -371,6 +371,15 @@ portabilityFeatures->vertexAttributeAccessBeyondStride = true; // Costs additional buffers. Should make configuration switch. break; } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: { + auto* formatFeatures = (VkPhysicalDevice4444FormatsFeaturesEXT*)next; + bool canSupport4444 = _metalFeatures.tileBasedDeferredRendering && + (_metalFeatures.nativeTextureSwizzle || + mvkConfig().fullImageViewSwizzle); + formatFeatures->formatA4R4G4B4 = canSupport4444; + formatFeatures->formatA4B4G4R4 = canSupport4444; + break; + } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: { auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next; interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def index 0674e4c18..c0bbb4816 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def @@ -62,6 +62,7 @@ MVK_DEVICE_FEATURE(VariablePointer, VARIABLE_POINTER, MVK_DEVICE_FEATURE(VulkanMemoryModel, VULKAN_MEMORY_MODEL, 3) MVK_DEVICE_FEATURE_EXTN(FragmentShaderBarycentric, FRAGMENT_SHADER_BARYCENTRIC, KHR, 1) MVK_DEVICE_FEATURE_EXTN(PortabilitySubset, PORTABILITY_SUBSET, KHR, 15) +MVK_DEVICE_FEATURE_EXTN(4444Formats, 4444_FORMATS, EXT, 2) MVK_DEVICE_FEATURE_EXTN(FragmentShaderInterlock, FRAGMENT_SHADER_INTERLOCK, EXT, 3) MVK_DEVICE_FEATURE_EXTN(PipelineCreationCacheControl, PIPELINE_CREATION_CACHE_CONTROL, EXT, 1) MVK_DEVICE_FEATURE_EXTN(Robustness2, ROBUSTNESS_2, EXT, 3) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index db83c323c..572e8f06a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -224,6 +224,9 @@ class MVKImage : public MVKVulkanAPIDeviceObject { /** Returns the number of planes of this image view. */ uint8_t getPlaneCount() { return _planes.size(); } + /** Returns whether or not the image format requires swizzling. */ + bool needsSwizzle() { return getPixelFormats()->needsSwizzle(_vkFormat); } + /** Populates the specified layout for the specified sub-resource. */ VkResult getSubresourceLayout(const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index cc8a1601f..148702215 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1575,6 +1575,26 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { VkImageAspectFlags aspectMask = pCreateInfo->subresourceRange.aspectMask; #define adjustComponentSwizzleValue(comp, currVal, newVal) if (_componentSwizzle.comp == VK_COMPONENT_SWIZZLE_ ##currVal) { _componentSwizzle.comp = VK_COMPONENT_SWIZZLE_ ##newVal; } +#define adjustAnyComponentSwizzleValue(comp, I, R, G, B, A) \ + switch (_componentSwizzle.comp) { \ + case VK_COMPONENT_SWIZZLE_IDENTITY: \ + _componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##I; \ + break; \ + case VK_COMPONENT_SWIZZLE_R: \ + _componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##R; \ + break; \ + case VK_COMPONENT_SWIZZLE_G: \ + _componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##G; \ + break; \ + case VK_COMPONENT_SWIZZLE_B: \ + _componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##B; \ + break; \ + case VK_COMPONENT_SWIZZLE_A: \ + _componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##A; \ + break; \ + default: \ + break; \ + } // Use swizzle adjustment to bridge some differences between Vulkan and Metal pixel formats. // Do this ahead of other tests and adjustments so that swizzling will be enabled by tests below. @@ -1589,6 +1609,24 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { adjustComponentSwizzleValue(a, IDENTITY, ONE); break; + case VK_FORMAT_A4R4G4B4_UNORM_PACK16: + // Metal doesn't (publicly) support this directly, so use a swizzle to get the ordering right. + // n.b. **Do NOT use adjustComponentSwizzleValue if multiple values need substitution, + // and some of the substitutes are keys for other substitutions!** + adjustAnyComponentSwizzleValue(r, G, G, B, A, R); + adjustAnyComponentSwizzleValue(g, B, G, B, A, R); + adjustAnyComponentSwizzleValue(b, A, G, B, A, R); + adjustAnyComponentSwizzleValue(a, R, G, B, A, R); + break; + + case VK_FORMAT_A4B4G4R4_UNORM_PACK16: + // Metal doesn't support this directly, so use a swizzle to get the ordering right. + adjustAnyComponentSwizzleValue(r, A, A, B, G, R); + adjustAnyComponentSwizzleValue(g, B, A, B, G, R); + adjustAnyComponentSwizzleValue(b, G, A, B, G, R); + adjustAnyComponentSwizzleValue(a, R, A, B, G, R); + break; + default: break; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h index 03fc0f98a..479965b48 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h @@ -148,6 +148,7 @@ typedef struct MVKVkFormatDesc { uint32_t bytesPerBlock; MVKFormatType formatType; VkFormatProperties properties; + VkComponentMapping componentMapping; const char* name; bool hasReportedSubstitution; @@ -158,6 +159,13 @@ typedef struct MVKVkFormatDesc { inline bool vertexIsSupported() const { return (mtlVertexFormat != MTLVertexFormatInvalid); }; inline bool vertexIsSupportedOrSubstitutable() const { return vertexIsSupported() || (mtlVertexFormatSubstitute != MTLVertexFormatInvalid); }; + + bool needsSwizzle() const { + return componentMapping.r != VK_COMPONENT_SWIZZLE_IDENTITY || + componentMapping.g != VK_COMPONENT_SWIZZLE_IDENTITY || + componentMapping.b != VK_COMPONENT_SWIZZLE_IDENTITY || + componentMapping.a != VK_COMPONENT_SWIZZLE_IDENTITY; + } } MVKVkFormatDesc; /** Describes the properties of a MTLPixelFormat or MTLVertexFormat. */ @@ -320,6 +328,21 @@ class MVKPixelFormats : public MVKBaseObject { */ size_t getBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer); + /** Returns whether or not the specified Vulkan format requires swizzling to use with Metal. */ + bool needsSwizzle(VkFormat vkFormat); + + /** Returns any VkComponentMapping needed to use the specified Vulkan format. */ + VkComponentMapping getVkComponentMapping(VkFormat vkFormat); + + /** + * Returns the inverse of the VkComponentMapping needed to use the specified Vulkan format. + * If the original mapping is not a one-to-one function, the behaviour is undefined. + */ + VkComponentMapping getInverseComponentMapping(VkFormat vkFormat); + + /** Returns any MTLTextureSwizzleChannels needed to use the specified Vulkan format. */ + MTLTextureSwizzleChannels getMTLTextureSwizzleChannels(VkFormat vkFormat); + /** Returns the default properties for the specified Vulkan format. */ VkFormatProperties& getVkFormatProperties(VkFormat vkFormat); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index 79f1dffa9..3044f66d9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -377,6 +377,44 @@ return mvkCeilingDivide(texelRowsPerLayer, getVkFormatDesc(mtlFormat).blockTexelSize.height) * bytesPerRow; } +bool MVKPixelFormats::needsSwizzle(VkFormat vkFormat) { + return getVkFormatDesc(vkFormat).needsSwizzle(); +} + +VkComponentMapping MVKPixelFormats::getVkComponentMapping(VkFormat vkFormat) { + return getVkFormatDesc(vkFormat).componentMapping; +} + +VkComponentMapping MVKPixelFormats::getInverseComponentMapping(VkFormat vkFormat) { +#define INVERT_SWIZZLE(x, X, Y) \ + case VK_COMPONENT_SWIZZLE_##X: \ + inverse.x = VK_COMPONENT_SWIZZLE_##Y; \ + break +#define INVERT_MAPPING(y, Y) \ + switch (mapping.y) { \ + case VK_COMPONENT_SWIZZLE_IDENTITY: \ + inverse.y = VK_COMPONENT_SWIZZLE_IDENTITY; \ + break; \ + INVERT_SWIZZLE(r, R, Y); \ + INVERT_SWIZZLE(g, G, Y); \ + INVERT_SWIZZLE(b, B, Y); \ + INVERT_SWIZZLE(a, A, Y); \ + default: break; \ + } + VkComponentMapping mapping = getVkComponentMapping(vkFormat), inverse; + INVERT_MAPPING(r, R) + INVERT_MAPPING(g, G) + INVERT_MAPPING(b, B) + INVERT_MAPPING(a, A) + return inverse; +#undef INVERT_MAPPING +#undef INVERT_SWIZZLE +} + +MTLTextureSwizzleChannels MVKPixelFormats::getMTLTextureSwizzleChannels(VkFormat vkFormat) { + return mvkMTLTextureSwizzleChannelsFromVkComponentMapping(getVkComponentMapping(vkFormat)); +} + VkFormatProperties& MVKPixelFormats::getVkFormatProperties(VkFormat vkFormat) { return getVkFormatDesc(vkFormat).properties; } @@ -464,13 +502,18 @@ MTLClearColor MVKPixelFormats::getMTLClearColor(VkClearValue vkClearValue, VkFormat vkFormat) { MTLClearColor mtlClr; + // The VkComponentMapping (and its MTLTextureSwizzleChannels equivalent) define the *sources* + // for the texture color components for reading. Since we're *writing* to the texture, + // we need to *invert* the mapping. + // n.b. Bad things might happen if the original swizzle isn't one-to-one! + VkComponentMapping inverseMap = getInverseComponentMapping(vkFormat); switch (getFormatType(vkFormat)) { case kMVKFormatColorHalf: - case kMVKFormatColorFloat: - mtlClr.red = vkClearValue.color.float32[0]; - mtlClr.green = vkClearValue.color.float32[1]; - mtlClr.blue = vkClearValue.color.float32[2]; - mtlClr.alpha = vkClearValue.color.float32[3]; + case kMVKFormatColorFloat: { + mtlClr.red = mvkVkClearColorFloatValueFromVkComponentSwizzle(vkClearValue.color.float32, 0, inverseMap.r); + mtlClr.green = mvkVkClearColorFloatValueFromVkComponentSwizzle(vkClearValue.color.float32, 1, inverseMap.g); + mtlClr.blue = mvkVkClearColorFloatValueFromVkComponentSwizzle(vkClearValue.color.float32, 2, inverseMap.b); + mtlClr.alpha = mvkVkClearColorFloatValueFromVkComponentSwizzle(vkClearValue.color.float32, 3, inverseMap.a); if (_physicalDevice && _physicalDevice->getMetalFeatures()->clearColorFloatRounding == MVK_FLOAT_ROUNDING_DOWN) { // For normalized formats, increment the clear value by half the ULP @@ -486,6 +529,8 @@ #define OFFSET_SNORM(COLOR, BIT_WIDTH) OFFSET_NORM(-1.0, COLOR, BIT_WIDTH - 1) switch (vkFormat) { case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + case VK_FORMAT_A4R4G4B4_UNORM_PACK16: + case VK_FORMAT_A4B4G4R4_UNORM_PACK16: OFFSET_UNORM(red, 4) OFFSET_UNORM(green, 4) OFFSET_UNORM(blue, 4) @@ -571,21 +616,22 @@ #undef OFFSET_NORM } break; + } case kMVKFormatColorUInt8: case kMVKFormatColorUInt16: case kMVKFormatColorUInt32: - mtlClr.red = vkClearValue.color.uint32[0]; - mtlClr.green = vkClearValue.color.uint32[1]; - mtlClr.blue = vkClearValue.color.uint32[2]; - mtlClr.alpha = vkClearValue.color.uint32[3]; + mtlClr.red = mvkVkClearColorUIntValueFromVkComponentSwizzle(vkClearValue.color.uint32, 0, inverseMap.r); + mtlClr.green = mvkVkClearColorUIntValueFromVkComponentSwizzle(vkClearValue.color.uint32, 1, inverseMap.g); + mtlClr.blue = mvkVkClearColorUIntValueFromVkComponentSwizzle(vkClearValue.color.uint32, 2, inverseMap.b); + mtlClr.alpha = mvkVkClearColorUIntValueFromVkComponentSwizzle(vkClearValue.color.uint32, 3, inverseMap.a); break; case kMVKFormatColorInt8: case kMVKFormatColorInt16: case kMVKFormatColorInt32: - mtlClr.red = vkClearValue.color.int32[0]; - mtlClr.green = vkClearValue.color.int32[1]; - mtlClr.blue = vkClearValue.color.int32[2]; - mtlClr.alpha = vkClearValue.color.int32[3]; + mtlClr.red = mvkVkClearColorIntValueFromVkComponentSwizzle(vkClearValue.color.int32, 0, inverseMap.r); + mtlClr.green = mvkVkClearColorIntValueFromVkComponentSwizzle(vkClearValue.color.int32, 1, inverseMap.g); + mtlClr.blue = mvkVkClearColorIntValueFromVkComponentSwizzle(vkClearValue.color.int32, 2, inverseMap.b); + mtlClr.alpha = mvkVkClearColorIntValueFromVkComponentSwizzle(vkClearValue.color.int32, 3, inverseMap.a); break; default: mtlClr.red = 0.0; @@ -756,16 +802,21 @@ buildVkFormatMaps(); } -#define addVkFormatDescFull(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE) \ +#define addVkFormatDescFull(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE, SWIZ_R, SWIZ_G, SWIZ_B, SWIZ_A) \ MVKAssert(fmtIdx < _vkFormatCount, "Attempting to describe %d VkFormats, but only have space for %d. Increase the value of _vkFormatCount", fmtIdx + 1, _vkFormatCount); \ _vkFormatDescriptions[fmtIdx++] = { VK_FORMAT_ ##VK_FMT, MTLPixelFormat ##MTL_FMT, MTLPixelFormat ##MTL_FMT_ALT, MTLVertexFormat ##MTL_VTX_FMT, MTLVertexFormat ##MTL_VTX_FMT_ALT, \ - CSPC, CSCB, { BLK_W, BLK_H }, BLK_BYTE_CNT, kMVKFormat ##MVK_FMT_TYPE, { 0, 0, 0 }, "VK_FORMAT_" #VK_FMT, false } + CSPC, CSCB, { BLK_W, BLK_H }, BLK_BYTE_CNT, kMVKFormat ##MVK_FMT_TYPE, { 0, 0, 0 }, \ + { VK_COMPONENT_SWIZZLE_ ##SWIZ_R, VK_COMPONENT_SWIZZLE_ ##SWIZ_G, VK_COMPONENT_SWIZZLE_ ##SWIZ_B, VK_COMPONENT_SWIZZLE_ ##SWIZ_A }, \ + "VK_FORMAT_" #VK_FMT, false } #define addVkFormatDesc(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE) \ - addVkFormatDescFull(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, 0, 0, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE) + addVkFormatDescFull(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, 0, 0, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE, IDENTITY, IDENTITY, IDENTITY, IDENTITY) + +#define addVkFormatDescSwizzled(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE, SWIZ_R, SWIZ_G, SWIZ_B, SWIZ_A) \ + addVkFormatDescFull(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, 0, 0, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE, SWIZ_R, SWIZ_G, SWIZ_B, SWIZ_A) #define addVkFormatDescChromaSubsampling(VK_FMT, MTL_FMT, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT) \ - addVkFormatDescFull(VK_FMT, MTL_FMT, Invalid, Invalid, Invalid, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT, ColorFloat) + addVkFormatDescFull(VK_FMT, MTL_FMT, Invalid, Invalid, Invalid, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT, ColorFloat, IDENTITY, IDENTITY, IDENTITY, IDENTITY) void MVKPixelFormats::initVkFormatCapabilities() { @@ -781,6 +832,8 @@ addVkFormatDesc( R4G4_UNORM_PACK8, Invalid, Invalid, Invalid, Invalid, 1, 1, 1, ColorFloat ); addVkFormatDesc( R4G4B4A4_UNORM_PACK16, ABGR4Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat ); addVkFormatDesc( B4G4R4A4_UNORM_PACK16, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat ); + addVkFormatDescSwizzled( A4R4G4B4_UNORM_PACK16, ABGR4Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat, G, B, A, R ); + addVkFormatDescSwizzled( A4B4G4R4_UNORM_PACK16, ABGR4Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat, A, B, G, R ); addVkFormatDesc( R5G6B5_UNORM_PACK16, B5G6R5Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat ); addVkFormatDesc( B5G6R5_UNORM_PACK16, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat ); @@ -1962,6 +2015,23 @@ _vkFormatDescIndicesByVkFormatsExt[vkFmt] = fmtIdx; } + if (vkDesc.needsSwizzle()) { + if (_physicalDevice) { + id mtlDev = _physicalDevice->getMTLDevice(); +#if MVK_MACCAT + bool supportsNativeTextureSwizzle = [mtlDev supportsFamily: MTLGPUFamilyMacCatalyst2]; +#elif MVK_MACOS + bool supportsNativeTextureSwizzle = mvkOSVersionIsAtLeast(10.15) && [mtlDev supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1]; +#endif +#if MVK_IOS || MVK_TVOS + bool supportsNativeTextureSwizzle = mtlDev && mvkOSVersionIsAtLeast(13.0); +#endif + if (!supportsNativeTextureSwizzle && !mvkConfig().fullImageViewSwizzle) { + vkDesc.mtlPixelFormat = vkDesc.mtlPixelFormatSubstitute = MTLPixelFormatInvalid; + } + } + } + // Populate the back reference from the Metal formats to the Vulkan format. // Validate the corresponding Metal formats for the platform, and clear them // in the Vulkan format if not supported. @@ -2078,6 +2148,13 @@ mvkDisableFlags(vkProps.optimalTilingFeatures, (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT)); } + // These formats require swizzling. In order to support rendering, we'll have to swizzle + // in the fragment shader, but that hasn't been implemented yet. + if (vkDesc.needsSwizzle()) { + mvkDisableFlags(vkProps.optimalTilingFeatures, (kMVKVkFormatFeatureFlagsTexColorAtt | + kMVKVkFormatFeatureFlagsTexBlend)); + } + // Linear tiling is not available to depth/stencil or compressed formats. // GBGR and BGRG formats also do not support linear tiling in Metal. if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed || diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index a50b3bb58..0a4bd964f 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -92,6 +92,7 @@ MVK_EXTENSION(KHR_timeline_semaphore, KHR_TIMELINE_SEMAPHORE, MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA) +MVK_EXTENSION(EXT_4444_formats, EXT_4444_FORMATS, DEVICE, 11.0, 13.0) MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0) diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index 1960dedd9..1aab82ebc 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -228,6 +228,45 @@ MVK_PUBLIC_SYMBOL MTLTextureSwizzleChannels mvkMTLTextureSwizzleChannelsFromVkCo #undef convert } +MVK_PUBLIC_SYMBOL float mvkVkClearColorFloatValueFromVkComponentSwizzle(float *colors, uint32_t index, VkComponentSwizzle vkSwizzle) { + switch (vkSwizzle) { + case VK_COMPONENT_SWIZZLE_IDENTITY: return colors[index]; + case VK_COMPONENT_SWIZZLE_ZERO: return 0.f; + case VK_COMPONENT_SWIZZLE_ONE: return 1.f; + case VK_COMPONENT_SWIZZLE_R: return colors[0]; + case VK_COMPONENT_SWIZZLE_G: return colors[1]; + case VK_COMPONENT_SWIZZLE_B: return colors[2]; + case VK_COMPONENT_SWIZZLE_A: return colors[3]; + default: return colors[index]; + } +} + +MVK_PUBLIC_SYMBOL uint32_t mvkVkClearColorUIntValueFromVkComponentSwizzle(uint32_t *colors, uint32_t index, VkComponentSwizzle vkSwizzle) { + switch (vkSwizzle) { + case VK_COMPONENT_SWIZZLE_IDENTITY: return colors[index]; + case VK_COMPONENT_SWIZZLE_ZERO: return 0U; + case VK_COMPONENT_SWIZZLE_ONE: return 1U; + case VK_COMPONENT_SWIZZLE_R: return colors[0]; + case VK_COMPONENT_SWIZZLE_G: return colors[1]; + case VK_COMPONENT_SWIZZLE_B: return colors[2]; + case VK_COMPONENT_SWIZZLE_A: return colors[3]; + default: return colors[index]; + } +} + +MVK_PUBLIC_SYMBOL int32_t mvkVkClearColorIntValueFromVkComponentSwizzle(int32_t *colors, uint32_t index, VkComponentSwizzle vkSwizzle) { + switch (vkSwizzle) { + case VK_COMPONENT_SWIZZLE_IDENTITY: return colors[index]; + case VK_COMPONENT_SWIZZLE_ZERO: return 0; + case VK_COMPONENT_SWIZZLE_ONE: return 1; + case VK_COMPONENT_SWIZZLE_R: return colors[0]; + case VK_COMPONENT_SWIZZLE_G: return colors[1]; + case VK_COMPONENT_SWIZZLE_B: return colors[2]; + case VK_COMPONENT_SWIZZLE_A: return colors[3]; + default: return colors[index]; + } +} + #pragma mark Mipmaps From 16990efeb132f859df324a848d25bd507f4b1ff1 Mon Sep 17 00:00:00 2001 From: Filip Lundgren Date: Fri, 23 Jun 2023 10:24:35 -0400 Subject: [PATCH 49/74] Support building for visionOS Note: Internal naming is xrOS, but publicly it should be referred to as visionOS --- Common/MVKCommonEnvironment.h | 10 + Common/MVKOSExtensions.h | 5 +- Common/MVKOSExtensions.mm | 2 +- .../project.pbxproj | 1482 +++++++++++++++++ .../ExternalDependencies-xrOS.xcscheme | 66 + .../xcschemes/SPIRV-Cross-xrOS.xcscheme | 66 + .../xcschemes/SPIRV-Tools-xrOS.xcscheme | 66 + .../xcschemes/glslang-xrOS.xcscheme | 66 + Makefile | 20 + MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 384 +++++ .../xcschemes/MoltenVK-xrOS.xcscheme | 66 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 4 +- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 8 +- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 194 +-- MoltenVK/MoltenVK/Layers/MVKExtensions.h | 2 +- MoltenVK/MoltenVK/Layers/MVKExtensions.mm | 34 +- MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h | 2 + MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m | 2 +- MoltenVK/MoltenVK/OS/MVKGPUCapture.mm | 4 +- MoltenVKPackaging.xcodeproj/project.pbxproj | 79 + .../MoltenVK Package (visionOS only).xcscheme | 72 + .../project.pbxproj | 121 +- .../MoltenVKShaderConverter-xrOS.xcscheme | 67 + Scripts/create_dylib.sh | 2 +- Scripts/create_dylib_ios.sh | 1 - Scripts/create_dylib_macos.sh | 2 +- Scripts/create_dylib_tvos.sh | 2 +- Scripts/create_dylib_xros.sh | 11 + Scripts/package_moltenvk.sh | 2 + fetchDependencies | 30 +- 30 files changed, 2740 insertions(+), 132 deletions(-) create mode 100644 ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-xrOS.xcscheme create mode 100644 ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-xrOS.xcscheme create mode 100644 ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-xrOS.xcscheme create mode 100644 ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-xrOS.xcscheme create mode 100644 MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-xrOS.xcscheme create mode 100644 MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package (visionOS only).xcscheme create mode 100644 MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter-xrOS.xcscheme create mode 100755 Scripts/create_dylib_xros.sh diff --git a/Common/MVKCommonEnvironment.h b/Common/MVKCommonEnvironment.h index ca6fe5239..84b71aacd 100644 --- a/Common/MVKCommonEnvironment.h +++ b/Common/MVKCommonEnvironment.h @@ -62,6 +62,11 @@ extern "C" { # define MVK_TVOS TARGET_OS_TV #endif +/** Building for visionOS. */ +#ifndef MVK_VISIONOS +# define MVK_VISIONOS TARGET_OS_XR +#endif + /** Building for iOS or tvOS. */ #ifndef MVK_IOS_OR_TVOS # define MVK_IOS_OR_TVOS (MVK_IOS || MVK_TVOS) @@ -72,6 +77,11 @@ extern "C" { # define MVK_MACOS_OR_IOS (MVK_MACOS || MVK_IOS) #endif +/** Building for macOS, iOS or visionOS. */ +#ifndef MVK_MACOS_OR_IOS_ORVISIONOS +# define MVK_MACOS_OR_IOS_OR_VISIONOS (MVK_MACOS || MVK_IOS | MVK_VISIONOS) +#endif + /** Building for a Simulator. */ #ifndef MVK_OS_SIMULATOR # define MVK_OS_SIMULATOR TARGET_OS_SIMULATOR diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h index fde73c5c1..65e3c8a81 100644 --- a/Common/MVKOSExtensions.h +++ b/Common/MVKOSExtensions.h @@ -52,13 +52,16 @@ inline bool mvkOSVersionIsAtLeast(MVKOSVersion minVer) { return mvkOSVersion() > * to always fail on that OS, which is useful for indidicating functionalty guarded by * this test is not supported on that OS. */ -inline bool mvkOSVersionIsAtLeast(MVKOSVersion macOSMinVer, MVKOSVersion iOSMinVer) { +inline bool mvkOSVersionIsAtLeast(MVKOSVersion macOSMinVer, MVKOSVersion iOSMinVer, MVKOSVersion visionOSMinVer) { #if MVK_MACOS return mvkOSVersionIsAtLeast(macOSMinVer); #endif #if MVK_IOS_OR_TVOS return mvkOSVersionIsAtLeast(iOSMinVer); #endif +#if MVK_VISIONOS + return mvkOSVersionIsAtLeast(visionOSMinVer); +#endif } /** diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 6c023086a..2d9f99077 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -97,7 +97,7 @@ bool mvkGetEnvVarBool(std::string varName, bool* pWasFound) { #pragma mark System memory uint64_t mvkGetSystemMemorySize() { -#if MVK_MACOS_OR_IOS +#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) { diff --git a/ExternalDependencies.xcodeproj/project.pbxproj b/ExternalDependencies.xcodeproj/project.pbxproj index b450046ef..8cdb8e767 100644 --- a/ExternalDependencies.xcodeproj/project.pbxproj +++ b/ExternalDependencies.xcodeproj/project.pbxproj @@ -63,6 +63,20 @@ name = ExternalDependencies; productName = "ExternalLibraries-macOS"; }; + DCFD7EC12A45BAAA007BBBF7 /* ExternalDependencies-xrOS */ = { + isa = PBXAggregateTarget; + buildConfigurationList = DCFD7EC92A45BAAA007BBBF7 /* Build configuration list for PBXAggregateTarget "ExternalDependencies-xrOS" */; + buildPhases = ( + DCFD7EC82A45BAAA007BBBF7 /* Package Libraries */, + ); + dependencies = ( + DCFD7ECD2A45BC08007BBBF7 /* PBXTargetDependency */, + DCFD7ECF2A45BC0C007BBBF7 /* PBXTargetDependency */, + DCFD7ED12A45BC10007BBBF7 /* PBXTargetDependency */, + ); + name = "ExternalDependencies-xrOS"; + productName = "ExternalLibraries-macOS"; + }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ @@ -1698,6 +1712,550 @@ A9F7BCF529425A1B00B30DA7 /* decoration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B35829425A1800B30DA7 /* decoration.h */; }; A9F7BCF629425A1B00B30DA7 /* decoration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B35829425A1800B30DA7 /* decoration.h */; }; A9F7BCF729425A1B00B30DA7 /* decoration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B35829425A1800B30DA7 /* decoration.h */; }; + DCFD7C8B2A45BA7D007BBBF7 /* spirv_cfg.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290921CC60BC00B52A68 /* spirv_cfg.hpp */; }; + DCFD7C8C2A45BA7D007BBBF7 /* spirv_cross_parsed_ir.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290821CC60BC00B52A68 /* spirv_cross_parsed_ir.hpp */; }; + DCFD7C8D2A45BA7D007BBBF7 /* spirv_common.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290721CC60BC00B52A68 /* spirv_common.hpp */; }; + DCFD7C8E2A45BA7D007BBBF7 /* spirv_glsl.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290A21CC60BC00B52A68 /* spirv_glsl.hpp */; }; + DCFD7C8F2A45BA7D007BBBF7 /* spirv_parser.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290C21CC60BC00B52A68 /* spirv_parser.hpp */; }; + DCFD7C902A45BA7D007BBBF7 /* spirv_cross_util.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A9717C0B26EE8C730041AE82 /* spirv_cross_util.hpp */; }; + DCFD7C912A45BA7D007BBBF7 /* spirv_cross_containers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A9717C0326EE8C570041AE82 /* spirv_cross_containers.hpp */; }; + DCFD7C922A45BA7D007BBBF7 /* spirv.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A9717C0F26EE8C9D0041AE82 /* spirv.hpp */; }; + DCFD7C932A45BA7D007BBBF7 /* spirv_cross_error_handling.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A9717C0426EE8C570041AE82 /* spirv_cross_error_handling.hpp */; }; + DCFD7C942A45BA7D007BBBF7 /* spirv_cross.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290321CC60BC00B52A68 /* spirv_cross.hpp */; }; + DCFD7C952A45BA7D007BBBF7 /* spirv_msl.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A976290221CC60BC00B52A68 /* spirv_msl.hpp */; }; + DCFD7C962A45BA7D007BBBF7 /* spirv_reflect.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 450A4F63221C5A95007203D7 /* spirv_reflect.hpp */; }; + DCFD7C982A45BA7D007BBBF7 /* spirv_msl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290D21CC60BC00B52A68 /* spirv_msl.cpp */; }; + DCFD7C992A45BA7D007BBBF7 /* spirv_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290421CC60BC00B52A68 /* spirv_parser.cpp */; }; + DCFD7C9A2A45BA7D007BBBF7 /* spirv_cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290B21CC60BC00B52A68 /* spirv_cfg.cpp */; }; + DCFD7C9B2A45BA7D007BBBF7 /* spirv_cross.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290521CC60BC00B52A68 /* spirv_cross.cpp */; }; + DCFD7C9C2A45BA7D007BBBF7 /* spirv_reflect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 450A4F64221C5A95007203D7 /* spirv_reflect.cpp */; }; + DCFD7C9D2A45BA7D007BBBF7 /* spirv_glsl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290621CC60BC00B52A68 /* spirv_glsl.cpp */; }; + DCFD7C9E2A45BA7D007BBBF7 /* spirv_cross_parsed_ir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290E21CC60BC00B52A68 /* spirv_cross_parsed_ir.cpp */; }; + DCFD7CA62A45BA92007BBBF7 /* propagateNoContraction.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F99626865A550006F71B /* propagateNoContraction.h */; }; + DCFD7CA72A45BA92007BBBF7 /* disassemble.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95626865A550006F71B /* disassemble.h */; }; + DCFD7CA82A45BA92007BBBF7 /* PpContext.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9B126865A550006F71B /* PpContext.h */; }; + DCFD7CA92A45BA92007BBBF7 /* InfoSink.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98226865A550006F71B /* InfoSink.h */; }; + DCFD7CAA2A45BA92007BBBF7 /* bitutils.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95526865A550006F71B /* bitutils.h */; }; + DCFD7CAB2A45BA92007BBBF7 /* SpvBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F94426865A550006F71B /* SpvBuilder.h */; }; + DCFD7CAC2A45BA92007BBBF7 /* GLSL.std.450.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95826865A550006F71B /* GLSL.std.450.h */; }; + DCFD7CAD2A45BA92007BBBF7 /* Logger.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95C26865A550006F71B /* Logger.h */; }; + DCFD7CAE2A45BA92007BBBF7 /* pch.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98A26865A550006F71B /* pch.h */; }; + DCFD7CAF2A45BA92007BBBF7 /* LiveTraverser.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9A226865A550006F71B /* LiveTraverser.h */; }; + DCFD7CB02A45BA92007BBBF7 /* spvIR.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95426865A550006F71B /* spvIR.h */; }; + DCFD7CB12A45BA92007BBBF7 /* glslang_c_shader_types.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97B26865A550006F71B /* glslang_c_shader_types.h */; }; + DCFD7CB22A45BA92007BBBF7 /* attribute.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9A726865A550006F71B /* attribute.h */; }; + DCFD7CB32A45BA92007BBBF7 /* Scan.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9B726865A550006F71B /* Scan.h */; }; + DCFD7CB42A45BA92007BBBF7 /* Types.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97926865A550006F71B /* Types.h */; }; + DCFD7CB52A45BA92007BBBF7 /* PoolAlloc.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98326865A550006F71B /* PoolAlloc.h */; }; + DCFD7CB62A45BA92007BBBF7 /* InitializeGlobals.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97D26865A550006F71B /* InitializeGlobals.h */; }; + DCFD7CB72A45BA92007BBBF7 /* parseVersions.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98726865A550006F71B /* parseVersions.h */; }; + DCFD7CB82A45BA92007BBBF7 /* osinclude.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F96E26865A550006F71B /* osinclude.h */; }; + DCFD7CB92A45BA92007BBBF7 /* gl_types.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98826865A550006F71B /* gl_types.h */; }; + DCFD7CBA2A45BA92007BBBF7 /* localintermediate.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98D26865A550006F71B /* localintermediate.h */; }; + DCFD7CBB2A45BA92007BBBF7 /* GLSL.ext.AMD.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F94C26865A550006F71B /* GLSL.ext.AMD.h */; }; + DCFD7CBC2A45BA92007BBBF7 /* reflection.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9B626865A550006F71B /* reflection.h */; }; + DCFD7CBD2A45BA92007BBBF7 /* ShHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97E26865A550006F71B /* ShHandle.h */; }; + DCFD7CBE2A45BA92007BBBF7 /* iomapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98C26865A550006F71B /* iomapper.h */; }; + DCFD7CBF2A45BA92007BBBF7 /* GLSL.ext.NV.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95226865A550006F71B /* GLSL.ext.NV.h */; }; + DCFD7CC02A45BA92007BBBF7 /* Versions.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F99726865A550006F71B /* Versions.h */; }; + DCFD7CC12A45BA92007BBBF7 /* SPVRemapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F94326865A550006F71B /* SPVRemapper.h */; }; + DCFD7CC22A45BA92007BBBF7 /* ConstantUnion.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98126865A550006F71B /* ConstantUnion.h */; }; + DCFD7CC32A45BA92007BBBF7 /* doc.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F94D26865A550006F71B /* doc.h */; }; + DCFD7CC42A45BA92007BBBF7 /* Initialize.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9A326865A550006F71B /* Initialize.h */; }; + DCFD7CC52A45BA92007BBBF7 /* GLSL.ext.EXT.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95026865A550006F71B /* GLSL.ext.EXT.h */; }; + DCFD7CC62A45BA92007BBBF7 /* ResourceLimits.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97626865A550006F71B /* ResourceLimits.h */; }; + DCFD7CC72A45BA92007BBBF7 /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98026865A550006F71B /* Common.h */; }; + DCFD7CC82A45BA92007BBBF7 /* GLSL.ext.KHR.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95126865A550006F71B /* GLSL.ext.KHR.h */; }; + DCFD7CC92A45BA92007BBBF7 /* intermediate.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97A26865A550006F71B /* intermediate.h */; }; + DCFD7CCA2A45BA92007BBBF7 /* ShaderLang.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9B926865A550006F71B /* ShaderLang.h */; }; + DCFD7CCB2A45BA92007BBBF7 /* ScanContext.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F98B26865A550006F71B /* ScanContext.h */; }; + DCFD7CCC2A45BA92007BBBF7 /* PpTokens.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9AF26865A550006F71B /* PpTokens.h */; }; + DCFD7CCD2A45BA92007BBBF7 /* BaseTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97C26865A550006F71B /* BaseTypes.h */; }; + DCFD7CCE2A45BA92007BBBF7 /* hex_float.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95B26865A550006F71B /* hex_float.h */; }; + DCFD7CCF2A45BA92007BBBF7 /* SpvTools.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F94926865A550006F71B /* SpvTools.h */; }; + DCFD7CD02A45BA92007BBBF7 /* RemoveTree.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F99026865A550006F71B /* RemoveTree.h */; }; + DCFD7CD12A45BA92007BBBF7 /* SymbolTable.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F99D26865A550006F71B /* SymbolTable.h */; }; + DCFD7CD22A45BA92007BBBF7 /* arrays.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97F26865A550006F71B /* arrays.h */; }; + DCFD7CD32A45BA92007BBBF7 /* spirv.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A997F94E26865A550006F71B /* spirv.hpp */; }; + DCFD7CD42A45BA92007BBBF7 /* glslang_c_interface.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97726865A550006F71B /* glslang_c_interface.h */; }; + DCFD7CD52A45BA92007BBBF7 /* GlslangToSpv.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F95726865A550006F71B /* GlslangToSpv.h */; }; + DCFD7CD62A45BA92007BBBF7 /* SpirvIntrinsics.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F97826865A550006F71B /* SpirvIntrinsics.h */; }; + DCFD7CD72A45BA92007BBBF7 /* NonSemanticDebugPrintf.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F94226865A550006F71B /* NonSemanticDebugPrintf.h */; }; + DCFD7CD82A45BA92007BBBF7 /* glslang_tab.cpp.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9A126865A550006F71B /* glslang_tab.cpp.h */; }; + DCFD7CD92A45BA92007BBBF7 /* ParseHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F9AC26865A550006F71B /* ParseHelper.h */; }; + DCFD7CDA2A45BA92007BBBF7 /* InitializeDll.h in Headers */ = {isa = PBXBuildFile; fileRef = A997F96126865A550006F71B /* InitializeDll.h */; }; + DCFD7CDC2A45BA92007BBBF7 /* ParseHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F98626865A550006F71B /* ParseHelper.cpp */; }; + DCFD7CDD2A45BA92007BBBF7 /* doc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F95D26865A550006F71B /* doc.cpp */; }; + DCFD7CDE2A45BA92007BBBF7 /* attribute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9A426865A550006F71B /* attribute.cpp */; }; + DCFD7CDF2A45BA92007BBBF7 /* IntermTraverse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99826865A550006F71B /* IntermTraverse.cpp */; }; + DCFD7CE02A45BA92007BBBF7 /* Versions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9A826865A550006F71B /* Versions.cpp */; }; + DCFD7CE12A45BA92007BBBF7 /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9A526865A550006F71B /* reflection.cpp */; }; + DCFD7CE22A45BA92007BBBF7 /* spirv_c_interface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F94826865A550006F71B /* spirv_c_interface.cpp */; }; + DCFD7CE32A45BA92007BBBF7 /* propagateNoContraction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F98926865A550006F71B /* propagateNoContraction.cpp */; }; + DCFD7CE42A45BA92007BBBF7 /* glslang_c_interface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F97426865A550006F71B /* glslang_c_interface.cpp */; }; + DCFD7CE52A45BA92007BBBF7 /* SPVRemapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F95926865A550006F71B /* SPVRemapper.cpp */; }; + DCFD7CE62A45BA92007BBBF7 /* SpvTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F94A26865A550006F71B /* SpvTools.cpp */; }; + DCFD7CE72A45BA92007BBBF7 /* Logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F95A26865A550006F71B /* Logger.cpp */; }; + DCFD7CE82A45BA92007BBBF7 /* ossource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F96C26865A550006F71B /* ossource.cpp */; }; + DCFD7CE92A45BA92007BBBF7 /* SpvPostProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F94626865A550006F71B /* SpvPostProcess.cpp */; }; + DCFD7CEA2A45BA92007BBBF7 /* Scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F98E26865A550006F71B /* Scan.cpp */; }; + DCFD7CEB2A45BA92007BBBF7 /* PpScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9B426865A550006F71B /* PpScanner.cpp */; }; + DCFD7CEC2A45BA92007BBBF7 /* PpContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9B326865A550006F71B /* PpContext.cpp */; }; + DCFD7CED2A45BA92007BBBF7 /* disassemble.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F95E26865A550006F71B /* disassemble.cpp */; }; + DCFD7CEE2A45BA92007BBBF7 /* SpirvIntrinsics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99426865A550006F71B /* SpirvIntrinsics.cpp */; }; + DCFD7CEF2A45BA92007BBBF7 /* linkValidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9AA26865A550006F71B /* linkValidate.cpp */; }; + DCFD7CF02A45BA92007BBBF7 /* parseConst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99526865A550006F71B /* parseConst.cpp */; }; + DCFD7CF12A45BA92007BBBF7 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F96226865A550006F71B /* InitializeDll.cpp */; }; + DCFD7CF22A45BA92007BBBF7 /* Link.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9CD26865A550006F71B /* Link.cpp */; }; + DCFD7CF32A45BA92007BBBF7 /* iomapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99A26865A550006F71B /* iomapper.cpp */; }; + DCFD7CF42A45BA92007BBBF7 /* ParseContextBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9B526865A550006F71B /* ParseContextBase.cpp */; }; + DCFD7CF52A45BA92007BBBF7 /* PpTokens.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9B226865A550006F71B /* PpTokens.cpp */; }; + DCFD7CF62A45BA92007BBBF7 /* GlslangToSpv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F95326865A550006F71B /* GlslangToSpv.cpp */; }; + DCFD7CF72A45BA92007BBBF7 /* limits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99326865A550006F71B /* limits.cpp */; }; + DCFD7CF82A45BA92007BBBF7 /* glslang_tab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99226865A550006F71B /* glslang_tab.cpp */; }; + DCFD7CF92A45BA92007BBBF7 /* Constant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9A926865A550006F71B /* Constant.cpp */; }; + DCFD7CFA2A45BA92007BBBF7 /* InfoSink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99E26865A550006F71B /* InfoSink.cpp */; }; + DCFD7CFB2A45BA92007BBBF7 /* RemoveTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9A626865A550006F71B /* RemoveTree.cpp */; }; + DCFD7CFC2A45BA92007BBBF7 /* intermOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99926865A550006F71B /* intermOut.cpp */; }; + DCFD7CFD2A45BA92007BBBF7 /* PoolAlloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99B26865A550006F71B /* PoolAlloc.cpp */; }; + DCFD7CFE2A45BA92007BBBF7 /* Initialize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99126865A550006F71B /* Initialize.cpp */; }; + DCFD7CFF2A45BA92007BBBF7 /* ShaderLang.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99C26865A550006F71B /* ShaderLang.cpp */; }; + DCFD7D002A45BA92007BBBF7 /* Intermediate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F99F26865A550006F71B /* Intermediate.cpp */; }; + DCFD7D012A45BA92007BBBF7 /* InReadableOrder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F94B26865A550006F71B /* InReadableOrder.cpp */; }; + DCFD7D022A45BA92007BBBF7 /* PpAtom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9AE26865A550006F71B /* PpAtom.cpp */; }; + DCFD7D032A45BA92007BBBF7 /* SpvBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F94F26865A550006F71B /* SpvBuilder.cpp */; }; + DCFD7D042A45BA92007BBBF7 /* CodeGen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9CC26865A550006F71B /* CodeGen.cpp */; }; + DCFD7D052A45BA92007BBBF7 /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9A026865A550006F71B /* SymbolTable.cpp */; }; + DCFD7D062A45BA92007BBBF7 /* Pp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A997F9B026865A550006F71B /* Pp.cpp */; }; + DCFD7D0E2A45BA9C007BBBF7 /* replace_invalid_opc.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0BC29425A1700B30DA7 /* replace_invalid_opc.h */; }; + DCFD7D0F2A45BA9C007BBBF7 /* convert_to_sampled_image_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0EE29425A1700B30DA7 /* convert_to_sampled_image_pass.h */; }; + DCFD7D102A45BA9C007BBBF7 /* text_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08C29425A1700B30DA7 /* text_handler.h */; }; + DCFD7D112A45BA9C007BBBF7 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0DA29425A1700B30DA7 /* types.h */; }; + DCFD7D122A45BA9C007BBBF7 /* dead_insert_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B10E29425A1800B30DA7 /* dead_insert_elim_pass.h */; }; + DCFD7D132A45BA9C007BBBF7 /* parse_number.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B01F29425A1700B30DA7 /* parse_number.h */; }; + DCFD7D142A45BA9C007BBBF7 /* make_unique.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02129425A1700B30DA7 /* make_unique.h */; }; + DCFD7D152A45BA9C007BBBF7 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17A29425A1800B30DA7 /* function.h */; }; + DCFD7D162A45BA9C007BBBF7 /* inst_debug_printf_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B10A29425A1800B30DA7 /* inst_debug_printf_pass.h */; }; + DCFD7D172A45BA9C007BBBF7 /* block_merge_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0E029425A1700B30DA7 /* block_merge_pass.h */; }; + DCFD7D182A45BA9C007BBBF7 /* scalar_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0B529425A1700B30DA7 /* scalar_analysis.h */; }; + DCFD7D192A45BA9C007BBBF7 /* composite.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0AA29425A1700B30DA7 /* composite.h */; }; + DCFD7D1A2A45BA9C007BBBF7 /* enum_set.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B01729425A1700B30DA7 /* enum_set.h */; }; + DCFD7D1B2A45BA9C007BBBF7 /* lints.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B01529425A1700B30DA7 /* lints.h */; }; + DCFD7D1C2A45BA9C007BBBF7 /* freeze_spec_constant_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B11029425A1800B30DA7 /* freeze_spec_constant_value_pass.h */; }; + DCFD7D1D2A45BA9C007BBBF7 /* reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B05F29425A1700B30DA7 /* reduction_opportunity.h */; }; + DCFD7D1E2A45BA9C007BBBF7 /* ir_context.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0CB29425A1700B30DA7 /* ir_context.h */; }; + DCFD7D1F2A45BA9C007BBBF7 /* loop_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16029425A1800B30DA7 /* loop_utils.h */; }; + DCFD7D202A45BA9C007BBBF7 /* relax_float_ops_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0EA29425A1700B30DA7 /* relax_float_ops_pass.h */; }; + DCFD7D212A45BA9C007BBBF7 /* pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13B29425A1800B30DA7 /* pass.h */; }; + DCFD7D222A45BA9C007BBBF7 /* inline_opaque_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0A529425A1700B30DA7 /* inline_opaque_pass.h */; }; + DCFD7D232A45BA9C007BBBF7 /* strength_reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B10729425A1800B30DA7 /* strength_reduction_pass.h */; }; + DCFD7D242A45BA9C007BBBF7 /* pch_source.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B07329425A1700B30DA7 /* pch_source.h */; }; + DCFD7D252A45BA9C007BBBF7 /* graphics_robust_access_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0B029425A1700B30DA7 /* graphics_robust_access_pass.h */; }; + DCFD7D262A45BA9C007BBBF7 /* scalar_analysis_nodes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B14329425A1800B30DA7 /* scalar_analysis_nodes.h */; }; + DCFD7D272A45BA9C007BBBF7 /* operand_to_const_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B03829425A1700B30DA7 /* operand_to_const_reduction_opportunity_finder.h */; }; + DCFD7D282A45BA9C007BBBF7 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0DD29425A1700B30DA7 /* basic_block.h */; }; + DCFD7D292A45BA9C007BBBF7 /* strip_nonsemantic_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0A229425A1700B30DA7 /* strip_nonsemantic_info_pass.h */; }; + DCFD7D2A2A45BA9C007BBBF7 /* fold.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13F29425A1800B30DA7 /* fold.h */; }; + DCFD7D2B2A45BA9C007BBBF7 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B34E29425A1800B30DA7 /* instruction.h */; }; + DCFD7D2C2A45BA9C007BBBF7 /* unify_const_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0D729425A1700B30DA7 /* unify_const_pass.h */; }; + DCFD7D2D2A45BA9C007BBBF7 /* vector_dce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16E29425A1800B30DA7 /* vector_dce.h */; }; + DCFD7D2E2A45BA9C007BBBF7 /* structured_construct_to_block_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B03629425A1700B30DA7 /* structured_construct_to_block_reduction_opportunity.h */; }; + DCFD7D2F2A45BA9C007BBBF7 /* spirv_target_env.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02E29425A1700B30DA7 /* spirv_target_env.h */; }; + DCFD7D302A45BA9C007BBBF7 /* loop_fusion.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0A629425A1700B30DA7 /* loop_fusion.h */; }; + DCFD7D312A45BA9C007BBBF7 /* print.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B09A29425A1700B30DA7 /* print.h */; }; + DCFD7D322A45BA9C007BBBF7 /* structured_loop_to_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04A29425A1700B30DA7 /* structured_loop_to_selection_reduction_opportunity.h */; }; + DCFD7D332A45BA9C007BBBF7 /* dominator_tree.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B18429425A1800B30DA7 /* dominator_tree.h */; }; + DCFD7D342A45BA9C007BBBF7 /* dead_branch_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B14129425A1800B30DA7 /* dead_branch_elim_pass.h */; }; + DCFD7D352A45BA9C007BBBF7 /* ccp_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17829425A1800B30DA7 /* ccp_pass.h */; }; + DCFD7D362A45BA9C007BBBF7 /* validate.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B33D29425A1800B30DA7 /* validate.h */; }; + DCFD7D372A45BA9C007BBBF7 /* construct.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B32829425A1800B30DA7 /* construct.h */; }; + DCFD7D382A45BA9C007BBBF7 /* null_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B15329425A1800B30DA7 /* null_pass.h */; }; + DCFD7D392A45BA9C007BBBF7 /* constants.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B12429425A1800B30DA7 /* constants.h */; }; + DCFD7D3A2A45BA9C007BBBF7 /* validation_state.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B33729425A1800B30DA7 /* validation_state.h */; }; + DCFD7D3B2A45BA9C007BBBF7 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16A29425A1800B30DA7 /* instruction.h */; }; + DCFD7D3C2A45BA9C007BBBF7 /* loop_unswitch_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16529425A1800B30DA7 /* loop_unswitch_pass.h */; }; + DCFD7D3D2A45BA9C007BBBF7 /* tree_iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0AE29425A1700B30DA7 /* tree_iterator.h */; }; + DCFD7D3E2A45BA9C007BBBF7 /* remove_struct_member_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04629425A1700B30DA7 /* remove_struct_member_reduction_opportunity.h */; }; + DCFD7D3F2A45BA9C007BBBF7 /* validate_scopes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B34129425A1800B30DA7 /* validate_scopes.h */; }; + DCFD7D402A45BA9C007BBBF7 /* passes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B14829425A1800B30DA7 /* passes.h */; }; + DCFD7D412A45BA9C007BBBF7 /* interp_fixup_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B10329425A1800B30DA7 /* interp_fixup_pass.h */; }; + DCFD7D422A45BA9C007BBBF7 /* validate_memory_semantics.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B34329425A1800B30DA7 /* validate_memory_semantics.h */; }; + DCFD7D432A45BA9C007BBBF7 /* hash_combine.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02429425A1700B30DA7 /* hash_combine.h */; }; + DCFD7D442A45BA9C007BBBF7 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B06029425A1700B30DA7 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */; }; + DCFD7D452A45BA9C007BBBF7 /* strip_debug_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0B629425A1700B30DA7 /* strip_debug_info_pass.h */; }; + DCFD7D462A45BA9C007BBBF7 /* pch_source_opt.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B15829425A1800B30DA7 /* pch_source_opt.h */; }; + DCFD7D472A45BA9C007BBBF7 /* merge_blocks_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B05229425A1700B30DA7 /* merge_blocks_reduction_opportunity_finder.h */; }; + DCFD7D482A45BA9C007BBBF7 /* reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B06F29425A1700B30DA7 /* reduction_pass.h */; }; + DCFD7D492A45BA9C007BBBF7 /* local_single_store_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0B129425A1700B30DA7 /* local_single_store_elim_pass.h */; }; + DCFD7D4A2A45BA9C007BBBF7 /* latest_version_opencl_std_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B07029425A1700B30DA7 /* latest_version_opencl_std_header.h */; }; + DCFD7D4B2A45BA9C007BBBF7 /* remove_block_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B03329425A1700B30DA7 /* remove_block_reduction_opportunity.h */; }; + DCFD7D4C2A45BA9C007BBBF7 /* remove_function_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B05929425A1700B30DA7 /* remove_function_reduction_opportunity_finder.h */; }; + DCFD7D4D2A45BA9C007BBBF7 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B31A29425A1800B30DA7 /* instruction.h */; }; + DCFD7D4E2A45BA9C007BBBF7 /* eliminate_dead_functions_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13D29425A1800B30DA7 /* eliminate_dead_functions_pass.h */; }; + DCFD7D4F2A45BA9C007BBBF7 /* bit_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02829425A1700B30DA7 /* bit_vector.h */; }; + DCFD7D502A45BA9C007BBBF7 /* assembly_grammar.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B00F29425A1700B30DA7 /* assembly_grammar.h */; }; + DCFD7D512A45BA9C007BBBF7 /* loop_dependence.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B11C29425A1800B30DA7 /* loop_dependence.h */; }; + DCFD7D522A45BA9C007BBBF7 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B03D29425A1700B30DA7 /* simple_conditional_branch_to_branch_reduction_opportunity.h */; }; + DCFD7D532A45BA9C007BBBF7 /* folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13C29425A1800B30DA7 /* folding_rules.h */; }; + DCFD7D542A45BA9C007BBBF7 /* eliminate_dead_members_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B11529425A1800B30DA7 /* eliminate_dead_members_pass.h */; }; + DCFD7D552A45BA9C007BBBF7 /* reduction_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B06629425A1700B30DA7 /* reduction_util.h */; }; + DCFD7D562A45BA9C007BBBF7 /* table.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B18929425A1800B30DA7 /* table.h */; }; + DCFD7D572A45BA9C007BBBF7 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B32F29425A1800B30DA7 /* basic_block.h */; }; + DCFD7D582A45BA9C007BBBF7 /* remove_block_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B06429425A1700B30DA7 /* remove_block_reduction_opportunity_finder.h */; }; + DCFD7D592A45BA9C007BBBF7 /* remove_dontinline_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0E929425A1700B30DA7 /* remove_dontinline_pass.h */; }; + DCFD7D5A2A45BA9C007BBBF7 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B03429425A1700B30DA7 /* operand_to_dominating_id_reduction_opportunity_finder.h */; }; + DCFD7D5B2A45BA9C007BBBF7 /* operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08029425A1700B30DA7 /* operand.h */; }; + DCFD7D5C2A45BA9C007BBBF7 /* disassemble.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B09C29425A1700B30DA7 /* disassemble.h */; }; + DCFD7D5D2A45BA9C007BBBF7 /* remove_unused_instruction_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04C29425A1700B30DA7 /* remove_unused_instruction_reduction_opportunity_finder.h */; }; + DCFD7D5E2A45BA9C007BBBF7 /* value_number_table.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B11D29425A1800B30DA7 /* value_number_table.h */; }; + DCFD7D5F2A45BA9C007BBBF7 /* small_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02329425A1700B30DA7 /* small_vector.h */; }; + DCFD7D602A45BA9C007BBBF7 /* log.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13129425A1800B30DA7 /* log.h */; }; + DCFD7D612A45BA9C007BBBF7 /* ilist_node.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02029425A1700B30DA7 /* ilist_node.h */; }; + DCFD7D622A45BA9C007BBBF7 /* feature_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17F29425A1800B30DA7 /* feature_manager.h */; }; + DCFD7D632A45BA9C007BBBF7 /* loop_fission.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B12E29425A1800B30DA7 /* loop_fission.h */; }; + DCFD7D642A45BA9C007BBBF7 /* interface_var_sroa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0AF29425A1700B30DA7 /* interface_var_sroa.h */; }; + DCFD7D652A45BA9C007BBBF7 /* licm_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17629425A1800B30DA7 /* licm_pass.h */; }; + DCFD7D662A45BA9C007BBBF7 /* convert_to_half_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0E829425A1700B30DA7 /* convert_to_half_pass.h */; }; + DCFD7D672A45BA9C007BBBF7 /* structured_construct_to_block_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B03B29425A1700B30DA7 /* structured_construct_to_block_reduction_opportunity_finder.h */; }; + DCFD7D682A45BA9C007BBBF7 /* fold_spec_constant_op_and_composite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0DB29425A1700B30DA7 /* fold_spec_constant_op_and_composite_pass.h */; }; + DCFD7D692A45BA9C007BBBF7 /* cfg.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16629425A1800B30DA7 /* cfg.h */; }; + DCFD7D6A2A45BA9C007BBBF7 /* remove_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04F29425A1700B30DA7 /* remove_selection_reduction_opportunity.h */; }; + DCFD7D6B2A45BA9C007BBBF7 /* opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B31C29425A1800B30DA7 /* opcode.h */; }; + DCFD7D6C2A45BA9C007BBBF7 /* flatten_decoration_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B11F29425A1800B30DA7 /* flatten_decoration_pass.h */; }; + DCFD7D6D2A45BA9C007BBBF7 /* private_to_local_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0E729425A1700B30DA7 /* private_to_local_pass.h */; }; + DCFD7D6E2A45BA9C007BBBF7 /* wrap_opkill.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0FE29425A1700B30DA7 /* wrap_opkill.h */; }; + DCFD7D6F2A45BA9C007BBBF7 /* text.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B01B29425A1700B30DA7 /* text.h */; }; + DCFD7D702A45BA9C007BBBF7 /* string_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02229425A1700B30DA7 /* string_utils.h */; }; + DCFD7D712A45BA9C007BBBF7 /* debug_info_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0E229425A1700B30DA7 /* debug_info_manager.h */; }; + DCFD7D722A45BA9C007BBBF7 /* fix_storage_class.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B14529425A1800B30DA7 /* fix_storage_class.h */; }; + DCFD7D732A45BA9C007BBBF7 /* copy_prop_arrays.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13229425A1800B30DA7 /* copy_prop_arrays.h */; }; + DCFD7D742A45BA9C007BBBF7 /* change_operand_to_undef_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04D29425A1700B30DA7 /* change_operand_to_undef_reduction_opportunity.h */; }; + DCFD7D752A45BA9C007BBBF7 /* lcs.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08829425A1700B30DA7 /* lcs.h */; }; + DCFD7D762A45BA9C007BBBF7 /* ilist.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02D29425A1700B30DA7 /* ilist.h */; }; + DCFD7D772A45BA9C007BBBF7 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04E29425A1700B30DA7 /* structured_loop_to_selection_reduction_opportunity_finder.h */; }; + DCFD7D782A45BA9C007BBBF7 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B35429425A1800B30DA7 /* function.h */; }; + DCFD7D792A45BA9C007BBBF7 /* eliminate_dead_constant_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13329425A1800B30DA7 /* eliminate_dead_constant_pass.h */; }; + DCFD7D7A2A45BA9C007BBBF7 /* reduce_load_size.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0B229425A1700B30DA7 /* reduce_load_size.h */; }; + DCFD7D7B2A45BA9C007BBBF7 /* set_spec_constant_default_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B18329425A1800B30DA7 /* set_spec_constant_default_value_pass.h */; }; + DCFD7D7C2A45BA9C007BBBF7 /* diagnostic.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B09129425A1700B30DA7 /* diagnostic.h */; }; + DCFD7D7D2A45BA9C007BBBF7 /* dataflow.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B18029425A1800B30DA7 /* dataflow.h */; }; + DCFD7D7E2A45BA9C007BBBF7 /* merge_blocks_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B06729425A1700B30DA7 /* merge_blocks_reduction_opportunity.h */; }; + DCFD7D7F2A45BA9C007BBBF7 /* module.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16129425A1800B30DA7 /* module.h */; }; + DCFD7D802A45BA9C007BBBF7 /* spirv_optimizer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B31B29425A1800B30DA7 /* spirv_optimizer_options.h */; }; + DCFD7D812A45BA9C007BBBF7 /* ext_inst.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B31629425A1800B30DA7 /* ext_inst.h */; }; + DCFD7D822A45BA9C007BBBF7 /* spirv_reducer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B07629425A1700B30DA7 /* spirv_reducer_options.h */; }; + DCFD7D832A45BA9C007BBBF7 /* decoration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B35829425A1800B30DA7 /* decoration.h */; }; + DCFD7D842A45BA9C007BBBF7 /* inst_buff_addr_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B10629425A1800B30DA7 /* inst_buff_addr_check_pass.h */; }; + DCFD7D852A45BA9C007BBBF7 /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17529425A1800B30DA7 /* iterator.h */; }; + DCFD7D862A45BA9C007BBBF7 /* latest_version_glsl_std_450_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B31E29425A1800B30DA7 /* latest_version_glsl_std_450_header.h */; }; + DCFD7D872A45BA9C007BBBF7 /* pch_source_reduce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B05A29425A1700B30DA7 /* pch_source_reduce.h */; }; + DCFD7D882A45BA9C007BBBF7 /* name_mapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08E29425A1700B30DA7 /* name_mapper.h */; }; + DCFD7D892A45BA9C007BBBF7 /* liveness.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0D229425A1700B30DA7 /* liveness.h */; }; + DCFD7D8A2A45BA9C007BBBF7 /* local_redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0F229425A1700B30DA7 /* local_redundancy_elimination.h */; }; + DCFD7D8B2A45BA9C007BBBF7 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04729425A1700B30DA7 /* simple_conditional_branch_to_branch_opportunity_finder.h */; }; + DCFD7D8C2A45BA9C007BBBF7 /* instruction_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0C429425A1700B30DA7 /* instruction_list.h */; }; + DCFD7D8D2A45BA9C007BBBF7 /* diff.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08729425A1700B30DA7 /* diff.h */; }; + DCFD7D8E2A45BA9C007BBBF7 /* instrument_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B11229425A1800B30DA7 /* instrument_pass.h */; }; + DCFD7D8F2A45BA9C007BBBF7 /* binary.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B32129425A1800B30DA7 /* binary.h */; }; + DCFD7D902A45BA9C007BBBF7 /* inline_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B11B29425A1800B30DA7 /* inline_pass.h */; }; + DCFD7D912A45BA9C007BBBF7 /* loop_fusion_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0F929425A1700B30DA7 /* loop_fusion_pass.h */; }; + DCFD7D922A45BA9C007BBBF7 /* dead_variable_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13729425A1800B30DA7 /* dead_variable_elimination.h */; }; + DCFD7D932A45BA9C007BBBF7 /* remove_unused_interface_variables_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B18529425A1800B30DA7 /* remove_unused_interface_variables_pass.h */; }; + DCFD7D942A45BA9C007BBBF7 /* remove_unused_struct_member_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B05529425A1700B30DA7 /* remove_unused_struct_member_reduction_opportunity_finder.h */; }; + DCFD7D952A45BA9C007BBBF7 /* simplification_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B14C29425A1800B30DA7 /* simplification_pass.h */; }; + DCFD7D962A45BA9C007BBBF7 /* remove_duplicates_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B14E29425A1800B30DA7 /* remove_duplicates_pass.h */; }; + DCFD7D972A45BA9C007BBBF7 /* eliminate_dead_io_components_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B10429425A1800B30DA7 /* eliminate_dead_io_components_pass.h */; }; + DCFD7D982A45BA9C007BBBF7 /* enum_string_mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B07429425A1700B30DA7 /* enum_string_mapping.h */; }; + DCFD7D992A45BA9C007BBBF7 /* hex_float.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02A29425A1700B30DA7 /* hex_float.h */; }; + DCFD7D9A2A45BA9C007BBBF7 /* spirv_validator_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08A29425A1700B30DA7 /* spirv_validator_options.h */; }; + DCFD7D9B2A45BA9C007BBBF7 /* desc_sroa_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B14F29425A1800B30DA7 /* desc_sroa_util.h */; }; + DCFD7D9C2A45BA9C007BBBF7 /* remove_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B05129425A1700B30DA7 /* remove_selection_reduction_opportunity_finder.h */; }; + DCFD7D9D2A45BA9C007BBBF7 /* pass_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17029425A1800B30DA7 /* pass_manager.h */; }; + DCFD7D9E2A45BA9C007BBBF7 /* dominator_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13929425A1800B30DA7 /* dominator_analysis.h */; }; + DCFD7D9F2A45BA9C007BBBF7 /* spirv_definition.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B07F29425A1700B30DA7 /* spirv_definition.h */; }; + DCFD7DA02A45BA9C007BBBF7 /* block_merge_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0F529425A1700B30DA7 /* block_merge_util.h */; }; + DCFD7DA12A45BA9C007BBBF7 /* remove_function_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04B29425A1700B30DA7 /* remove_function_reduction_opportunity.h */; }; + DCFD7DA22A45BA9C007BBBF7 /* reducer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B05D29425A1700B30DA7 /* reducer.h */; }; + DCFD7DA32A45BA9C007BBBF7 /* def_use_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0EC29425A1700B30DA7 /* def_use_manager.h */; }; + DCFD7DA42A45BA9C007BBBF7 /* type_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B18629425A1800B30DA7 /* type_manager.h */; }; + DCFD7DA52A45BA9C007BBBF7 /* common_debug_info.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B09729425A1700B30DA7 /* common_debug_info.h */; }; + DCFD7DA62A45BA9C007BBBF7 /* cfg_cleanup_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0EF29425A1700B30DA7 /* cfg_cleanup_pass.h */; }; + DCFD7DA72A45BA9C007BBBF7 /* desc_sroa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0F729425A1700B30DA7 /* desc_sroa.h */; }; + DCFD7DA82A45BA9C007BBBF7 /* local_single_block_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B10229425A1800B30DA7 /* local_single_block_elim_pass.h */; }; + DCFD7DA92A45BA9C007BBBF7 /* spirv_endian.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B09229425A1700B30DA7 /* spirv_endian.h */; }; + DCFD7DAA2A45BA9C007BBBF7 /* redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B15A29425A1800B30DA7 /* redundancy_elimination.h */; }; + DCFD7DAB2A45BA9C007BBBF7 /* combine_access_chains.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16F29425A1800B30DA7 /* combine_access_chains.h */; }; + DCFD7DAC2A45BA9C007BBBF7 /* latest_version_spirv_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B31829425A1800B30DA7 /* latest_version_spirv_header.h */; }; + DCFD7DAD2A45BA9C007BBBF7 /* eliminate_dead_output_stores_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0BD29425A1700B30DA7 /* eliminate_dead_output_stores_pass.h */; }; + DCFD7DAE2A45BA9C007BBBF7 /* spread_volatile_semantics.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17129425A1800B30DA7 /* spread_volatile_semantics.h */; }; + DCFD7DAF2A45BA9C007BBBF7 /* ir_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16329425A1800B30DA7 /* ir_builder.h */; }; + DCFD7DB02A45BA9C007BBBF7 /* build_module.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17729425A1800B30DA7 /* build_module.h */; }; + DCFD7DB12A45BA9C007BBBF7 /* inline_exhaustive_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B12329425A1800B30DA7 /* inline_exhaustive_pass.h */; }; + DCFD7DB22A45BA9C007BBBF7 /* reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B06229425A1700B30DA7 /* reduction_opportunity_finder.h */; }; + DCFD7DB32A45BA9C007BBBF7 /* divergence_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B01629425A1700B30DA7 /* divergence_analysis.h */; }; + DCFD7DB42A45BA9C007BBBF7 /* upgrade_memory_model.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B12929425A1800B30DA7 /* upgrade_memory_model.h */; }; + DCFD7DB52A45BA9C007BBBF7 /* bitutils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02929425A1700B30DA7 /* bitutils.h */; }; + DCFD7DB62A45BA9C007BBBF7 /* parsed_operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08D29425A1700B30DA7 /* parsed_operand.h */; }; + DCFD7DB72A45BA9C007BBBF7 /* spirv_constant.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08329425A1700B30DA7 /* spirv_constant.h */; }; + DCFD7DB82A45BA9C007BBBF7 /* fix_func_call_arguments.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B17B29425A1800B30DA7 /* fix_func_call_arguments.h */; }; + DCFD7DB92A45BA9C007BBBF7 /* eliminate_dead_functions_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13E29425A1800B30DA7 /* eliminate_dead_functions_util.h */; }; + DCFD7DBA2A45BA9C007BBBF7 /* loop_unroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0D329425A1700B30DA7 /* loop_unroller.h */; }; + DCFD7DBB2A45BA9C007BBBF7 /* ssa_rewrite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B13529425A1800B30DA7 /* ssa_rewrite_pass.h */; }; + DCFD7DBC2A45BA9C007BBBF7 /* propagator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0C329425A1700B30DA7 /* propagator.h */; }; + DCFD7DBD2A45BA9C007BBBF7 /* loop_descriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16929425A1800B30DA7 /* loop_descriptor.h */; }; + DCFD7DBE2A45BA9C007BBBF7 /* merge_return_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0A429425A1700B30DA7 /* merge_return_pass.h */; }; + DCFD7DBF2A45BA9C007BBBF7 /* empty_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0FF29425A1800B30DA7 /* empty_pass.h */; }; + DCFD7DC02A45BA9C007BBBF7 /* scalar_replacement_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B15629425A1800B30DA7 /* scalar_replacement_pass.h */; }; + DCFD7DC12A45BA9C007BBBF7 /* code_sink.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16729425A1800B30DA7 /* code_sink.h */; }; + DCFD7DC22A45BA9C007BBBF7 /* change_operand_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B06329425A1700B30DA7 /* change_operand_reduction_opportunity.h */; }; + DCFD7DC32A45BA9C007BBBF7 /* analyze_live_input_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B12B29425A1800B30DA7 /* analyze_live_input_pass.h */; }; + DCFD7DC42A45BA9C007BBBF7 /* cfa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B07229425A1700B30DA7 /* cfa.h */; }; + DCFD7DC52A45BA9C007BBBF7 /* amd_ext_to_khr.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0C929425A1700B30DA7 /* amd_ext_to_khr.h */; }; + DCFD7DC62A45BA9C007BBBF7 /* decoration_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B10029425A1800B30DA7 /* decoration_manager.h */; }; + DCFD7DC72A45BA9C007BBBF7 /* loop_peeling.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0F329425A1700B30DA7 /* loop_peeling.h */; }; + DCFD7DC82A45BA9C007BBBF7 /* replace_desc_array_access_using_var_index.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0B729425A1700B30DA7 /* replace_desc_array_access_using_var_index.h */; }; + DCFD7DC92A45BA9C007BBBF7 /* reflect.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B15129425A1800B30DA7 /* reflect.h */; }; + DCFD7DCA2A45BA9C007BBBF7 /* compact_ids_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0AC29425A1700B30DA7 /* compact_ids_pass.h */; }; + DCFD7DCB2A45BA9C007BBBF7 /* macro.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B08229425A1700B30DA7 /* macro.h */; }; + DCFD7DCC2A45BA9C007BBBF7 /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B02629425A1700B30DA7 /* timer.h */; }; + DCFD7DCD2A45BA9C007BBBF7 /* extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B31F29425A1800B30DA7 /* extensions.h */; }; + DCFD7DCE2A45BA9C007BBBF7 /* mem_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B11329425A1800B30DA7 /* mem_pass.h */; }; + DCFD7DCF2A45BA9C007BBBF7 /* local_access_chain_convert_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0BE29425A1700B30DA7 /* local_access_chain_convert_pass.h */; }; + DCFD7DD02A45BA9C007BBBF7 /* remove_instruction_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B03F29425A1700B30DA7 /* remove_instruction_reduction_opportunity.h */; }; + DCFD7DD12A45BA9C007BBBF7 /* control_dependence.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0CD29425A1700B30DA7 /* control_dependence.h */; }; + DCFD7DD22A45BA9C007BBBF7 /* ir_loader.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0D829425A1700B30DA7 /* ir_loader.h */; }; + DCFD7DD32A45BA9C007BBBF7 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B04029425A1700B30DA7 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */; }; + DCFD7DD42A45BA9C007BBBF7 /* workaround1209.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B12F29425A1800B30DA7 /* workaround1209.h */; }; + DCFD7DD52A45BA9C007BBBF7 /* register_pressure.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0AD29425A1700B30DA7 /* register_pressure.h */; }; + DCFD7DD62A45BA9C007BBBF7 /* operand_to_undef_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B03129425A1700B30DA7 /* operand_to_undef_reduction_opportunity_finder.h */; }; + DCFD7DD72A45BA9C007BBBF7 /* struct_cfg_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B0FA29425A1700B30DA7 /* struct_cfg_analysis.h */; }; + DCFD7DD82A45BA9C007BBBF7 /* spirv_fuzzer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B00E29425A1700B30DA7 /* spirv_fuzzer_options.h */; }; + DCFD7DD92A45BA9C007BBBF7 /* const_folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B15529425A1800B30DA7 /* const_folding_rules.h */; }; + DCFD7DDA2A45BA9C007BBBF7 /* inst_bindless_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B18129425A1800B30DA7 /* inst_bindless_check_pass.h */; }; + DCFD7DDB2A45BA9C007BBBF7 /* aggressive_dead_code_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B16B29425A1800B30DA7 /* aggressive_dead_code_elim_pass.h */; }; + DCFD7DDC2A45BA9C007BBBF7 /* if_conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F7B09F29425A1700B30DA7 /* if_conversion.h */; }; + DCFD7DDE2A45BA9C007BBBF7 /* spirv_reducer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B08F29425A1700B30DA7 /* spirv_reducer_options.cpp */; }; + DCFD7DDF2A45BA9C007BBBF7 /* register_pressure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0A029425A1700B30DA7 /* register_pressure.cpp */; }; + DCFD7DE02A45BA9C007BBBF7 /* loop_peeling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B18829425A1800B30DA7 /* loop_peeling.cpp */; }; + DCFD7DE12A45BA9C007BBBF7 /* block_merge_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B13829425A1800B30DA7 /* block_merge_pass.cpp */; }; + DCFD7DE22A45BA9C007BBBF7 /* opcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B09929425A1700B30DA7 /* opcode.cpp */; }; + DCFD7DE32A45BA9C007BBBF7 /* validate_builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33429425A1800B30DA7 /* validate_builtins.cpp */; }; + DCFD7DE42A45BA9C007BBBF7 /* validate_non_uniform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32A29425A1800B30DA7 /* validate_non_uniform.cpp */; }; + DCFD7DE52A45BA9C007BBBF7 /* table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B02F29425A1700B30DA7 /* table.cpp */; }; + DCFD7DE62A45BA9C007BBBF7 /* validate_logicals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34729425A1800B30DA7 /* validate_logicals.cpp */; }; + DCFD7DE72A45BA9C007BBBF7 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05E29425A1700B30DA7 /* change_operand_to_undef_reduction_opportunity.cpp */; }; + DCFD7DE82A45BA9C007BBBF7 /* bit_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B02C29425A1700B30DA7 /* bit_vector.cpp */; }; + DCFD7DE92A45BA9C007BBBF7 /* ir_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B11129425A1800B30DA7 /* ir_context.cpp */; }; + DCFD7DEA2A45BA9C007BBBF7 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B03C29425A1700B30DA7 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */; }; + DCFD7DEB2A45BA9C007BBBF7 /* if_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12029425A1800B30DA7 /* if_conversion.cpp */; }; + DCFD7DEC2A45BA9C007BBBF7 /* remove_dontinline_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B16D29425A1800B30DA7 /* remove_dontinline_pass.cpp */; }; + DCFD7DED2A45BA9C007BBBF7 /* convert_to_sampled_image_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B13A29425A1800B30DA7 /* convert_to_sampled_image_pass.cpp */; }; + DCFD7DEE2A45BA9C007BBBF7 /* merge_return_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0CA29425A1700B30DA7 /* merge_return_pass.cpp */; }; + DCFD7DEF2A45BA9C007BBBF7 /* reducer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05729425A1700B30DA7 /* reducer.cpp */; }; + DCFD7DF02A45BA9C007BBBF7 /* remove_function_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B04229425A1700B30DA7 /* remove_function_reduction_opportunity.cpp */; }; + DCFD7DF12A45BA9C007BBBF7 /* disassemble.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32029425A1800B30DA7 /* disassemble.cpp */; }; + DCFD7DF22A45BA9C007BBBF7 /* composite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B11929425A1800B30DA7 /* composite.cpp */; }; + DCFD7DF32A45BA9C007BBBF7 /* validate_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33F29425A1800B30DA7 /* validate_conversion.cpp */; }; + DCFD7DF42A45BA9C007BBBF7 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34C29425A1800B30DA7 /* instruction.cpp */; }; + DCFD7DF52A45BA9C007BBBF7 /* validate_ray_query.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32B29425A1800B30DA7 /* validate_ray_query.cpp */; }; + DCFD7DF62A45BA9C007BBBF7 /* operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B31D29425A1800B30DA7 /* operand.cpp */; }; + DCFD7DF72A45BA9C007BBBF7 /* unify_const_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0E529425A1700B30DA7 /* unify_const_pass.cpp */; }; + DCFD7DF82A45BA9C007BBBF7 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B03729425A1700B30DA7 /* operand_to_const_reduction_opportunity_finder.cpp */; }; + DCFD7DF92A45BA9C007BBBF7 /* enum_string_mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B08B29425A1700B30DA7 /* enum_string_mapping.cpp */; }; + DCFD7DFA2A45BA9C007BBBF7 /* validate_mode_setting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34529425A1800B30DA7 /* validate_mode_setting.cpp */; }; + DCFD7DFB2A45BA9C007BBBF7 /* binary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B08429425A1700B30DA7 /* binary.cpp */; }; + DCFD7DFC2A45BA9C007BBBF7 /* struct_cfg_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B16C29425A1800B30DA7 /* struct_cfg_analysis.cpp */; }; + DCFD7DFD2A45BA9C007BBBF7 /* validate_capability.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32729425A1800B30DA7 /* validate_capability.cpp */; }; + DCFD7DFE2A45BA9C007BBBF7 /* diagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B31729425A1800B30DA7 /* diagnostic.cpp */; }; + DCFD7DFF2A45BA9C007BBBF7 /* libspirv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B31929425A1800B30DA7 /* libspirv.cpp */; }; + DCFD7E002A45BA9C007BBBF7 /* validate_mesh_shading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34F29425A1800B30DA7 /* validate_mesh_shading.cpp */; }; + DCFD7E012A45BA9C007BBBF7 /* build_module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0A829425A1700B30DA7 /* build_module.cpp */; }; + DCFD7E022A45BA9C007BBBF7 /* cfg_cleanup_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0CE29425A1700B30DA7 /* cfg_cleanup_pass.cpp */; }; + DCFD7E032A45BA9C007BBBF7 /* spirv_fuzzer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B07529425A1700B30DA7 /* spirv_fuzzer_options.cpp */; }; + DCFD7E042A45BA9C007BBBF7 /* validate_adjacency.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33E29425A1800B30DA7 /* validate_adjacency.cpp */; }; + DCFD7E052A45BA9C007BBBF7 /* validate_id.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34229425A1800B30DA7 /* validate_id.cpp */; }; + DCFD7E062A45BA9C007BBBF7 /* parse_number.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B02B29425A1700B30DA7 /* parse_number.cpp */; }; + DCFD7E072A45BA9C007BBBF7 /* scalar_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B13629425A1800B30DA7 /* scalar_analysis.cpp */; }; + DCFD7E082A45BA9C007BBBF7 /* lint_divergent_derivatives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B01229425A1700B30DA7 /* lint_divergent_derivatives.cpp */; }; + DCFD7E092A45BA9C007BBBF7 /* remove_struct_member_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05429425A1700B30DA7 /* remove_struct_member_reduction_opportunity.cpp */; }; + DCFD7E0A2A45BA9C007BBBF7 /* validate_scopes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32D29425A1800B30DA7 /* validate_scopes.cpp */; }; + DCFD7E0B2A45BA9C007BBBF7 /* strip_debug_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0D429425A1700B30DA7 /* strip_debug_info_pass.cpp */; }; + DCFD7E0C2A45BA9C007BBBF7 /* eliminate_dead_functions_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B10929425A1800B30DA7 /* eliminate_dead_functions_util.cpp */; }; + DCFD7E0D2A45BA9C007BBBF7 /* remove_function_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B03E29425A1700B30DA7 /* remove_function_reduction_opportunity_finder.cpp */; }; + DCFD7E0E2A45BA9C007BBBF7 /* ssa_rewrite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0D529425A1700B30DA7 /* ssa_rewrite_pass.cpp */; }; + DCFD7E0F2A45BA9C007BBBF7 /* validate_image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34A29425A1800B30DA7 /* validate_image.cpp */; }; + DCFD7E102A45BA9C007BBBF7 /* module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0E129425A1700B30DA7 /* module.cpp */; }; + DCFD7E112A45BA9C007BBBF7 /* merge_blocks_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B04829425A1700B30DA7 /* merge_blocks_reduction_opportunity.cpp */; }; + DCFD7E122A45BA9C007BBBF7 /* constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0F829425A1700B30DA7 /* constants.cpp */; }; + DCFD7E132A45BA9C007BBBF7 /* remove_block_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06B29425A1700B30DA7 /* remove_block_reduction_opportunity.cpp */; }; + DCFD7E142A45BA9C007BBBF7 /* spirv_target_env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B00D29425A1700B30DA7 /* spirv_target_env.cpp */; }; + DCFD7E152A45BA9C007BBBF7 /* loop_fission.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0C729425A1700B30DA7 /* loop_fission.cpp */; }; + DCFD7E162A45BA9C007BBBF7 /* remove_block_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06529425A1700B30DA7 /* remove_block_reduction_opportunity_finder.cpp */; }; + DCFD7E172A45BA9C007BBBF7 /* remove_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B04429425A1700B30DA7 /* remove_selection_reduction_opportunity_finder.cpp */; }; + DCFD7E182A45BA9C007BBBF7 /* fold.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14929425A1800B30DA7 /* fold.cpp */; }; + DCFD7E192A45BA9C007BBBF7 /* def_use_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0FD29425A1700B30DA7 /* def_use_manager.cpp */; }; + DCFD7E1A2A45BA9C007BBBF7 /* parsed_operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B09029425A1700B30DA7 /* parsed_operand.cpp */; }; + DCFD7E1B2A45BA9C007BBBF7 /* eliminate_dead_members_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12529425A1800B30DA7 /* eliminate_dead_members_pass.cpp */; }; + DCFD7E1C2A45BA9C007BBBF7 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15729425A1800B30DA7 /* instruction.cpp */; }; + DCFD7E1D2A45BA9C007BBBF7 /* name_mapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B09329425A1700B30DA7 /* name_mapper.cpp */; }; + DCFD7E1E2A45BA9C007BBBF7 /* analyze_live_input_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B17D29425A1800B30DA7 /* analyze_live_input_pass.cpp */; }; + DCFD7E1F2A45BA9C007BBBF7 /* validate_cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32629425A1800B30DA7 /* validate_cfg.cpp */; }; + DCFD7E202A45BA9C007BBBF7 /* change_operand_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B04929425A1700B30DA7 /* change_operand_reduction_opportunity.cpp */; }; + DCFD7E212A45BA9C007BBBF7 /* validate_instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33029425A1800B30DA7 /* validate_instruction.cpp */; }; + DCFD7E222A45BA9C007BBBF7 /* instrument_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0C229425A1700B30DA7 /* instrument_pass.cpp */; }; + DCFD7E232A45BA9C007BBBF7 /* validate_ray_tracing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32C29425A1800B30DA7 /* validate_ray_tracing.cpp */; }; + DCFD7E242A45BA9C007BBBF7 /* pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0C629425A1700B30DA7 /* pass.cpp */; }; + DCFD7E252A45BA9C007BBBF7 /* ccp_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B10129425A1800B30DA7 /* ccp_pass.cpp */; }; + DCFD7E262A45BA9C007BBBF7 /* desc_sroa_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0FB29425A1700B30DA7 /* desc_sroa_util.cpp */; }; + DCFD7E272A45BA9C007BBBF7 /* validate_bitwise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33929425A1800B30DA7 /* validate_bitwise.cpp */; }; + DCFD7E282A45BA9C007BBBF7 /* block_merge_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12829425A1800B30DA7 /* block_merge_util.cpp */; }; + DCFD7E292A45BA9C007BBBF7 /* validate_debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33329425A1800B30DA7 /* validate_debug.cpp */; }; + DCFD7E2A2A45BA9C007BBBF7 /* loop_descriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B11429425A1800B30DA7 /* loop_descriptor.cpp */; }; + DCFD7E2B2A45BA9C007BBBF7 /* linker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B09629425A1700B30DA7 /* linker.cpp */; }; + DCFD7E2C2A45BA9C007BBBF7 /* freeze_spec_constant_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0BB29425A1700B30DA7 /* freeze_spec_constant_value_pass.cpp */; }; + DCFD7E2D2A45BA9C007BBBF7 /* string_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B02729425A1700B30DA7 /* string_utils.cpp */; }; + DCFD7E2E2A45BA9C007BBBF7 /* validate_memory_semantics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34629425A1800B30DA7 /* validate_memory_semantics.cpp */; }; + DCFD7E2F2A45BA9C007BBBF7 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0B429425A1700B30DA7 /* types.cpp */; }; + DCFD7E302A45BA9C007BBBF7 /* pch_source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B01D29425A1700B30DA7 /* pch_source.cpp */; }; + DCFD7E312A45BA9C007BBBF7 /* print.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B07E29425A1700B30DA7 /* print.cpp */; }; + DCFD7E322A45BA9C007BBBF7 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33C29425A1800B30DA7 /* function.cpp */; }; + DCFD7E332A45BA9C007BBBF7 /* inline_exhaustive_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12D29425A1800B30DA7 /* inline_exhaustive_pass.cpp */; }; + DCFD7E342A45BA9C007BBBF7 /* eliminate_dead_constant_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0CC29425A1700B30DA7 /* eliminate_dead_constant_pass.cpp */; }; + DCFD7E352A45BA9C007BBBF7 /* inline_opaque_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15E29425A1800B30DA7 /* inline_opaque_pass.cpp */; }; + DCFD7E362A45BA9C007BBBF7 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06829425A1700B30DA7 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */; }; + DCFD7E372A45BA9C007BBBF7 /* linter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B01329425A1700B30DA7 /* linter.cpp */; }; + DCFD7E382A45BA9C007BBBF7 /* eliminate_dead_output_stores_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0A929425A1700B30DA7 /* eliminate_dead_output_stores_pass.cpp */; }; + DCFD7E392A45BA9C007BBBF7 /* compact_ids_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B18729425A1800B30DA7 /* compact_ids_pass.cpp */; }; + DCFD7E3A2A45BA9C007BBBF7 /* folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B10F29425A1800B30DA7 /* folding_rules.cpp */; }; + DCFD7E3B2A45BA9C007BBBF7 /* strip_nonsemantic_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B11E29425A1800B30DA7 /* strip_nonsemantic_info_pass.cpp */; }; + DCFD7E3C2A45BA9C007BBBF7 /* private_to_local_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14229425A1800B30DA7 /* private_to_local_pass.cpp */; }; + DCFD7E3D2A45BA9C007BBBF7 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0E329425A1700B30DA7 /* fold_spec_constant_op_and_composite_pass.cpp */; }; + DCFD7E3E2A45BA9C007BBBF7 /* validate_ray_tracing_reorder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33129425A1800B30DA7 /* validate_ray_tracing_reorder.cpp */; }; + DCFD7E3F2A45BA9C007BBBF7 /* validate_derivatives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34829425A1800B30DA7 /* validate_derivatives.cpp */; }; + DCFD7E402A45BA9C007BBBF7 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B04129425A1700B30DA7 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */; }; + DCFD7E412A45BA9C007BBBF7 /* control_dependence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B11829425A1800B30DA7 /* control_dependence.cpp */; }; + DCFD7E422A45BA9C007BBBF7 /* spirv_optimizer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B07129425A1700B30DA7 /* spirv_optimizer_options.cpp */; }; + DCFD7E432A45BA9C007BBBF7 /* pch_source_reduce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05329425A1700B30DA7 /* pch_source_reduce.cpp */; }; + DCFD7E442A45BA9C007BBBF7 /* dead_variable_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0DF29425A1700B30DA7 /* dead_variable_elimination.cpp */; }; + DCFD7E452A45BA9C007BBBF7 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B04529425A1700B30DA7 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */; }; + DCFD7E462A45BA9C007BBBF7 /* strength_reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12629425A1800B30DA7 /* strength_reduction_pass.cpp */; }; + DCFD7E472A45BA9C007BBBF7 /* scalar_analysis_simplification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B18229425A1800B30DA7 /* scalar_analysis_simplification.cpp */; }; + DCFD7E482A45BA9C007BBBF7 /* validate_interfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33529425A1800B30DA7 /* validate_interfaces.cpp */; }; + DCFD7E492A45BA9C007BBBF7 /* validate_atomics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32E29425A1800B30DA7 /* validate_atomics.cpp */; }; + DCFD7E4A2A45BA9C007BBBF7 /* ext_inst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B09B29425A1700B30DA7 /* ext_inst.cpp */; }; + DCFD7E4B2A45BA9C007BBBF7 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06129425A1700B30DA7 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */; }; + DCFD7E4C2A45BA9C007BBBF7 /* decoration_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0B929425A1700B30DA7 /* decoration_manager.cpp */; }; + DCFD7E4D2A45BA9C007BBBF7 /* workaround1209.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15229425A1800B30DA7 /* workaround1209.cpp */; }; + DCFD7E4E2A45BA9C007BBBF7 /* interp_fixup_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B17329425A1800B30DA7 /* interp_fixup_pass.cpp */; }; + DCFD7E4F2A45BA9C007BBBF7 /* validate_literals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34B29425A1800B30DA7 /* validate_literals.cpp */; }; + DCFD7E502A45BA9C007BBBF7 /* diff.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B08929425A1700B30DA7 /* diff.cpp */; }; + DCFD7E512A45BA9C007BBBF7 /* dominator_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0C829425A1700B30DA7 /* dominator_tree.cpp */; }; + DCFD7E522A45BA9C007BBBF7 /* interface_var_sroa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14D29425A1800B30DA7 /* interface_var_sroa.cpp */; }; + DCFD7E532A45BA9C007BBBF7 /* upgrade_memory_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B17E29425A1800B30DA7 /* upgrade_memory_model.cpp */; }; + DCFD7E542A45BA9C007BBBF7 /* combine_access_chains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0A729425A1700B30DA7 /* combine_access_chains.cpp */; }; + DCFD7E552A45BA9C007BBBF7 /* instruction_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B11729425A1800B30DA7 /* instruction_list.cpp */; }; + DCFD7E562A45BA9C007BBBF7 /* aggressive_dead_code_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B10829425A1800B30DA7 /* aggressive_dead_code_elim_pass.cpp */; }; + DCFD7E572A45BA9C007BBBF7 /* reduction_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B03A29425A1700B30DA7 /* reduction_util.cpp */; }; + DCFD7E582A45BA9C007BBBF7 /* eliminate_dead_functions_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0F129425A1700B30DA7 /* eliminate_dead_functions_pass.cpp */; }; + DCFD7E592A45BA9C007BBBF7 /* validate_small_type_uses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34029425A1800B30DA7 /* validate_small_type_uses.cpp */; }; + DCFD7E5A2A45BA9C007BBBF7 /* validate_misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32529425A1800B30DA7 /* validate_misc.cpp */; }; + DCFD7E5B2A45BA9C007BBBF7 /* code_sink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0B329425A1700B30DA7 /* code_sink.cpp */; }; + DCFD7E5C2A45BA9C007BBBF7 /* pass_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12C29425A1800B30DA7 /* pass_manager.cpp */; }; + DCFD7E5D2A45BA9C007BBBF7 /* feature_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0C529425A1700B30DA7 /* feature_manager.cpp */; }; + DCFD7E5E2A45BA9C007BBBF7 /* wrap_opkill.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0CF29425A1700B30DA7 /* wrap_opkill.cpp */; }; + DCFD7E5F2A45BA9C007BBBF7 /* dataflow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B16829425A1800B30DA7 /* dataflow.cpp */; }; + DCFD7E602A45BA9C007BBBF7 /* validate_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34D29425A1800B30DA7 /* validate_type.cpp */; }; + DCFD7E612A45BA9C007BBBF7 /* set_spec_constant_default_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14729425A1800B30DA7 /* set_spec_constant_default_value_pass.cpp */; }; + DCFD7E622A45BA9C007BBBF7 /* remove_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B03229425A1700B30DA7 /* remove_selection_reduction_opportunity.cpp */; }; + DCFD7E632A45BA9C007BBBF7 /* validate_constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33829425A1800B30DA7 /* validate_constants.cpp */; }; + DCFD7E642A45BA9C007BBBF7 /* validate_layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B35129425A1800B30DA7 /* validate_layout.cpp */; }; + DCFD7E652A45BA9C007BBBF7 /* const_folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0D129425A1700B30DA7 /* const_folding_rules.cpp */; }; + DCFD7E662A45BA9C007BBBF7 /* replace_invalid_opc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15F29425A1800B30DA7 /* replace_invalid_opc.cpp */; }; + DCFD7E672A45BA9C007BBBF7 /* eliminate_dead_io_components_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0D029425A1700B30DA7 /* eliminate_dead_io_components_pass.cpp */; }; + DCFD7E682A45BA9C007BBBF7 /* structured_construct_to_block_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06E29425A1700B30DA7 /* structured_construct_to_block_reduction_opportunity_finder.cpp */; }; + DCFD7E692A45BA9C007BBBF7 /* reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06D29425A1700B30DA7 /* reduction_opportunity_finder.cpp */; }; + DCFD7E6A2A45BA9C007BBBF7 /* liveness.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0AB29425A1700B30DA7 /* liveness.cpp */; }; + DCFD7E6B2A45BA9C007BBBF7 /* debug_info_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12229425A1800B30DA7 /* debug_info_manager.cpp */; }; + DCFD7E6C2A45BA9C007BBBF7 /* relax_float_ops_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15429425A1800B30DA7 /* relax_float_ops_pass.cpp */; }; + DCFD7E6D2A45BA9C007BBBF7 /* value_number_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15C29425A1800B30DA7 /* value_number_table.cpp */; }; + DCFD7E6E2A45BA9C007BBBF7 /* text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B01929425A1700B30DA7 /* text.cpp */; }; + DCFD7E6F2A45BA9C007BBBF7 /* local_single_store_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14029425A1800B30DA7 /* local_single_store_elim_pass.cpp */; }; + DCFD7E702A45BA9C007BBBF7 /* remove_unused_instruction_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05629425A1700B30DA7 /* remove_unused_instruction_reduction_opportunity_finder.cpp */; }; + DCFD7E712A45BA9C007BBBF7 /* reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B03529425A1700B30DA7 /* reduction_pass.cpp */; }; + DCFD7E722A45BA9C007BBBF7 /* convert_to_half_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B11A29425A1800B30DA7 /* convert_to_half_pass.cpp */; }; + DCFD7E732A45BA9C007BBBF7 /* reduce_load_size.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15929425A1800B30DA7 /* reduce_load_size.cpp */; }; + DCFD7E742A45BA9C007BBBF7 /* local_access_chain_convert_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B17229425A1800B30DA7 /* local_access_chain_convert_pass.cpp */; }; + DCFD7E752A45BA9C007BBBF7 /* inst_bindless_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0BF29425A1700B30DA7 /* inst_bindless_check_pass.cpp */; }; + DCFD7E762A45BA9C007BBBF7 /* local_single_block_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0BA29425A1700B30DA7 /* local_single_block_elim_pass.cpp */; }; + DCFD7E772A45BA9C007BBBF7 /* validate_execution_limitations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B35029425A1800B30DA7 /* validate_execution_limitations.cpp */; }; + DCFD7E782A45BA9C007BBBF7 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B11629425A1800B30DA7 /* function.cpp */; }; + DCFD7E792A45BA9C007BBBF7 /* fix_func_call_arguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12129425A1800B30DA7 /* fix_func_call_arguments.cpp */; }; + DCFD7E7A2A45BA9C007BBBF7 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06929425A1700B30DA7 /* structured_loop_to_selection_reduction_opportunity.cpp */; }; + DCFD7E7B2A45BA9C007BBBF7 /* graphics_robust_access_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B17929425A1800B30DA7 /* graphics_robust_access_pass.cpp */; }; + DCFD7E7C2A45BA9C007BBBF7 /* construct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33B29425A1800B30DA7 /* construct.cpp */; }; + DCFD7E7D2A45BA9C007BBBF7 /* loop_unroller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0F629425A1700B30DA7 /* loop_unroller.cpp */; }; + DCFD7E7E2A45BA9C007BBBF7 /* spirv_validator_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B07729425A1700B30DA7 /* spirv_validator_options.cpp */; }; + DCFD7E7F2A45BA9C007BBBF7 /* divergence_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B01429425A1700B30DA7 /* divergence_analysis.cpp */; }; + DCFD7E802A45BA9C007BBBF7 /* loop_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0A129425A1700B30DA7 /* loop_utils.cpp */; }; + DCFD7E812A45BA9C007BBBF7 /* spread_volatile_semantics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0A329425A1700B30DA7 /* spread_volatile_semantics.cpp */; }; + DCFD7E822A45BA9C007BBBF7 /* desc_sroa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12729425A1800B30DA7 /* desc_sroa.cpp */; }; + DCFD7E832A45BA9C007BBBF7 /* dead_insert_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B13429425A1800B30DA7 /* dead_insert_elim_pass.cpp */; }; + DCFD7E842A45BA9C007BBBF7 /* validate_decorations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33229425A1800B30DA7 /* validate_decorations.cpp */; }; + DCFD7E852A45BA9C007BBBF7 /* loop_fusion_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B13029425A1800B30DA7 /* loop_fusion_pass.cpp */; }; + DCFD7E862A45BA9C007BBBF7 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05B29425A1700B30DA7 /* merge_blocks_reduction_opportunity_finder.cpp */; }; + DCFD7E872A45BA9C007BBBF7 /* flatten_decoration_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B10D29425A1800B30DA7 /* flatten_decoration_pass.cpp */; }; + DCFD7E882A45BA9C007BBBF7 /* fix_storage_class.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15B29425A1800B30DA7 /* fix_storage_class.cpp */; }; + DCFD7E892A45BA9C007BBBF7 /* software_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B09829425A1700B30DA7 /* software_version.cpp */; }; + DCFD7E8A2A45BA9C007BBBF7 /* assembly_grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B01A29425A1700B30DA7 /* assembly_grammar.cpp */; }; + DCFD7E8B2A45BA9C007BBBF7 /* amd_ext_to_khr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14A29425A1800B30DA7 /* amd_ext_to_khr.cpp */; }; + DCFD7E8C2A45BA9C007BBBF7 /* text_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32229425A1800B30DA7 /* text_handler.cpp */; }; + DCFD7E8D2A45BA9C007BBBF7 /* optimizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B09E29425A1700B30DA7 /* optimizer.cpp */; }; + DCFD7E8E2A45BA9C007BBBF7 /* validation_state.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B35629425A1800B30DA7 /* validation_state.cpp */; }; + DCFD7E8F2A45BA9C007BBBF7 /* mem_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0DC29425A1700B30DA7 /* mem_pass.cpp */; }; + DCFD7E902A45BA9C007BBBF7 /* replace_desc_array_access_using_var_index.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B16429425A1800B30DA7 /* replace_desc_array_access_using_var_index.cpp */; }; + DCFD7E912A45BA9C007BBBF7 /* ir_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0ED29425A1700B30DA7 /* ir_loader.cpp */; }; + DCFD7E922A45BA9C007BBBF7 /* extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B01C29425A1700B30DA7 /* extensions.cpp */; }; + DCFD7E932A45BA9C007BBBF7 /* type_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0E629425A1700B30DA7 /* type_manager.cpp */; }; + DCFD7E942A45BA9C007BBBF7 /* scalar_replacement_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14B29425A1800B30DA7 /* scalar_replacement_pass.cpp */; }; + DCFD7E952A45BA9C007BBBF7 /* loop_unswitch_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0E429425A1700B30DA7 /* loop_unswitch_pass.cpp */; }; + DCFD7E962A45BA9C007BBBF7 /* reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05C29425A1700B30DA7 /* reduction_opportunity.cpp */; }; + DCFD7E972A45BA9C007BBBF7 /* validate_extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33A29425A1800B30DA7 /* validate_extensions.cpp */; }; + DCFD7E982A45BA9C007BBBF7 /* remove_unused_struct_member_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06C29425A1700B30DA7 /* remove_unused_struct_member_reduction_opportunity_finder.cpp */; }; + DCFD7E992A45BA9C007BBBF7 /* timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B02529425A1700B30DA7 /* timer.cpp */; }; + DCFD7E9A2A45BA9C007BBBF7 /* pch_source_opt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B10529425A1800B30DA7 /* pch_source_opt.cpp */; }; + DCFD7E9B2A45BA9C007BBBF7 /* inline_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0EB29425A1700B30DA7 /* inline_pass.cpp */; }; + DCFD7E9C2A45BA9C007BBBF7 /* inst_buff_addr_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0FC29425A1700B30DA7 /* inst_buff_addr_check_pass.cpp */; }; + DCFD7E9D2A45BA9C007BBBF7 /* validate_barriers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32929425A1800B30DA7 /* validate_barriers.cpp */; }; + DCFD7E9E2A45BA9C007BBBF7 /* redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15029425A1800B30DA7 /* redundancy_elimination.cpp */; }; + DCFD7E9F2A45BA9C007BBBF7 /* spirv_endian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B08129425A1700B30DA7 /* spirv_endian.cpp */; }; + DCFD7EA02A45BA9C007BBBF7 /* cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0B829425A1700B30DA7 /* cfg.cpp */; }; + DCFD7EA12A45BA9C007BBBF7 /* remove_duplicates_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0DE29425A1700B30DA7 /* remove_duplicates_pass.cpp */; }; + DCFD7EA22A45BA9C007BBBF7 /* validate_annotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B32429425A1800B30DA7 /* validate_annotation.cpp */; }; + DCFD7EA32A45BA9C007BBBF7 /* loop_dependence_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14629425A1800B30DA7 /* loop_dependence_helpers.cpp */; }; + DCFD7EA42A45BA9C007BBBF7 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B17429425A1800B30DA7 /* basic_block.cpp */; }; + DCFD7EA52A45BA9C007BBBF7 /* loop_dependence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0D629425A1700B30DA7 /* loop_dependence.cpp */; }; + DCFD7EA62A45BA9C007BBBF7 /* licm_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0F029425A1700B30DA7 /* licm_pass.cpp */; }; + DCFD7EA72A45BA9C007BBBF7 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05829425A1700B30DA7 /* operand_to_undef_reduction_opportunity_finder.cpp */; }; + DCFD7EA82A45BA9C007BBBF7 /* dead_branch_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B10C29425A1800B30DA7 /* dead_branch_elim_pass.cpp */; }; + DCFD7EA92A45BA9C007BBBF7 /* inst_debug_printf_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0D929425A1700B30DA7 /* inst_debug_printf_pass.cpp */; }; + DCFD7EAA2A45BA9C007BBBF7 /* local_redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0C029425A1700B30DA7 /* local_redundancy_elimination.cpp */; }; + DCFD7EAB2A45BA9C007BBBF7 /* validate_memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34929425A1800B30DA7 /* validate_memory.cpp */; }; + DCFD7EAC2A45BA9C007BBBF7 /* dominator_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B16229425A1800B30DA7 /* dominator_analysis.cpp */; }; + DCFD7EAD2A45BA9C007BBBF7 /* validate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B33629425A1800B30DA7 /* validate.cpp */; }; + DCFD7EAE2A45BA9C007BBBF7 /* copy_prop_arrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B12A29425A1800B30DA7 /* copy_prop_arrays.cpp */; }; + DCFD7EAF2A45BA9C007BBBF7 /* structured_construct_to_block_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B06A29425A1700B30DA7 /* structured_construct_to_block_reduction_opportunity.cpp */; }; + DCFD7EB02A45BA9C007BBBF7 /* validate_composites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B35529425A1800B30DA7 /* validate_composites.cpp */; }; + DCFD7EB12A45BA9C007BBBF7 /* loop_fusion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B17C29425A1800B30DA7 /* loop_fusion.cpp */; }; + DCFD7EB22A45BA9C007BBBF7 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B35229425A1800B30DA7 /* basic_block.cpp */; }; + DCFD7EB32A45BA9C007BBBF7 /* remove_unused_interface_variables_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B15D29425A1800B30DA7 /* remove_unused_interface_variables_pass.cpp */; }; + DCFD7EB42A45BA9C007BBBF7 /* validate_function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B35329425A1800B30DA7 /* validate_function.cpp */; }; + DCFD7EB52A45BA9C007BBBF7 /* vector_dce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B0F429425A1700B30DA7 /* vector_dce.cpp */; }; + DCFD7EB62A45BA9C007BBBF7 /* validate_primitives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B35729425A1800B30DA7 /* validate_primitives.cpp */; }; + DCFD7EB72A45BA9C007BBBF7 /* simplification_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B10B29425A1800B30DA7 /* simplification_pass.cpp */; }; + DCFD7EB82A45BA9C007BBBF7 /* propagator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B14429425A1800B30DA7 /* propagator.cpp */; }; + DCFD7EB92A45BA9C007BBBF7 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B04329425A1700B30DA7 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */; }; + DCFD7EBA2A45BA9C007BBBF7 /* remove_instruction_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B05029425A1700B30DA7 /* remove_instruction_reduction_opportunity.cpp */; }; + DCFD7EBB2A45BA9C007BBBF7 /* validate_arithmetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F7B34429425A1800B30DA7 /* validate_arithmetics.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1785,6 +2343,27 @@ remoteGlobalIDString = A972ABDD21CED7CB0013AB25; remoteInfo = "glslang-macOS"; }; + DCFD7ECC2A45BC08007BBBF7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A9F55D25198BE6A7004EC31B /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCFD7C892A45BA7D007BBBF7; + remoteInfo = "SPIRV-Cross-xrOS"; + }; + DCFD7ECE2A45BC0C007BBBF7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A9F55D25198BE6A7004EC31B /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCFD7D0C2A45BA9C007BBBF7; + remoteInfo = "SPIRV-Tools-xrOS"; + }; + DCFD7ED02A45BC10007BBBF7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A9F55D25198BE6A7004EC31B /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCFD7CA42A45BA92007BBBF7; + remoteInfo = "glslang-xrOS"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -2361,6 +2940,9 @@ A9F7B35729425A1800B30DA7 /* validate_primitives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_primitives.cpp; sourceTree = ""; }; A9F7B35829425A1800B30DA7 /* decoration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decoration.h; sourceTree = ""; }; A9FC5F7F249DA96D003CB086 /* package_ext_libs_finish.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = package_ext_libs_finish.sh; sourceTree = ""; }; + DCFD7CA32A45BA7D007BBBF7 /* libSPIRVCross.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSPIRVCross.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DCFD7D0B2A45BA92007BBBF7 /* libglslang.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libglslang.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DCFD7EC02A45BA9C007BBBF7 /* libSPIRVTools.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSPIRVTools.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -2651,6 +3233,9 @@ A90FD9E921CC519E00B92BB2 /* External */, A9679AAB21D2699800856BF7 /* Scripts */, A972AD2421CEE30F0013AB25 /* Products */, + DCFD7CA32A45BA7D007BBBF7 /* libSPIRVCross.a */, + DCFD7D0B2A45BA92007BBBF7 /* libglslang.a */, + DCFD7EC02A45BA9C007BBBF7 /* libSPIRVTools.a */, ); sourceTree = ""; }; @@ -4034,6 +4619,299 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCFD7C8A2A45BA7D007BBBF7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7C8B2A45BA7D007BBBF7 /* spirv_cfg.hpp in Headers */, + DCFD7C8C2A45BA7D007BBBF7 /* spirv_cross_parsed_ir.hpp in Headers */, + DCFD7C8D2A45BA7D007BBBF7 /* spirv_common.hpp in Headers */, + DCFD7C8E2A45BA7D007BBBF7 /* spirv_glsl.hpp in Headers */, + DCFD7C8F2A45BA7D007BBBF7 /* spirv_parser.hpp in Headers */, + DCFD7C902A45BA7D007BBBF7 /* spirv_cross_util.hpp in Headers */, + DCFD7C912A45BA7D007BBBF7 /* spirv_cross_containers.hpp in Headers */, + DCFD7C922A45BA7D007BBBF7 /* spirv.hpp in Headers */, + DCFD7C932A45BA7D007BBBF7 /* spirv_cross_error_handling.hpp in Headers */, + DCFD7C942A45BA7D007BBBF7 /* spirv_cross.hpp in Headers */, + DCFD7C952A45BA7D007BBBF7 /* spirv_msl.hpp in Headers */, + DCFD7C962A45BA7D007BBBF7 /* spirv_reflect.hpp in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DCFD7CA52A45BA92007BBBF7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7CA62A45BA92007BBBF7 /* propagateNoContraction.h in Headers */, + DCFD7CA72A45BA92007BBBF7 /* disassemble.h in Headers */, + DCFD7CA82A45BA92007BBBF7 /* PpContext.h in Headers */, + DCFD7CA92A45BA92007BBBF7 /* InfoSink.h in Headers */, + DCFD7CAA2A45BA92007BBBF7 /* bitutils.h in Headers */, + DCFD7CAB2A45BA92007BBBF7 /* SpvBuilder.h in Headers */, + DCFD7CAC2A45BA92007BBBF7 /* GLSL.std.450.h in Headers */, + DCFD7CAD2A45BA92007BBBF7 /* Logger.h in Headers */, + DCFD7CAE2A45BA92007BBBF7 /* pch.h in Headers */, + DCFD7CAF2A45BA92007BBBF7 /* LiveTraverser.h in Headers */, + DCFD7CB02A45BA92007BBBF7 /* spvIR.h in Headers */, + DCFD7CB12A45BA92007BBBF7 /* glslang_c_shader_types.h in Headers */, + DCFD7CB22A45BA92007BBBF7 /* attribute.h in Headers */, + DCFD7CB32A45BA92007BBBF7 /* Scan.h in Headers */, + DCFD7CB42A45BA92007BBBF7 /* Types.h in Headers */, + DCFD7CB52A45BA92007BBBF7 /* PoolAlloc.h in Headers */, + DCFD7CB62A45BA92007BBBF7 /* InitializeGlobals.h in Headers */, + DCFD7CB72A45BA92007BBBF7 /* parseVersions.h in Headers */, + DCFD7CB82A45BA92007BBBF7 /* osinclude.h in Headers */, + DCFD7CB92A45BA92007BBBF7 /* gl_types.h in Headers */, + DCFD7CBA2A45BA92007BBBF7 /* localintermediate.h in Headers */, + DCFD7CBB2A45BA92007BBBF7 /* GLSL.ext.AMD.h in Headers */, + DCFD7CBC2A45BA92007BBBF7 /* reflection.h in Headers */, + DCFD7CBD2A45BA92007BBBF7 /* ShHandle.h in Headers */, + DCFD7CBE2A45BA92007BBBF7 /* iomapper.h in Headers */, + DCFD7CBF2A45BA92007BBBF7 /* GLSL.ext.NV.h in Headers */, + DCFD7CC02A45BA92007BBBF7 /* Versions.h in Headers */, + DCFD7CC12A45BA92007BBBF7 /* SPVRemapper.h in Headers */, + DCFD7CC22A45BA92007BBBF7 /* ConstantUnion.h in Headers */, + DCFD7CC32A45BA92007BBBF7 /* doc.h in Headers */, + DCFD7CC42A45BA92007BBBF7 /* Initialize.h in Headers */, + DCFD7CC52A45BA92007BBBF7 /* GLSL.ext.EXT.h in Headers */, + DCFD7CC62A45BA92007BBBF7 /* ResourceLimits.h in Headers */, + DCFD7CC72A45BA92007BBBF7 /* Common.h in Headers */, + DCFD7CC82A45BA92007BBBF7 /* GLSL.ext.KHR.h in Headers */, + DCFD7CC92A45BA92007BBBF7 /* intermediate.h in Headers */, + DCFD7CCA2A45BA92007BBBF7 /* ShaderLang.h in Headers */, + DCFD7CCB2A45BA92007BBBF7 /* ScanContext.h in Headers */, + DCFD7CCC2A45BA92007BBBF7 /* PpTokens.h in Headers */, + DCFD7CCD2A45BA92007BBBF7 /* BaseTypes.h in Headers */, + DCFD7CCE2A45BA92007BBBF7 /* hex_float.h in Headers */, + DCFD7CCF2A45BA92007BBBF7 /* SpvTools.h in Headers */, + DCFD7CD02A45BA92007BBBF7 /* RemoveTree.h in Headers */, + DCFD7CD12A45BA92007BBBF7 /* SymbolTable.h in Headers */, + DCFD7CD22A45BA92007BBBF7 /* arrays.h in Headers */, + DCFD7CD32A45BA92007BBBF7 /* spirv.hpp in Headers */, + DCFD7CD42A45BA92007BBBF7 /* glslang_c_interface.h in Headers */, + DCFD7CD52A45BA92007BBBF7 /* GlslangToSpv.h in Headers */, + DCFD7CD62A45BA92007BBBF7 /* SpirvIntrinsics.h in Headers */, + DCFD7CD72A45BA92007BBBF7 /* NonSemanticDebugPrintf.h in Headers */, + DCFD7CD82A45BA92007BBBF7 /* glslang_tab.cpp.h in Headers */, + DCFD7CD92A45BA92007BBBF7 /* ParseHelper.h in Headers */, + DCFD7CDA2A45BA92007BBBF7 /* InitializeDll.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DCFD7D0D2A45BA9C007BBBF7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7D0E2A45BA9C007BBBF7 /* replace_invalid_opc.h in Headers */, + DCFD7D0F2A45BA9C007BBBF7 /* convert_to_sampled_image_pass.h in Headers */, + DCFD7D102A45BA9C007BBBF7 /* text_handler.h in Headers */, + DCFD7D112A45BA9C007BBBF7 /* types.h in Headers */, + DCFD7D122A45BA9C007BBBF7 /* dead_insert_elim_pass.h in Headers */, + DCFD7D132A45BA9C007BBBF7 /* parse_number.h in Headers */, + DCFD7D142A45BA9C007BBBF7 /* make_unique.h in Headers */, + DCFD7D152A45BA9C007BBBF7 /* function.h in Headers */, + DCFD7D162A45BA9C007BBBF7 /* inst_debug_printf_pass.h in Headers */, + DCFD7D172A45BA9C007BBBF7 /* block_merge_pass.h in Headers */, + DCFD7D182A45BA9C007BBBF7 /* scalar_analysis.h in Headers */, + DCFD7D192A45BA9C007BBBF7 /* composite.h in Headers */, + DCFD7D1A2A45BA9C007BBBF7 /* enum_set.h in Headers */, + DCFD7D1B2A45BA9C007BBBF7 /* lints.h in Headers */, + DCFD7D1C2A45BA9C007BBBF7 /* freeze_spec_constant_value_pass.h in Headers */, + DCFD7D1D2A45BA9C007BBBF7 /* reduction_opportunity.h in Headers */, + DCFD7D1E2A45BA9C007BBBF7 /* ir_context.h in Headers */, + DCFD7D1F2A45BA9C007BBBF7 /* loop_utils.h in Headers */, + DCFD7D202A45BA9C007BBBF7 /* relax_float_ops_pass.h in Headers */, + DCFD7D212A45BA9C007BBBF7 /* pass.h in Headers */, + DCFD7D222A45BA9C007BBBF7 /* inline_opaque_pass.h in Headers */, + DCFD7D232A45BA9C007BBBF7 /* strength_reduction_pass.h in Headers */, + DCFD7D242A45BA9C007BBBF7 /* pch_source.h in Headers */, + DCFD7D252A45BA9C007BBBF7 /* graphics_robust_access_pass.h in Headers */, + DCFD7D262A45BA9C007BBBF7 /* scalar_analysis_nodes.h in Headers */, + DCFD7D272A45BA9C007BBBF7 /* operand_to_const_reduction_opportunity_finder.h in Headers */, + DCFD7D282A45BA9C007BBBF7 /* basic_block.h in Headers */, + DCFD7D292A45BA9C007BBBF7 /* strip_nonsemantic_info_pass.h in Headers */, + DCFD7D2A2A45BA9C007BBBF7 /* fold.h in Headers */, + DCFD7D2B2A45BA9C007BBBF7 /* instruction.h in Headers */, + DCFD7D2C2A45BA9C007BBBF7 /* unify_const_pass.h in Headers */, + DCFD7D2D2A45BA9C007BBBF7 /* vector_dce.h in Headers */, + DCFD7D2E2A45BA9C007BBBF7 /* structured_construct_to_block_reduction_opportunity.h in Headers */, + DCFD7D2F2A45BA9C007BBBF7 /* spirv_target_env.h in Headers */, + DCFD7D302A45BA9C007BBBF7 /* loop_fusion.h in Headers */, + DCFD7D312A45BA9C007BBBF7 /* print.h in Headers */, + DCFD7D322A45BA9C007BBBF7 /* structured_loop_to_selection_reduction_opportunity.h in Headers */, + DCFD7D332A45BA9C007BBBF7 /* dominator_tree.h in Headers */, + DCFD7D342A45BA9C007BBBF7 /* dead_branch_elim_pass.h in Headers */, + DCFD7D352A45BA9C007BBBF7 /* ccp_pass.h in Headers */, + DCFD7D362A45BA9C007BBBF7 /* validate.h in Headers */, + DCFD7D372A45BA9C007BBBF7 /* construct.h in Headers */, + DCFD7D382A45BA9C007BBBF7 /* null_pass.h in Headers */, + DCFD7D392A45BA9C007BBBF7 /* constants.h in Headers */, + DCFD7D3A2A45BA9C007BBBF7 /* validation_state.h in Headers */, + DCFD7D3B2A45BA9C007BBBF7 /* instruction.h in Headers */, + DCFD7D3C2A45BA9C007BBBF7 /* loop_unswitch_pass.h in Headers */, + DCFD7D3D2A45BA9C007BBBF7 /* tree_iterator.h in Headers */, + DCFD7D3E2A45BA9C007BBBF7 /* remove_struct_member_reduction_opportunity.h in Headers */, + DCFD7D3F2A45BA9C007BBBF7 /* validate_scopes.h in Headers */, + DCFD7D402A45BA9C007BBBF7 /* passes.h in Headers */, + DCFD7D412A45BA9C007BBBF7 /* interp_fixup_pass.h in Headers */, + DCFD7D422A45BA9C007BBBF7 /* validate_memory_semantics.h in Headers */, + DCFD7D432A45BA9C007BBBF7 /* hash_combine.h in Headers */, + DCFD7D442A45BA9C007BBBF7 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */, + DCFD7D452A45BA9C007BBBF7 /* strip_debug_info_pass.h in Headers */, + DCFD7D462A45BA9C007BBBF7 /* pch_source_opt.h in Headers */, + DCFD7D472A45BA9C007BBBF7 /* merge_blocks_reduction_opportunity_finder.h in Headers */, + DCFD7D482A45BA9C007BBBF7 /* reduction_pass.h in Headers */, + DCFD7D492A45BA9C007BBBF7 /* local_single_store_elim_pass.h in Headers */, + DCFD7D4A2A45BA9C007BBBF7 /* latest_version_opencl_std_header.h in Headers */, + DCFD7D4B2A45BA9C007BBBF7 /* remove_block_reduction_opportunity.h in Headers */, + DCFD7D4C2A45BA9C007BBBF7 /* remove_function_reduction_opportunity_finder.h in Headers */, + DCFD7D4D2A45BA9C007BBBF7 /* instruction.h in Headers */, + DCFD7D4E2A45BA9C007BBBF7 /* eliminate_dead_functions_pass.h in Headers */, + DCFD7D4F2A45BA9C007BBBF7 /* bit_vector.h in Headers */, + DCFD7D502A45BA9C007BBBF7 /* assembly_grammar.h in Headers */, + DCFD7D512A45BA9C007BBBF7 /* loop_dependence.h in Headers */, + DCFD7D522A45BA9C007BBBF7 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */, + DCFD7D532A45BA9C007BBBF7 /* folding_rules.h in Headers */, + DCFD7D542A45BA9C007BBBF7 /* eliminate_dead_members_pass.h in Headers */, + DCFD7D552A45BA9C007BBBF7 /* reduction_util.h in Headers */, + DCFD7D562A45BA9C007BBBF7 /* table.h in Headers */, + DCFD7D572A45BA9C007BBBF7 /* basic_block.h in Headers */, + DCFD7D582A45BA9C007BBBF7 /* remove_block_reduction_opportunity_finder.h in Headers */, + DCFD7D592A45BA9C007BBBF7 /* remove_dontinline_pass.h in Headers */, + DCFD7D5A2A45BA9C007BBBF7 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */, + DCFD7D5B2A45BA9C007BBBF7 /* operand.h in Headers */, + DCFD7D5C2A45BA9C007BBBF7 /* disassemble.h in Headers */, + DCFD7D5D2A45BA9C007BBBF7 /* remove_unused_instruction_reduction_opportunity_finder.h in Headers */, + DCFD7D5E2A45BA9C007BBBF7 /* value_number_table.h in Headers */, + DCFD7D5F2A45BA9C007BBBF7 /* small_vector.h in Headers */, + DCFD7D602A45BA9C007BBBF7 /* log.h in Headers */, + DCFD7D612A45BA9C007BBBF7 /* ilist_node.h in Headers */, + DCFD7D622A45BA9C007BBBF7 /* feature_manager.h in Headers */, + DCFD7D632A45BA9C007BBBF7 /* loop_fission.h in Headers */, + DCFD7D642A45BA9C007BBBF7 /* interface_var_sroa.h in Headers */, + DCFD7D652A45BA9C007BBBF7 /* licm_pass.h in Headers */, + DCFD7D662A45BA9C007BBBF7 /* convert_to_half_pass.h in Headers */, + DCFD7D672A45BA9C007BBBF7 /* structured_construct_to_block_reduction_opportunity_finder.h in Headers */, + DCFD7D682A45BA9C007BBBF7 /* fold_spec_constant_op_and_composite_pass.h in Headers */, + DCFD7D692A45BA9C007BBBF7 /* cfg.h in Headers */, + DCFD7D6A2A45BA9C007BBBF7 /* remove_selection_reduction_opportunity.h in Headers */, + DCFD7D6B2A45BA9C007BBBF7 /* opcode.h in Headers */, + DCFD7D6C2A45BA9C007BBBF7 /* flatten_decoration_pass.h in Headers */, + DCFD7D6D2A45BA9C007BBBF7 /* private_to_local_pass.h in Headers */, + DCFD7D6E2A45BA9C007BBBF7 /* wrap_opkill.h in Headers */, + DCFD7D6F2A45BA9C007BBBF7 /* text.h in Headers */, + DCFD7D702A45BA9C007BBBF7 /* string_utils.h in Headers */, + DCFD7D712A45BA9C007BBBF7 /* debug_info_manager.h in Headers */, + DCFD7D722A45BA9C007BBBF7 /* fix_storage_class.h in Headers */, + DCFD7D732A45BA9C007BBBF7 /* copy_prop_arrays.h in Headers */, + DCFD7D742A45BA9C007BBBF7 /* change_operand_to_undef_reduction_opportunity.h in Headers */, + DCFD7D752A45BA9C007BBBF7 /* lcs.h in Headers */, + DCFD7D762A45BA9C007BBBF7 /* ilist.h in Headers */, + DCFD7D772A45BA9C007BBBF7 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */, + DCFD7D782A45BA9C007BBBF7 /* function.h in Headers */, + DCFD7D792A45BA9C007BBBF7 /* eliminate_dead_constant_pass.h in Headers */, + DCFD7D7A2A45BA9C007BBBF7 /* reduce_load_size.h in Headers */, + DCFD7D7B2A45BA9C007BBBF7 /* set_spec_constant_default_value_pass.h in Headers */, + DCFD7D7C2A45BA9C007BBBF7 /* diagnostic.h in Headers */, + DCFD7D7D2A45BA9C007BBBF7 /* dataflow.h in Headers */, + DCFD7D7E2A45BA9C007BBBF7 /* merge_blocks_reduction_opportunity.h in Headers */, + DCFD7D7F2A45BA9C007BBBF7 /* module.h in Headers */, + DCFD7D802A45BA9C007BBBF7 /* spirv_optimizer_options.h in Headers */, + DCFD7D812A45BA9C007BBBF7 /* ext_inst.h in Headers */, + DCFD7D822A45BA9C007BBBF7 /* spirv_reducer_options.h in Headers */, + DCFD7D832A45BA9C007BBBF7 /* decoration.h in Headers */, + DCFD7D842A45BA9C007BBBF7 /* inst_buff_addr_check_pass.h in Headers */, + DCFD7D852A45BA9C007BBBF7 /* iterator.h in Headers */, + DCFD7D862A45BA9C007BBBF7 /* latest_version_glsl_std_450_header.h in Headers */, + DCFD7D872A45BA9C007BBBF7 /* pch_source_reduce.h in Headers */, + DCFD7D882A45BA9C007BBBF7 /* name_mapper.h in Headers */, + DCFD7D892A45BA9C007BBBF7 /* liveness.h in Headers */, + DCFD7D8A2A45BA9C007BBBF7 /* local_redundancy_elimination.h in Headers */, + DCFD7D8B2A45BA9C007BBBF7 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */, + DCFD7D8C2A45BA9C007BBBF7 /* instruction_list.h in Headers */, + DCFD7D8D2A45BA9C007BBBF7 /* diff.h in Headers */, + DCFD7D8E2A45BA9C007BBBF7 /* instrument_pass.h in Headers */, + DCFD7D8F2A45BA9C007BBBF7 /* binary.h in Headers */, + DCFD7D902A45BA9C007BBBF7 /* inline_pass.h in Headers */, + DCFD7D912A45BA9C007BBBF7 /* loop_fusion_pass.h in Headers */, + DCFD7D922A45BA9C007BBBF7 /* dead_variable_elimination.h in Headers */, + DCFD7D932A45BA9C007BBBF7 /* remove_unused_interface_variables_pass.h in Headers */, + DCFD7D942A45BA9C007BBBF7 /* remove_unused_struct_member_reduction_opportunity_finder.h in Headers */, + DCFD7D952A45BA9C007BBBF7 /* simplification_pass.h in Headers */, + DCFD7D962A45BA9C007BBBF7 /* remove_duplicates_pass.h in Headers */, + DCFD7D972A45BA9C007BBBF7 /* eliminate_dead_io_components_pass.h in Headers */, + DCFD7D982A45BA9C007BBBF7 /* enum_string_mapping.h in Headers */, + DCFD7D992A45BA9C007BBBF7 /* hex_float.h in Headers */, + DCFD7D9A2A45BA9C007BBBF7 /* spirv_validator_options.h in Headers */, + DCFD7D9B2A45BA9C007BBBF7 /* desc_sroa_util.h in Headers */, + DCFD7D9C2A45BA9C007BBBF7 /* remove_selection_reduction_opportunity_finder.h in Headers */, + DCFD7D9D2A45BA9C007BBBF7 /* pass_manager.h in Headers */, + DCFD7D9E2A45BA9C007BBBF7 /* dominator_analysis.h in Headers */, + DCFD7D9F2A45BA9C007BBBF7 /* spirv_definition.h in Headers */, + DCFD7DA02A45BA9C007BBBF7 /* block_merge_util.h in Headers */, + DCFD7DA12A45BA9C007BBBF7 /* remove_function_reduction_opportunity.h in Headers */, + DCFD7DA22A45BA9C007BBBF7 /* reducer.h in Headers */, + DCFD7DA32A45BA9C007BBBF7 /* def_use_manager.h in Headers */, + DCFD7DA42A45BA9C007BBBF7 /* type_manager.h in Headers */, + DCFD7DA52A45BA9C007BBBF7 /* common_debug_info.h in Headers */, + DCFD7DA62A45BA9C007BBBF7 /* cfg_cleanup_pass.h in Headers */, + DCFD7DA72A45BA9C007BBBF7 /* desc_sroa.h in Headers */, + DCFD7DA82A45BA9C007BBBF7 /* local_single_block_elim_pass.h in Headers */, + DCFD7DA92A45BA9C007BBBF7 /* spirv_endian.h in Headers */, + DCFD7DAA2A45BA9C007BBBF7 /* redundancy_elimination.h in Headers */, + DCFD7DAB2A45BA9C007BBBF7 /* combine_access_chains.h in Headers */, + DCFD7DAC2A45BA9C007BBBF7 /* latest_version_spirv_header.h in Headers */, + DCFD7DAD2A45BA9C007BBBF7 /* eliminate_dead_output_stores_pass.h in Headers */, + DCFD7DAE2A45BA9C007BBBF7 /* spread_volatile_semantics.h in Headers */, + DCFD7DAF2A45BA9C007BBBF7 /* ir_builder.h in Headers */, + DCFD7DB02A45BA9C007BBBF7 /* build_module.h in Headers */, + DCFD7DB12A45BA9C007BBBF7 /* inline_exhaustive_pass.h in Headers */, + DCFD7DB22A45BA9C007BBBF7 /* reduction_opportunity_finder.h in Headers */, + DCFD7DB32A45BA9C007BBBF7 /* divergence_analysis.h in Headers */, + DCFD7DB42A45BA9C007BBBF7 /* upgrade_memory_model.h in Headers */, + DCFD7DB52A45BA9C007BBBF7 /* bitutils.h in Headers */, + DCFD7DB62A45BA9C007BBBF7 /* parsed_operand.h in Headers */, + DCFD7DB72A45BA9C007BBBF7 /* spirv_constant.h in Headers */, + DCFD7DB82A45BA9C007BBBF7 /* fix_func_call_arguments.h in Headers */, + DCFD7DB92A45BA9C007BBBF7 /* eliminate_dead_functions_util.h in Headers */, + DCFD7DBA2A45BA9C007BBBF7 /* loop_unroller.h in Headers */, + DCFD7DBB2A45BA9C007BBBF7 /* ssa_rewrite_pass.h in Headers */, + DCFD7DBC2A45BA9C007BBBF7 /* propagator.h in Headers */, + DCFD7DBD2A45BA9C007BBBF7 /* loop_descriptor.h in Headers */, + DCFD7DBE2A45BA9C007BBBF7 /* merge_return_pass.h in Headers */, + DCFD7DBF2A45BA9C007BBBF7 /* empty_pass.h in Headers */, + DCFD7DC02A45BA9C007BBBF7 /* scalar_replacement_pass.h in Headers */, + DCFD7DC12A45BA9C007BBBF7 /* code_sink.h in Headers */, + DCFD7DC22A45BA9C007BBBF7 /* change_operand_reduction_opportunity.h in Headers */, + DCFD7DC32A45BA9C007BBBF7 /* analyze_live_input_pass.h in Headers */, + DCFD7DC42A45BA9C007BBBF7 /* cfa.h in Headers */, + DCFD7DC52A45BA9C007BBBF7 /* amd_ext_to_khr.h in Headers */, + DCFD7DC62A45BA9C007BBBF7 /* decoration_manager.h in Headers */, + DCFD7DC72A45BA9C007BBBF7 /* loop_peeling.h in Headers */, + DCFD7DC82A45BA9C007BBBF7 /* replace_desc_array_access_using_var_index.h in Headers */, + DCFD7DC92A45BA9C007BBBF7 /* reflect.h in Headers */, + DCFD7DCA2A45BA9C007BBBF7 /* compact_ids_pass.h in Headers */, + DCFD7DCB2A45BA9C007BBBF7 /* macro.h in Headers */, + DCFD7DCC2A45BA9C007BBBF7 /* timer.h in Headers */, + DCFD7DCD2A45BA9C007BBBF7 /* extensions.h in Headers */, + DCFD7DCE2A45BA9C007BBBF7 /* mem_pass.h in Headers */, + DCFD7DCF2A45BA9C007BBBF7 /* local_access_chain_convert_pass.h in Headers */, + DCFD7DD02A45BA9C007BBBF7 /* remove_instruction_reduction_opportunity.h in Headers */, + DCFD7DD12A45BA9C007BBBF7 /* control_dependence.h in Headers */, + DCFD7DD22A45BA9C007BBBF7 /* ir_loader.h in Headers */, + DCFD7DD32A45BA9C007BBBF7 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */, + DCFD7DD42A45BA9C007BBBF7 /* workaround1209.h in Headers */, + DCFD7DD52A45BA9C007BBBF7 /* register_pressure.h in Headers */, + DCFD7DD62A45BA9C007BBBF7 /* operand_to_undef_reduction_opportunity_finder.h in Headers */, + DCFD7DD72A45BA9C007BBBF7 /* struct_cfg_analysis.h in Headers */, + DCFD7DD82A45BA9C007BBBF7 /* spirv_fuzzer_options.h in Headers */, + DCFD7DD92A45BA9C007BBBF7 /* const_folding_rules.h in Headers */, + DCFD7DDA2A45BA9C007BBBF7 /* inst_bindless_check_pass.h in Headers */, + DCFD7DDB2A45BA9C007BBBF7 /* aggressive_dead_code_elim_pass.h in Headers */, + DCFD7DDC2A45BA9C007BBBF7 /* if_conversion.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -4190,6 +5068,57 @@ productReference = A972ABF021CED7CB0013AB25 /* libglslang.a */; productType = "com.apple.product-type.library.static"; }; + DCFD7C892A45BA7D007BBBF7 /* SPIRV-Cross-xrOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = DCFD7CA02A45BA7D007BBBF7 /* Build configuration list for PBXNativeTarget "SPIRV-Cross-xrOS" */; + buildPhases = ( + DCFD7C8A2A45BA7D007BBBF7 /* Headers */, + DCFD7C972A45BA7D007BBBF7 /* Sources */, + DCFD7C9F2A45BA7D007BBBF7 /* Copy to Staging */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SPIRV-Cross-xrOS"; + productName = "SPIRV-Cross-xrOS"; + productReference = DCFD7CA32A45BA7D007BBBF7 /* libSPIRVCross.a */; + productType = "com.apple.product-type.library.static"; + }; + DCFD7CA42A45BA92007BBBF7 /* glslang-xrOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = DCFD7D082A45BA92007BBBF7 /* Build configuration list for PBXNativeTarget "glslang-xrOS" */; + buildPhases = ( + DCFD7CA52A45BA92007BBBF7 /* Headers */, + DCFD7CDB2A45BA92007BBBF7 /* Sources */, + DCFD7D072A45BA92007BBBF7 /* Copy to Staging */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "glslang-xrOS"; + productName = "SPIRV-Cross-xrOS"; + productReference = DCFD7D0B2A45BA92007BBBF7 /* libglslang.a */; + productType = "com.apple.product-type.library.static"; + }; + DCFD7D0C2A45BA9C007BBBF7 /* SPIRV-Tools-xrOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = DCFD7EBD2A45BA9C007BBBF7 /* Build configuration list for PBXNativeTarget "SPIRV-Tools-xrOS" */; + buildPhases = ( + DCFD7D0D2A45BA9C007BBBF7 /* Headers */, + DCFD7DDD2A45BA9C007BBBF7 /* Sources */, + DCFD7EBC2A45BA9C007BBBF7 /* Copy to Staging */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SPIRV-Tools-xrOS"; + productName = "SPIRV-Cross-xrOS"; + productReference = DCFD7EC02A45BA9C007BBBF7 /* libSPIRVTools.a */; + productType = "com.apple.product-type.library.static"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -4212,6 +5141,9 @@ A972A7F221CEC81B0013AB25 = { ProvisioningStyle = Automatic; }; + DCFD7EC12A45BAAA007BBBF7 = { + ProvisioningStyle = Automatic; + }; }; }; buildConfigurationList = A9F55D28198BE6A7004EC31B /* Build configuration list for PBXProject "ExternalDependencies" */; @@ -4230,15 +5162,19 @@ A972A7F221CEC81B0013AB25 /* ExternalDependencies */, A972A7EA21CEC8030013AB25 /* ExternalDependencies-iOS */, 2FEA0ADD2490320500EEF3AD /* ExternalDependencies-tvOS */, + DCFD7EC12A45BAAA007BBBF7 /* ExternalDependencies-xrOS */, A972A7E421CEC72F0013AB25 /* ExternalDependencies-macOS */, A90FD75B21CC4EAB00B92BB2 /* SPIRV-Cross-iOS */, 2FEA0CD92490322B00EEF3AD /* SPIRV-Cross-tvOS */, + DCFD7C892A45BA7D007BBBF7 /* SPIRV-Cross-xrOS */, A90FD8A021CC4EB900B92BB2 /* SPIRV-Cross-macOS */, A972A7FC21CECBBF0013AB25 /* SPIRV-Tools-iOS */, 2FEA0B4B2490322100EEF3AD /* SPIRV-Tools-tvOS */, + DCFD7D0C2A45BA9C007BBBF7 /* SPIRV-Tools-xrOS */, A972A81021CECBE90013AB25 /* SPIRV-Tools-macOS */, A972ABC921CED7BC0013AB25 /* glslang-iOS */, 2FEA0AE82490321700EEF3AD /* glslang-tvOS */, + DCFD7CA42A45BA92007BBBF7 /* glslang-xrOS */, A972ABDD21CED7CB0013AB25 /* glslang-macOS */, ); }; @@ -4505,6 +5441,86 @@ shellPath = /bin/sh; shellScript = ". \"${SRCROOT}/Scripts/create_ext_lib_xcframeworks.sh\"\n. \"${SRCROOT}/Scripts/package_ext_libs_finish.sh\"\n"; }; + DCFD7C9F2A45BA7D007BBBF7 /* Copy to Staging */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${BUILT_PRODUCTS_DIR}/lib${PRODUCT_NAME}.a", + ); + name = "Copy to Staging"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/$(TARGET_NAME)/CopyPhaseDummyOutputFile", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ". \"${SRCROOT}/Scripts/copy_ext_lib_to_staging.sh\"\n"; + }; + DCFD7D072A45BA92007BBBF7 /* Copy to Staging */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${BUILT_PRODUCTS_DIR}/lib${PRODUCT_NAME}.a", + ); + name = "Copy to Staging"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/$(TARGET_NAME)/CopyPhaseDummyOutputFile", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ". \"${SRCROOT}/Scripts/copy_ext_lib_to_staging.sh\"\n"; + }; + DCFD7EBC2A45BA9C007BBBF7 /* Copy to Staging */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${BUILT_PRODUCTS_DIR}/lib${PRODUCT_NAME}.a", + ); + name = "Copy to Staging"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/$(TARGET_NAME)/CopyPhaseDummyOutputFile", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ". \"${SRCROOT}/Scripts/copy_ext_lib_to_staging.sh\"\n"; + }; + DCFD7EC82A45BAAA007BBBF7 /* Package Libraries */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PROJECT_DIR}/External/build/Intermediates/XCFrameworkStaging", + ); + name = "Package Libraries"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/$(TARGET_NAME)/PackagePhaseDummyOutputFile", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ". \"${SRCROOT}/Scripts/create_ext_lib_xcframeworks.sh\"\n. \"${SRCROOT}/Scripts/package_ext_libs_finish.sh\"\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -5387,6 +6403,299 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCFD7C972A45BA7D007BBBF7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7C982A45BA7D007BBBF7 /* spirv_msl.cpp in Sources */, + DCFD7C992A45BA7D007BBBF7 /* spirv_parser.cpp in Sources */, + DCFD7C9A2A45BA7D007BBBF7 /* spirv_cfg.cpp in Sources */, + DCFD7C9B2A45BA7D007BBBF7 /* spirv_cross.cpp in Sources */, + DCFD7C9C2A45BA7D007BBBF7 /* spirv_reflect.cpp in Sources */, + DCFD7C9D2A45BA7D007BBBF7 /* spirv_glsl.cpp in Sources */, + DCFD7C9E2A45BA7D007BBBF7 /* spirv_cross_parsed_ir.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DCFD7CDB2A45BA92007BBBF7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7CDC2A45BA92007BBBF7 /* ParseHelper.cpp in Sources */, + DCFD7CDD2A45BA92007BBBF7 /* doc.cpp in Sources */, + DCFD7CDE2A45BA92007BBBF7 /* attribute.cpp in Sources */, + DCFD7CDF2A45BA92007BBBF7 /* IntermTraverse.cpp in Sources */, + DCFD7CE02A45BA92007BBBF7 /* Versions.cpp in Sources */, + DCFD7CE12A45BA92007BBBF7 /* reflection.cpp in Sources */, + DCFD7CE22A45BA92007BBBF7 /* spirv_c_interface.cpp in Sources */, + DCFD7CE32A45BA92007BBBF7 /* propagateNoContraction.cpp in Sources */, + DCFD7CE42A45BA92007BBBF7 /* glslang_c_interface.cpp in Sources */, + DCFD7CE52A45BA92007BBBF7 /* SPVRemapper.cpp in Sources */, + DCFD7CE62A45BA92007BBBF7 /* SpvTools.cpp in Sources */, + DCFD7CE72A45BA92007BBBF7 /* Logger.cpp in Sources */, + DCFD7CE82A45BA92007BBBF7 /* ossource.cpp in Sources */, + DCFD7CE92A45BA92007BBBF7 /* SpvPostProcess.cpp in Sources */, + DCFD7CEA2A45BA92007BBBF7 /* Scan.cpp in Sources */, + DCFD7CEB2A45BA92007BBBF7 /* PpScanner.cpp in Sources */, + DCFD7CEC2A45BA92007BBBF7 /* PpContext.cpp in Sources */, + DCFD7CED2A45BA92007BBBF7 /* disassemble.cpp in Sources */, + DCFD7CEE2A45BA92007BBBF7 /* SpirvIntrinsics.cpp in Sources */, + DCFD7CEF2A45BA92007BBBF7 /* linkValidate.cpp in Sources */, + DCFD7CF02A45BA92007BBBF7 /* parseConst.cpp in Sources */, + DCFD7CF12A45BA92007BBBF7 /* InitializeDll.cpp in Sources */, + DCFD7CF22A45BA92007BBBF7 /* Link.cpp in Sources */, + DCFD7CF32A45BA92007BBBF7 /* iomapper.cpp in Sources */, + DCFD7CF42A45BA92007BBBF7 /* ParseContextBase.cpp in Sources */, + DCFD7CF52A45BA92007BBBF7 /* PpTokens.cpp in Sources */, + DCFD7CF62A45BA92007BBBF7 /* GlslangToSpv.cpp in Sources */, + DCFD7CF72A45BA92007BBBF7 /* limits.cpp in Sources */, + DCFD7CF82A45BA92007BBBF7 /* glslang_tab.cpp in Sources */, + DCFD7CF92A45BA92007BBBF7 /* Constant.cpp in Sources */, + DCFD7CFA2A45BA92007BBBF7 /* InfoSink.cpp in Sources */, + DCFD7CFB2A45BA92007BBBF7 /* RemoveTree.cpp in Sources */, + DCFD7CFC2A45BA92007BBBF7 /* intermOut.cpp in Sources */, + DCFD7CFD2A45BA92007BBBF7 /* PoolAlloc.cpp in Sources */, + DCFD7CFE2A45BA92007BBBF7 /* Initialize.cpp in Sources */, + DCFD7CFF2A45BA92007BBBF7 /* ShaderLang.cpp in Sources */, + DCFD7D002A45BA92007BBBF7 /* Intermediate.cpp in Sources */, + DCFD7D012A45BA92007BBBF7 /* InReadableOrder.cpp in Sources */, + DCFD7D022A45BA92007BBBF7 /* PpAtom.cpp in Sources */, + DCFD7D032A45BA92007BBBF7 /* SpvBuilder.cpp in Sources */, + DCFD7D042A45BA92007BBBF7 /* CodeGen.cpp in Sources */, + DCFD7D052A45BA92007BBBF7 /* SymbolTable.cpp in Sources */, + DCFD7D062A45BA92007BBBF7 /* Pp.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DCFD7DDD2A45BA9C007BBBF7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7DDE2A45BA9C007BBBF7 /* spirv_reducer_options.cpp in Sources */, + DCFD7DDF2A45BA9C007BBBF7 /* register_pressure.cpp in Sources */, + DCFD7DE02A45BA9C007BBBF7 /* loop_peeling.cpp in Sources */, + DCFD7DE12A45BA9C007BBBF7 /* block_merge_pass.cpp in Sources */, + DCFD7DE22A45BA9C007BBBF7 /* opcode.cpp in Sources */, + DCFD7DE32A45BA9C007BBBF7 /* validate_builtins.cpp in Sources */, + DCFD7DE42A45BA9C007BBBF7 /* validate_non_uniform.cpp in Sources */, + DCFD7DE52A45BA9C007BBBF7 /* table.cpp in Sources */, + DCFD7DE62A45BA9C007BBBF7 /* validate_logicals.cpp in Sources */, + DCFD7DE72A45BA9C007BBBF7 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */, + DCFD7DE82A45BA9C007BBBF7 /* bit_vector.cpp in Sources */, + DCFD7DE92A45BA9C007BBBF7 /* ir_context.cpp in Sources */, + DCFD7DEA2A45BA9C007BBBF7 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */, + DCFD7DEB2A45BA9C007BBBF7 /* if_conversion.cpp in Sources */, + DCFD7DEC2A45BA9C007BBBF7 /* remove_dontinline_pass.cpp in Sources */, + DCFD7DED2A45BA9C007BBBF7 /* convert_to_sampled_image_pass.cpp in Sources */, + DCFD7DEE2A45BA9C007BBBF7 /* merge_return_pass.cpp in Sources */, + DCFD7DEF2A45BA9C007BBBF7 /* reducer.cpp in Sources */, + DCFD7DF02A45BA9C007BBBF7 /* remove_function_reduction_opportunity.cpp in Sources */, + DCFD7DF12A45BA9C007BBBF7 /* disassemble.cpp in Sources */, + DCFD7DF22A45BA9C007BBBF7 /* composite.cpp in Sources */, + DCFD7DF32A45BA9C007BBBF7 /* validate_conversion.cpp in Sources */, + DCFD7DF42A45BA9C007BBBF7 /* instruction.cpp in Sources */, + DCFD7DF52A45BA9C007BBBF7 /* validate_ray_query.cpp in Sources */, + DCFD7DF62A45BA9C007BBBF7 /* operand.cpp in Sources */, + DCFD7DF72A45BA9C007BBBF7 /* unify_const_pass.cpp in Sources */, + DCFD7DF82A45BA9C007BBBF7 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */, + DCFD7DF92A45BA9C007BBBF7 /* enum_string_mapping.cpp in Sources */, + DCFD7DFA2A45BA9C007BBBF7 /* validate_mode_setting.cpp in Sources */, + DCFD7DFB2A45BA9C007BBBF7 /* binary.cpp in Sources */, + DCFD7DFC2A45BA9C007BBBF7 /* struct_cfg_analysis.cpp in Sources */, + DCFD7DFD2A45BA9C007BBBF7 /* validate_capability.cpp in Sources */, + DCFD7DFE2A45BA9C007BBBF7 /* diagnostic.cpp in Sources */, + DCFD7DFF2A45BA9C007BBBF7 /* libspirv.cpp in Sources */, + DCFD7E002A45BA9C007BBBF7 /* validate_mesh_shading.cpp in Sources */, + DCFD7E012A45BA9C007BBBF7 /* build_module.cpp in Sources */, + DCFD7E022A45BA9C007BBBF7 /* cfg_cleanup_pass.cpp in Sources */, + DCFD7E032A45BA9C007BBBF7 /* spirv_fuzzer_options.cpp in Sources */, + DCFD7E042A45BA9C007BBBF7 /* validate_adjacency.cpp in Sources */, + DCFD7E052A45BA9C007BBBF7 /* validate_id.cpp in Sources */, + DCFD7E062A45BA9C007BBBF7 /* parse_number.cpp in Sources */, + DCFD7E072A45BA9C007BBBF7 /* scalar_analysis.cpp in Sources */, + DCFD7E082A45BA9C007BBBF7 /* lint_divergent_derivatives.cpp in Sources */, + DCFD7E092A45BA9C007BBBF7 /* remove_struct_member_reduction_opportunity.cpp in Sources */, + DCFD7E0A2A45BA9C007BBBF7 /* validate_scopes.cpp in Sources */, + DCFD7E0B2A45BA9C007BBBF7 /* strip_debug_info_pass.cpp in Sources */, + DCFD7E0C2A45BA9C007BBBF7 /* eliminate_dead_functions_util.cpp in Sources */, + DCFD7E0D2A45BA9C007BBBF7 /* remove_function_reduction_opportunity_finder.cpp in Sources */, + DCFD7E0E2A45BA9C007BBBF7 /* ssa_rewrite_pass.cpp in Sources */, + DCFD7E0F2A45BA9C007BBBF7 /* validate_image.cpp in Sources */, + DCFD7E102A45BA9C007BBBF7 /* module.cpp in Sources */, + DCFD7E112A45BA9C007BBBF7 /* merge_blocks_reduction_opportunity.cpp in Sources */, + DCFD7E122A45BA9C007BBBF7 /* constants.cpp in Sources */, + DCFD7E132A45BA9C007BBBF7 /* remove_block_reduction_opportunity.cpp in Sources */, + DCFD7E142A45BA9C007BBBF7 /* spirv_target_env.cpp in Sources */, + DCFD7E152A45BA9C007BBBF7 /* loop_fission.cpp in Sources */, + DCFD7E162A45BA9C007BBBF7 /* remove_block_reduction_opportunity_finder.cpp in Sources */, + DCFD7E172A45BA9C007BBBF7 /* remove_selection_reduction_opportunity_finder.cpp in Sources */, + DCFD7E182A45BA9C007BBBF7 /* fold.cpp in Sources */, + DCFD7E192A45BA9C007BBBF7 /* def_use_manager.cpp in Sources */, + DCFD7E1A2A45BA9C007BBBF7 /* parsed_operand.cpp in Sources */, + DCFD7E1B2A45BA9C007BBBF7 /* eliminate_dead_members_pass.cpp in Sources */, + DCFD7E1C2A45BA9C007BBBF7 /* instruction.cpp in Sources */, + DCFD7E1D2A45BA9C007BBBF7 /* name_mapper.cpp in Sources */, + DCFD7E1E2A45BA9C007BBBF7 /* analyze_live_input_pass.cpp in Sources */, + DCFD7E1F2A45BA9C007BBBF7 /* validate_cfg.cpp in Sources */, + DCFD7E202A45BA9C007BBBF7 /* change_operand_reduction_opportunity.cpp in Sources */, + DCFD7E212A45BA9C007BBBF7 /* validate_instruction.cpp in Sources */, + DCFD7E222A45BA9C007BBBF7 /* instrument_pass.cpp in Sources */, + DCFD7E232A45BA9C007BBBF7 /* validate_ray_tracing.cpp in Sources */, + DCFD7E242A45BA9C007BBBF7 /* pass.cpp in Sources */, + DCFD7E252A45BA9C007BBBF7 /* ccp_pass.cpp in Sources */, + DCFD7E262A45BA9C007BBBF7 /* desc_sroa_util.cpp in Sources */, + DCFD7E272A45BA9C007BBBF7 /* validate_bitwise.cpp in Sources */, + DCFD7E282A45BA9C007BBBF7 /* block_merge_util.cpp in Sources */, + DCFD7E292A45BA9C007BBBF7 /* validate_debug.cpp in Sources */, + DCFD7E2A2A45BA9C007BBBF7 /* loop_descriptor.cpp in Sources */, + DCFD7E2B2A45BA9C007BBBF7 /* linker.cpp in Sources */, + DCFD7E2C2A45BA9C007BBBF7 /* freeze_spec_constant_value_pass.cpp in Sources */, + DCFD7E2D2A45BA9C007BBBF7 /* string_utils.cpp in Sources */, + DCFD7E2E2A45BA9C007BBBF7 /* validate_memory_semantics.cpp in Sources */, + DCFD7E2F2A45BA9C007BBBF7 /* types.cpp in Sources */, + DCFD7E302A45BA9C007BBBF7 /* pch_source.cpp in Sources */, + DCFD7E312A45BA9C007BBBF7 /* print.cpp in Sources */, + DCFD7E322A45BA9C007BBBF7 /* function.cpp in Sources */, + DCFD7E332A45BA9C007BBBF7 /* inline_exhaustive_pass.cpp in Sources */, + DCFD7E342A45BA9C007BBBF7 /* eliminate_dead_constant_pass.cpp in Sources */, + DCFD7E352A45BA9C007BBBF7 /* inline_opaque_pass.cpp in Sources */, + DCFD7E362A45BA9C007BBBF7 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */, + DCFD7E372A45BA9C007BBBF7 /* linter.cpp in Sources */, + DCFD7E382A45BA9C007BBBF7 /* eliminate_dead_output_stores_pass.cpp in Sources */, + DCFD7E392A45BA9C007BBBF7 /* compact_ids_pass.cpp in Sources */, + DCFD7E3A2A45BA9C007BBBF7 /* folding_rules.cpp in Sources */, + DCFD7E3B2A45BA9C007BBBF7 /* strip_nonsemantic_info_pass.cpp in Sources */, + DCFD7E3C2A45BA9C007BBBF7 /* private_to_local_pass.cpp in Sources */, + DCFD7E3D2A45BA9C007BBBF7 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */, + DCFD7E3E2A45BA9C007BBBF7 /* validate_ray_tracing_reorder.cpp in Sources */, + DCFD7E3F2A45BA9C007BBBF7 /* validate_derivatives.cpp in Sources */, + DCFD7E402A45BA9C007BBBF7 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */, + DCFD7E412A45BA9C007BBBF7 /* control_dependence.cpp in Sources */, + DCFD7E422A45BA9C007BBBF7 /* spirv_optimizer_options.cpp in Sources */, + DCFD7E432A45BA9C007BBBF7 /* pch_source_reduce.cpp in Sources */, + DCFD7E442A45BA9C007BBBF7 /* dead_variable_elimination.cpp in Sources */, + DCFD7E452A45BA9C007BBBF7 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */, + DCFD7E462A45BA9C007BBBF7 /* strength_reduction_pass.cpp in Sources */, + DCFD7E472A45BA9C007BBBF7 /* scalar_analysis_simplification.cpp in Sources */, + DCFD7E482A45BA9C007BBBF7 /* validate_interfaces.cpp in Sources */, + DCFD7E492A45BA9C007BBBF7 /* validate_atomics.cpp in Sources */, + DCFD7E4A2A45BA9C007BBBF7 /* ext_inst.cpp in Sources */, + DCFD7E4B2A45BA9C007BBBF7 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */, + DCFD7E4C2A45BA9C007BBBF7 /* decoration_manager.cpp in Sources */, + DCFD7E4D2A45BA9C007BBBF7 /* workaround1209.cpp in Sources */, + DCFD7E4E2A45BA9C007BBBF7 /* interp_fixup_pass.cpp in Sources */, + DCFD7E4F2A45BA9C007BBBF7 /* validate_literals.cpp in Sources */, + DCFD7E502A45BA9C007BBBF7 /* diff.cpp in Sources */, + DCFD7E512A45BA9C007BBBF7 /* dominator_tree.cpp in Sources */, + DCFD7E522A45BA9C007BBBF7 /* interface_var_sroa.cpp in Sources */, + DCFD7E532A45BA9C007BBBF7 /* upgrade_memory_model.cpp in Sources */, + DCFD7E542A45BA9C007BBBF7 /* combine_access_chains.cpp in Sources */, + DCFD7E552A45BA9C007BBBF7 /* instruction_list.cpp in Sources */, + DCFD7E562A45BA9C007BBBF7 /* aggressive_dead_code_elim_pass.cpp in Sources */, + DCFD7E572A45BA9C007BBBF7 /* reduction_util.cpp in Sources */, + DCFD7E582A45BA9C007BBBF7 /* eliminate_dead_functions_pass.cpp in Sources */, + DCFD7E592A45BA9C007BBBF7 /* validate_small_type_uses.cpp in Sources */, + DCFD7E5A2A45BA9C007BBBF7 /* validate_misc.cpp in Sources */, + DCFD7E5B2A45BA9C007BBBF7 /* code_sink.cpp in Sources */, + DCFD7E5C2A45BA9C007BBBF7 /* pass_manager.cpp in Sources */, + DCFD7E5D2A45BA9C007BBBF7 /* feature_manager.cpp in Sources */, + DCFD7E5E2A45BA9C007BBBF7 /* wrap_opkill.cpp in Sources */, + DCFD7E5F2A45BA9C007BBBF7 /* dataflow.cpp in Sources */, + DCFD7E602A45BA9C007BBBF7 /* validate_type.cpp in Sources */, + DCFD7E612A45BA9C007BBBF7 /* set_spec_constant_default_value_pass.cpp in Sources */, + DCFD7E622A45BA9C007BBBF7 /* remove_selection_reduction_opportunity.cpp in Sources */, + DCFD7E632A45BA9C007BBBF7 /* validate_constants.cpp in Sources */, + DCFD7E642A45BA9C007BBBF7 /* validate_layout.cpp in Sources */, + DCFD7E652A45BA9C007BBBF7 /* const_folding_rules.cpp in Sources */, + DCFD7E662A45BA9C007BBBF7 /* replace_invalid_opc.cpp in Sources */, + DCFD7E672A45BA9C007BBBF7 /* eliminate_dead_io_components_pass.cpp in Sources */, + DCFD7E682A45BA9C007BBBF7 /* structured_construct_to_block_reduction_opportunity_finder.cpp in Sources */, + DCFD7E692A45BA9C007BBBF7 /* reduction_opportunity_finder.cpp in Sources */, + DCFD7E6A2A45BA9C007BBBF7 /* liveness.cpp in Sources */, + DCFD7E6B2A45BA9C007BBBF7 /* debug_info_manager.cpp in Sources */, + DCFD7E6C2A45BA9C007BBBF7 /* relax_float_ops_pass.cpp in Sources */, + DCFD7E6D2A45BA9C007BBBF7 /* value_number_table.cpp in Sources */, + DCFD7E6E2A45BA9C007BBBF7 /* text.cpp in Sources */, + DCFD7E6F2A45BA9C007BBBF7 /* local_single_store_elim_pass.cpp in Sources */, + DCFD7E702A45BA9C007BBBF7 /* remove_unused_instruction_reduction_opportunity_finder.cpp in Sources */, + DCFD7E712A45BA9C007BBBF7 /* reduction_pass.cpp in Sources */, + DCFD7E722A45BA9C007BBBF7 /* convert_to_half_pass.cpp in Sources */, + DCFD7E732A45BA9C007BBBF7 /* reduce_load_size.cpp in Sources */, + DCFD7E742A45BA9C007BBBF7 /* local_access_chain_convert_pass.cpp in Sources */, + DCFD7E752A45BA9C007BBBF7 /* inst_bindless_check_pass.cpp in Sources */, + DCFD7E762A45BA9C007BBBF7 /* local_single_block_elim_pass.cpp in Sources */, + DCFD7E772A45BA9C007BBBF7 /* validate_execution_limitations.cpp in Sources */, + DCFD7E782A45BA9C007BBBF7 /* function.cpp in Sources */, + DCFD7E792A45BA9C007BBBF7 /* fix_func_call_arguments.cpp in Sources */, + DCFD7E7A2A45BA9C007BBBF7 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */, + DCFD7E7B2A45BA9C007BBBF7 /* graphics_robust_access_pass.cpp in Sources */, + DCFD7E7C2A45BA9C007BBBF7 /* construct.cpp in Sources */, + DCFD7E7D2A45BA9C007BBBF7 /* loop_unroller.cpp in Sources */, + DCFD7E7E2A45BA9C007BBBF7 /* spirv_validator_options.cpp in Sources */, + DCFD7E7F2A45BA9C007BBBF7 /* divergence_analysis.cpp in Sources */, + DCFD7E802A45BA9C007BBBF7 /* loop_utils.cpp in Sources */, + DCFD7E812A45BA9C007BBBF7 /* spread_volatile_semantics.cpp in Sources */, + DCFD7E822A45BA9C007BBBF7 /* desc_sroa.cpp in Sources */, + DCFD7E832A45BA9C007BBBF7 /* dead_insert_elim_pass.cpp in Sources */, + DCFD7E842A45BA9C007BBBF7 /* validate_decorations.cpp in Sources */, + DCFD7E852A45BA9C007BBBF7 /* loop_fusion_pass.cpp in Sources */, + DCFD7E862A45BA9C007BBBF7 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */, + DCFD7E872A45BA9C007BBBF7 /* flatten_decoration_pass.cpp in Sources */, + DCFD7E882A45BA9C007BBBF7 /* fix_storage_class.cpp in Sources */, + DCFD7E892A45BA9C007BBBF7 /* software_version.cpp in Sources */, + DCFD7E8A2A45BA9C007BBBF7 /* assembly_grammar.cpp in Sources */, + DCFD7E8B2A45BA9C007BBBF7 /* amd_ext_to_khr.cpp in Sources */, + DCFD7E8C2A45BA9C007BBBF7 /* text_handler.cpp in Sources */, + DCFD7E8D2A45BA9C007BBBF7 /* optimizer.cpp in Sources */, + DCFD7E8E2A45BA9C007BBBF7 /* validation_state.cpp in Sources */, + DCFD7E8F2A45BA9C007BBBF7 /* mem_pass.cpp in Sources */, + DCFD7E902A45BA9C007BBBF7 /* replace_desc_array_access_using_var_index.cpp in Sources */, + DCFD7E912A45BA9C007BBBF7 /* ir_loader.cpp in Sources */, + DCFD7E922A45BA9C007BBBF7 /* extensions.cpp in Sources */, + DCFD7E932A45BA9C007BBBF7 /* type_manager.cpp in Sources */, + DCFD7E942A45BA9C007BBBF7 /* scalar_replacement_pass.cpp in Sources */, + DCFD7E952A45BA9C007BBBF7 /* loop_unswitch_pass.cpp in Sources */, + DCFD7E962A45BA9C007BBBF7 /* reduction_opportunity.cpp in Sources */, + DCFD7E972A45BA9C007BBBF7 /* validate_extensions.cpp in Sources */, + DCFD7E982A45BA9C007BBBF7 /* remove_unused_struct_member_reduction_opportunity_finder.cpp in Sources */, + DCFD7E992A45BA9C007BBBF7 /* timer.cpp in Sources */, + DCFD7E9A2A45BA9C007BBBF7 /* pch_source_opt.cpp in Sources */, + DCFD7E9B2A45BA9C007BBBF7 /* inline_pass.cpp in Sources */, + DCFD7E9C2A45BA9C007BBBF7 /* inst_buff_addr_check_pass.cpp in Sources */, + DCFD7E9D2A45BA9C007BBBF7 /* validate_barriers.cpp in Sources */, + DCFD7E9E2A45BA9C007BBBF7 /* redundancy_elimination.cpp in Sources */, + DCFD7E9F2A45BA9C007BBBF7 /* spirv_endian.cpp in Sources */, + DCFD7EA02A45BA9C007BBBF7 /* cfg.cpp in Sources */, + DCFD7EA12A45BA9C007BBBF7 /* remove_duplicates_pass.cpp in Sources */, + DCFD7EA22A45BA9C007BBBF7 /* validate_annotation.cpp in Sources */, + DCFD7EA32A45BA9C007BBBF7 /* loop_dependence_helpers.cpp in Sources */, + DCFD7EA42A45BA9C007BBBF7 /* basic_block.cpp in Sources */, + DCFD7EA52A45BA9C007BBBF7 /* loop_dependence.cpp in Sources */, + DCFD7EA62A45BA9C007BBBF7 /* licm_pass.cpp in Sources */, + DCFD7EA72A45BA9C007BBBF7 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */, + DCFD7EA82A45BA9C007BBBF7 /* dead_branch_elim_pass.cpp in Sources */, + DCFD7EA92A45BA9C007BBBF7 /* inst_debug_printf_pass.cpp in Sources */, + DCFD7EAA2A45BA9C007BBBF7 /* local_redundancy_elimination.cpp in Sources */, + DCFD7EAB2A45BA9C007BBBF7 /* validate_memory.cpp in Sources */, + DCFD7EAC2A45BA9C007BBBF7 /* dominator_analysis.cpp in Sources */, + DCFD7EAD2A45BA9C007BBBF7 /* validate.cpp in Sources */, + DCFD7EAE2A45BA9C007BBBF7 /* copy_prop_arrays.cpp in Sources */, + DCFD7EAF2A45BA9C007BBBF7 /* structured_construct_to_block_reduction_opportunity.cpp in Sources */, + DCFD7EB02A45BA9C007BBBF7 /* validate_composites.cpp in Sources */, + DCFD7EB12A45BA9C007BBBF7 /* loop_fusion.cpp in Sources */, + DCFD7EB22A45BA9C007BBBF7 /* basic_block.cpp in Sources */, + DCFD7EB32A45BA9C007BBBF7 /* remove_unused_interface_variables_pass.cpp in Sources */, + DCFD7EB42A45BA9C007BBBF7 /* validate_function.cpp in Sources */, + DCFD7EB52A45BA9C007BBBF7 /* vector_dce.cpp in Sources */, + DCFD7EB62A45BA9C007BBBF7 /* validate_primitives.cpp in Sources */, + DCFD7EB72A45BA9C007BBBF7 /* simplification_pass.cpp in Sources */, + DCFD7EB82A45BA9C007BBBF7 /* propagator.cpp in Sources */, + DCFD7EB92A45BA9C007BBBF7 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */, + DCFD7EBA2A45BA9C007BBBF7 /* remove_instruction_reduction_opportunity.cpp in Sources */, + DCFD7EBB2A45BA9C007BBBF7 /* validate_arithmetics.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -5450,6 +6759,21 @@ target = A972ABDD21CED7CB0013AB25 /* glslang-macOS */; targetProxy = A972ABF321CED8C20013AB25 /* PBXContainerItemProxy */; }; + DCFD7ECD2A45BC08007BBBF7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCFD7C892A45BA7D007BBBF7 /* SPIRV-Cross-xrOS */; + targetProxy = DCFD7ECC2A45BC08007BBBF7 /* PBXContainerItemProxy */; + }; + DCFD7ECF2A45BC0C007BBBF7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCFD7D0C2A45BA9C007BBBF7 /* SPIRV-Tools-xrOS */; + targetProxy = DCFD7ECE2A45BC0C007BBBF7 /* PBXContainerItemProxy */; + }; + DCFD7ED12A45BC10007BBBF7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCFD7CA42A45BA92007BBBF7 /* glslang-xrOS */; + targetProxy = DCFD7ED02A45BC10007BBBF7 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -5939,6 +7263,128 @@ }; name = Release; }; + DCFD7CA12A45BA7D007BBBF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross", + ); + PRODUCT_NAME = SPIRVCross; + SDKROOT = xros; + }; + name = Debug; + }; + DCFD7CA22A45BA7D007BBBF7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross", + ); + PRODUCT_NAME = SPIRVCross; + SDKROOT = xros; + }; + name = Release; + }; + DCFD7D092A45BA92007BBBF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "AMD_EXTENSIONS=1", + "NV_EXTENSIONS=1", + ); + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_CHECK_SWITCH_STATEMENTS = NO; + GCC_WARN_UNUSED_PARAMETER = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/External/glslang\"", + "\"$(SRCROOT)/External/glslang/build/include\"", + ); + PRODUCT_NAME = glslang; + SDKROOT = xros; + }; + name = Debug; + }; + DCFD7D0A2A45BA92007BBBF7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "AMD_EXTENSIONS=1", + "NV_EXTENSIONS=1", + ); + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_CHECK_SWITCH_STATEMENTS = NO; + GCC_WARN_UNUSED_PARAMETER = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/External/glslang\"", + "\"$(SRCROOT)/External/glslang/build/include\"", + ); + PRODUCT_NAME = glslang; + SDKROOT = xros; + }; + name = Release; + }; + DCFD7EBE2A45BA9C007BBBF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_CHECK_SWITCH_STATEMENTS = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/External/glslang/External/spirv-tools/\"", + "\"$(SRCROOT)/External/glslang/External/spirv-tools/include\"", + "\"$(SRCROOT)/External/glslang/External/spirv-tools/external/spirv-headers/include\"", + "\"$(SRCROOT)/External/glslang/External/spirv-tools/build\"", + ); + PRODUCT_NAME = SPIRVTools; + SDKROOT = xros; + }; + name = Debug; + }; + DCFD7EBF2A45BA9C007BBBF7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_CHECK_SWITCH_STATEMENTS = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/External/glslang/External/spirv-tools/\"", + "\"$(SRCROOT)/External/glslang/External/spirv-tools/include\"", + "\"$(SRCROOT)/External/glslang/External/spirv-tools/external/spirv-headers/include\"", + "\"$(SRCROOT)/External/glslang/External/spirv-tools/build\"", + ); + PRODUCT_NAME = SPIRVTools; + SDKROOT = xros; + }; + name = Release; + }; + DCFD7ECA2A45BAAA007BBBF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + DCFD7ECB2A45BAAA007BBBF7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -6068,6 +7514,42 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + DCFD7CA02A45BA7D007BBBF7 /* Build configuration list for PBXNativeTarget "SPIRV-Cross-xrOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DCFD7CA12A45BA7D007BBBF7 /* Debug */, + DCFD7CA22A45BA7D007BBBF7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DCFD7D082A45BA92007BBBF7 /* Build configuration list for PBXNativeTarget "glslang-xrOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DCFD7D092A45BA92007BBBF7 /* Debug */, + DCFD7D0A2A45BA92007BBBF7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DCFD7EBD2A45BA9C007BBBF7 /* Build configuration list for PBXNativeTarget "SPIRV-Tools-xrOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DCFD7EBE2A45BA9C007BBBF7 /* Debug */, + DCFD7EBF2A45BA9C007BBBF7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DCFD7EC92A45BAAA007BBBF7 /* Build configuration list for PBXAggregateTarget "ExternalDependencies-xrOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DCFD7ECA2A45BAAA007BBBF7 /* Debug */, + DCFD7ECB2A45BAAA007BBBF7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = A9F55D25198BE6A7004EC31B /* Project object */; diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-xrOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-xrOS.xcscheme new file mode 100644 index 000000000..288332c83 --- /dev/null +++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-xrOS.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-xrOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-xrOS.xcscheme new file mode 100644 index 000000000..e94a658a6 --- /dev/null +++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-xrOS.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-xrOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-xrOS.xcscheme new file mode 100644 index 000000000..18e609a79 --- /dev/null +++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-xrOS.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-xrOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-xrOS.xcscheme new file mode 100644 index 000000000..9feb36b2c --- /dev/null +++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-xrOS.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Makefile b/Makefile index 62e1ab5f8..b1885f0d3 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,8 @@ all: @$(MAKE) maccat @$(MAKE) tvos @$(MAKE) tvossim + @$(MAKE) visionos + @$(MAKE) visionossim .PHONY: all-debug all-debug: @@ -38,6 +40,8 @@ all-debug: @$(MAKE) maccat-debug @$(MAKE) tvos-debug @$(MAKE) tvossim-debug + @$(MAKE) visionos-debug + @$(MAKE) visionossim-debug .PHONY: macos macos: @@ -87,6 +91,22 @@ tvossim: tvossim-debug: $(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)" -destination "generic/platform=tvOS Simulator" -configuration "Debug" GCC_PREPROCESSOR_DEFINITIONS='$${inherited} $(MAKEARGS)' $(OUTPUT_FMT_CMD) +.PHONY: visionos +visionos: + $(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (visionOS only)" -destination "generic/platform=xrOS" GCC_PREPROCESSOR_DEFINITIONS='$${inherited} $(MAKEARGS)' $(OUTPUT_FMT_CMD) + +.PHONY: visionos-debug +visionos-debug: + $(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (visionOS only)" -destination "generic/platform=xrOS" -configuration "Debug" GCC_PREPROCESSOR_DEFINITIONS='$${inherited} $(MAKEARGS)' $(OUTPUT_FMT_CMD) + +.PHONY: visionossim +visionossim: + $(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (visionOS only)" -destination "generic/platform=xrOS Simulator" GCC_PREPROCESSOR_DEFINITIONS='$${inherited} $(MAKEARGS)' $(OUTPUT_FMT_CMD) + +.PHONY: visionossim-debug +visionossim-debug: + $(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (visionOS only)" -destination "generic/platform=xrOS Simulator" -configuration "Debug" GCC_PREPROCESSOR_DEFINITIONS='$${inherited} $(MAKEARGS)' $(OUTPUT_FMT_CMD) + .PHONY: clean clean: $(XCODEBUILD) clean -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (macOS only)" -destination "generic/platform=macOS" $(OUTPUT_FMT_CMD) diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index 2c4b87eb0..8525d1361 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -365,6 +365,126 @@ A9F3D9DD24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */; }; A9F3D9DE24732A4D00745190 /* MVKSmallVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */; }; A9F3D9DF24732A4D00745190 /* MVKSmallVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */; }; + DCFD7EE42A45BC6E007BBBF7 /* MVKExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A909F65A213B190600FCD6BE /* MVKExtensions.h */; }; + DCFD7EE52A45BC6E007BBBF7 /* vk_mvk_moltenvk.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7691C7DFB4800632CA3 /* vk_mvk_moltenvk.h */; }; + DCFD7EE62A45BC6E007BBBF7 /* MVKDeviceFeatureStructs.def in Headers */ = {isa = PBXBuildFile; fileRef = A987B666289AFB2400F933C8 /* MVKDeviceFeatureStructs.def */; }; + DCFD7EE72A45BC6E007BBBF7 /* mvk_datatypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7671C7DFB4800632CA3 /* mvk_datatypes.h */; }; + DCFD7EE82A45BC6E007BBBF7 /* mvk_vulkan.h in Headers */ = {isa = PBXBuildFile; fileRef = A948BB7E1E51642700DE59F2 /* mvk_vulkan.h */; }; + DCFD7EE92A45BC6E007BBBF7 /* MVKEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149431FB6A3F7005F00B4 /* MVKEnvironment.h */; }; + DCFD7EEA2A45BC6E007BBBF7 /* MVKSurface.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7991C7DFB4800632CA3 /* MVKSurface.h */; }; + DCFD7EEB2A45BC6E007BBBF7 /* MTLRenderPipelineDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DFE21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.h */; }; + DCFD7EEC2A45BC6E007BBBF7 /* MVKInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB78B1C7DFB4800632CA3 /* MVKInstance.h */; }; + DCFD7EED2A45BC6E007BBBF7 /* MVKCommandResourceFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = A95870F61C90D29F009EB096 /* MVKCommandResourceFactory.h */; }; + DCFD7EEE2A45BC6E007BBBF7 /* MVKQueryPool.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB78F1C7DFB4800632CA3 /* MVKQueryPool.h */; }; + DCFD7EEF2A45BC6E007BBBF7 /* MVKCommandEncoderState.h in Headers */ = {isa = PBXBuildFile; fileRef = A95B7D671D3EE486003183D3 /* MVKCommandEncoderState.h */; }; + DCFD7EF02A45BC6E007BBBF7 /* MVKCommandPipelineStateFactoryShaderSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB77C1C7DFB4800632CA3 /* MVKCommandPipelineStateFactoryShaderSource.h */; }; + DCFD7EF12A45BC6E007BBBF7 /* MVKDescriptorSet.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7811C7DFB4800632CA3 /* MVKDescriptorSet.h */; }; + DCFD7EF22A45BC6E007BBBF7 /* MVKBitArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A9D7104E25CDE05E00E38106 /* MVKBitArray.h */; }; + DCFD7EF32A45BC6E007BBBF7 /* NSString+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DD22100B197002781DD /* NSString+MoltenVK.h */; }; + DCFD7EF42A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DD12100B197002781DD /* CAMetalLayer+MoltenVK.h */; }; + DCFD7EF52A45BC6E007BBBF7 /* MVKCodec.h in Headers */ = {isa = PBXBuildFile; fileRef = 45557A5121C9EFF3008868BD /* MVKCodec.h */; }; + DCFD7EF62A45BC6E007BBBF7 /* MVKRenderPass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7931C7DFB4800632CA3 /* MVKRenderPass.h */; }; + DCFD7EF72A45BC6E007BBBF7 /* MVKLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */; }; + DCFD7EF82A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = 4536382D2508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h */; }; + DCFD7EF92A45BC6E007BBBF7 /* MVKQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7911C7DFB4800632CA3 /* MVKQueue.h */; }; + DCFD7EFA2A45BC6E007BBBF7 /* MVKFramebuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7871C7DFB4800632CA3 /* MVKFramebuffer.h */; }; + DCFD7EFB2A45BC6E007BBBF7 /* MVKWatermarkShaderSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A981494B1FB6A3F7005F00B4 /* MVKWatermarkShaderSource.h */; }; + DCFD7EFC2A45BC6E007BBBF7 /* MTLSamplerDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DD32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h */; }; + DCFD7EFD2A45BC6E007BBBF7 /* MVKSync.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB79D1C7DFB4800632CA3 /* MVKSync.h */; }; + DCFD7EFE2A45BC6E007BBBF7 /* MVKDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7831C7DFB4800632CA3 /* MVKDevice.h */; }; + DCFD7EFF2A45BC6E007BBBF7 /* MVKSmallVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */; }; + DCFD7F002A45BC6E007BBBF7 /* MVKCommandPool.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB77A1C7DFB4800632CA3 /* MVKCommandPool.h */; }; + DCFD7F012A45BC6E007BBBF7 /* MVKShaderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7971C7DFB4800632CA3 /* MVKShaderModule.h */; }; + DCFD7F022A45BC6E007BBBF7 /* MVKVulkanAPIObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A99C91012295FAC500A061DA /* MVKVulkanAPIObject.h */; }; + DCFD7F032A45BC6E007BBBF7 /* MVKCmdQueries.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7701C7DFB4800632CA3 /* MVKCmdQueries.h */; }; + DCFD7F042A45BC6E007BBBF7 /* MVKCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7761C7DFB4800632CA3 /* MVKCommand.h */; }; + DCFD7F052A45BC6E007BBBF7 /* MVKBaseObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149421FB6A3F7005F00B4 /* MVKBaseObject.h */; }; + DCFD7F062A45BC6E007BBBF7 /* MVKMTLBufferAllocation.h in Headers */ = {isa = PBXBuildFile; fileRef = A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */; }; + DCFD7F072A45BC6E007BBBF7 /* MVKObjectPool.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149461FB6A3F7005F00B4 /* MVKObjectPool.h */; }; + DCFD7F082A45BC6E007BBBF7 /* MVKSwapchain.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB79B1C7DFB4800632CA3 /* MVKSwapchain.h */; }; + DCFD7F092A45BC6E007BBBF7 /* MVKGPUCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = A93E832E2121C5D3001FEBD4 /* MVKGPUCapture.h */; }; + DCFD7F0A2A45BC6E007BBBF7 /* MVKBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB77F1C7DFB4800632CA3 /* MVKBuffer.h */; }; + DCFD7F0B2A45BC6E007BBBF7 /* MVKCommonEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */; }; + DCFD7F0C2A45BC6E007BBBF7 /* MVKWatermark.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149491FB6A3F7005F00B4 /* MVKWatermark.h */; }; + DCFD7F0D2A45BC6E007BBBF7 /* MVKOSExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */; }; + DCFD7F0E2A45BC6E007BBBF7 /* MVKCmdRenderPass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRenderPass.h */; }; + DCFD7F0F2A45BC6E007BBBF7 /* MVKCmdPipeline.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB76E1C7DFB4800632CA3 /* MVKCmdPipeline.h */; }; + DCFD7F102A45BC6E007BBBF7 /* MVKSmallVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */; }; + DCFD7F112A45BC6E007BBBF7 /* MVKPipeline.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB78D1C7DFB4800632CA3 /* MVKPipeline.h */; }; + DCFD7F122A45BC6E007BBBF7 /* MVKImage.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7891C7DFB4800632CA3 /* MVKImage.h */; }; + DCFD7F132A45BC6E007BBBF7 /* MVKBlockObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4553AEFA2251617100E8EBCD /* MVKBlockObserver.h */; }; + DCFD7F142A45BC6E007BBBF7 /* MVKCmdTransfer.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB76C1C7DFB4800632CA3 /* MVKCmdTransfer.h */; }; + DCFD7F152A45BC6E007BBBF7 /* MVKDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A966A5DC23C535D000BBF9B4 /* MVKDescriptor.h */; }; + DCFD7F162A45BC6E007BBBF7 /* MVKCmdDraw.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7741C7DFB4800632CA3 /* MVKCmdDraw.h */; }; + DCFD7F172A45BC6E007BBBF7 /* MVKCommandBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7781C7DFB4800632CA3 /* MVKCommandBuffer.h */; }; + DCFD7F182A45BC6E007BBBF7 /* MTLRenderPassDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */; }; + DCFD7F192A45BC6E007BBBF7 /* MVKCmdDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = A99C90EC229455B200A061DA /* MVKCmdDebug.h */; }; + DCFD7F1A2A45BC6E007BBBF7 /* MVKWatermarkTextureContent.h in Headers */ = {isa = PBXBuildFile; fileRef = A981494C1FB6A3F7005F00B4 /* MVKWatermarkTextureContent.h */; }; + DCFD7F1B2A45BC6E007BBBF7 /* MVKFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149441FB6A3F7005F00B4 /* MVKFoundation.h */; }; + DCFD7F1C2A45BC6E007BBBF7 /* MVKDeviceMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7851C7DFB4800632CA3 /* MVKDeviceMemory.h */; }; + DCFD7F1D2A45BC6E007BBBF7 /* MVKMTLResourceBindings.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E4B7881E1D8AF10046A4CE /* MVKMTLResourceBindings.h */; }; + DCFD7F1E2A45BC6E007BBBF7 /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; }; + DCFD7F1F2A45BC6E007BBBF7 /* mvk_datatypes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A9CEAAD1227378D400FAF779 /* mvk_datatypes.hpp */; }; + DCFD7F202A45BC6E007BBBF7 /* MVKCommandEncodingPool.h in Headers */ = {isa = PBXBuildFile; fileRef = A90C8DE81F45354D009CB32C /* MVKCommandEncodingPool.h */; }; + DCFD7F212A45BC6E007BBBF7 /* MVKResource.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7951C7DFB4800632CA3 /* MVKResource.h */; }; + DCFD7F222A45BC6E007BBBF7 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = 453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */; }; + DCFD7F232A45BC6E007BBBF7 /* MTLTextureDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DD02100B197002781DD /* MTLTextureDescriptor+MoltenVK.h */; }; + DCFD7F242A45BC6E007BBBF7 /* MVKPixelFormats.h in Headers */ = {isa = PBXBuildFile; fileRef = A9653FB724129C84005999D7 /* MVKPixelFormats.h */; }; + DCFD7F252A45BC6E007BBBF7 /* MVKStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = A981496A1FB6A998005F00B4 /* MVKStrings.h */; }; + DCFD7F262A45BC6E007BBBF7 /* MVKLayers.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7A01C7DFB4800632CA3 /* MVKLayers.h */; }; + DCFD7F282A45BC6E007BBBF7 /* MVKBlockObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 4553AEF62251617100E8EBCD /* MVKBlockObserver.m */; }; + DCFD7F292A45BC6E007BBBF7 /* MTLRenderPipelineDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DFA21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m */; }; + DCFD7F2A2A45BC6E007BBBF7 /* MVKResource.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7961C7DFB4800632CA3 /* MVKResource.mm */; }; + DCFD7F2B2A45BC6E007BBBF7 /* MVKDescriptorSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7821C7DFB4800632CA3 /* MVKDescriptorSet.mm */; }; + DCFD7F2C2A45BC6E007BBBF7 /* MVKVulkanAPIObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = A99C91002295FAC500A061DA /* MVKVulkanAPIObject.mm */; }; + DCFD7F2D2A45BC6E007BBBF7 /* MTLTextureDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */; }; + DCFD7F2E2A45BC6E007BBBF7 /* MVKCommandResourceFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = A95870F71C90D29F009EB096 /* MVKCommandResourceFactory.mm */; }; + DCFD7F2F2A45BC6E007BBBF7 /* MVKCommandEncodingPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = A90C8DE91F45354D009CB32C /* MVKCommandEncodingPool.mm */; }; + DCFD7F302A45BC6E007BBBF7 /* MVKWatermark.mm in Sources */ = {isa = PBXBuildFile; fileRef = A981494A1FB6A3F7005F00B4 /* MVKWatermark.mm */; }; + DCFD7F312A45BC6E007BBBF7 /* MVKBaseObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = A98149411FB6A3F7005F00B4 /* MVKBaseObject.mm */; }; + DCFD7F322A45BC6E007BBBF7 /* NSString+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD42100B197002781DD /* NSString+MoltenVK.mm */; }; + DCFD7F332A45BC6E007BBBF7 /* vulkan.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AD1C7DFB4800632CA3 /* vulkan.mm */; }; + DCFD7F342A45BC6E007BBBF7 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */; }; + DCFD7F352A45BC6E007BBBF7 /* MVKSurface.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB79A1C7DFB4800632CA3 /* MVKSurface.mm */; }; + DCFD7F362A45BC6E007BBBF7 /* MVKQueryPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7901C7DFB4800632CA3 /* MVKQueryPool.mm */; }; + DCFD7F372A45BC6E007BBBF7 /* MVKInstance.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB78C1C7DFB4800632CA3 /* MVKInstance.mm */; }; + DCFD7F382A45BC6E007BBBF7 /* MVKDeviceMemory.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7861C7DFB4800632CA3 /* MVKDeviceMemory.mm */; }; + DCFD7F392A45BC6E007BBBF7 /* MVKImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB78A1C7DFB4800632CA3 /* MVKImage.mm */; }; + DCFD7F3A2A45BC6E007BBBF7 /* MVKCommandPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB77B1C7DFB4800632CA3 /* MVKCommandPool.mm */; }; + DCFD7F3B2A45BC6E007BBBF7 /* MVKCmdDraw.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7751C7DFB4800632CA3 /* MVKCmdDraw.mm */; }; + DCFD7F3C2A45BC6E007BBBF7 /* MVKCommandBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7791C7DFB4800632CA3 /* MVKCommandBuffer.mm */; }; + DCFD7F3D2A45BC6E007BBBF7 /* MVKCmdRenderPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRenderPass.mm */; }; + DCFD7F3E2A45BC6E007BBBF7 /* MVKBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7801C7DFB4800632CA3 /* MVKBuffer.mm */; }; + DCFD7F3F2A45BC6E007BBBF7 /* MVKEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */; }; + DCFD7F402A45BC6E007BBBF7 /* mvk_datatypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A91C7DFB4800632CA3 /* mvk_datatypes.mm */; }; + DCFD7F412A45BC6E007BBBF7 /* MVKExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = A909F65E213B190700FCD6BE /* MVKExtensions.mm */; }; + DCFD7F422A45BC6E007BBBF7 /* MVKFoundation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A98149451FB6A3F7005F00B4 /* MVKFoundation.cpp */; }; + DCFD7F432A45BC6E007BBBF7 /* MVKPixelFormats.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9653FB924129C84005999D7 /* MVKPixelFormats.mm */; }; + DCFD7F442A45BC6E007BBBF7 /* MVKDevice.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7841C7DFB4800632CA3 /* MVKDevice.mm */; }; + DCFD7F452A45BC6E007BBBF7 /* MTLRenderPassDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DF22100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m */; }; + DCFD7F462A45BC6E007BBBF7 /* MVKDescriptor.mm in Sources */ = {isa = PBXBuildFile; fileRef = A966A5DE23C535D000BBF9B4 /* MVKDescriptor.mm */; }; + DCFD7F472A45BC6E007BBBF7 /* MVKPipeline.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB78E1C7DFB4800632CA3 /* MVKPipeline.mm */; }; + DCFD7F482A45BC6E007BBBF7 /* MVKQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7921C7DFB4800632CA3 /* MVKQueue.mm */; }; + DCFD7F492A45BC6E007BBBF7 /* MTLSamplerDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DCD2100B197002781DD /* MTLSamplerDescriptor+MoltenVK.m */; }; + DCFD7F4A2A45BC6E007BBBF7 /* MVKRenderPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7941C7DFB4800632CA3 /* MVKRenderPass.mm */; }; + DCFD7F4B2A45BC6E007BBBF7 /* MVKCmdTransfer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB76D1C7DFB4800632CA3 /* MVKCmdTransfer.mm */; }; + DCFD7F4C2A45BC6E007BBBF7 /* MVKCmdQueries.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7711C7DFB4800632CA3 /* MVKCmdQueries.mm */; }; + DCFD7F4D2A45BC6E007BBBF7 /* vk_mvk_moltenvk.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* vk_mvk_moltenvk.mm */; }; + DCFD7F4E2A45BC6E007BBBF7 /* MVKSwapchain.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB79C1C7DFB4800632CA3 /* MVKSwapchain.mm */; }; + DCFD7F4F2A45BC6E007BBBF7 /* MVKCommandEncoderState.mm in Sources */ = {isa = PBXBuildFile; fileRef = A95B7D681D3EE486003183D3 /* MVKCommandEncoderState.mm */; }; + DCFD7F502A45BC6E007BBBF7 /* MVKGPUCapture.mm in Sources */ = {isa = PBXBuildFile; fileRef = A93E83342121F0C8001FEBD4 /* MVKGPUCapture.mm */; }; + DCFD7F512A45BC6E007BBBF7 /* MVKOSExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */; }; + DCFD7F522A45BC6E007BBBF7 /* MVKShaderModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7981C7DFB4800632CA3 /* MVKShaderModule.mm */; }; + DCFD7F532A45BC6E007BBBF7 /* MVKSync.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB79E1C7DFB4800632CA3 /* MVKSync.mm */; }; + DCFD7F542A45BC6E007BBBF7 /* MVKCodec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45557A4D21C9EFF3008868BD /* MVKCodec.mm */; }; + DCFD7F552A45BC6E007BBBF7 /* MVKCmdPipeline.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB76F1C7DFB4800632CA3 /* MVKCmdPipeline.mm */; }; + DCFD7F562A45BC6E007BBBF7 /* MVKLayers.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A11C7DFB4800632CA3 /* MVKLayers.mm */; }; + 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 */; }; + 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 */ /* Begin PBXContainerItemProxy section */ @@ -417,6 +537,20 @@ remoteGlobalIDString = A9092A8C1A81717B00051823; remoteInfo = MoltenVKShaderConverter; }; + DCA2CEAE2A45DFD400FB75B6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A9C86CB61C55B8350096CAF2 /* MoltenVKShaderConverter.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = DCFD7F6F2A45BDA0007BBBF7; + remoteInfo = "MoltenVKShaderConverter-xrOS"; + }; + DCBC41212A45DB1000F49BD1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A9C86CB61C55B8350096CAF2 /* MoltenVKShaderConverter.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = DCFD7F882A45BDA0007BBBF7; + remoteInfo = MoltenVKShaderConverter; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -549,6 +683,7 @@ A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKLogging.h; sourceTree = ""; }; A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKSmallVectorAllocator.h; sourceTree = ""; }; A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKSmallVector.h; sourceTree = ""; }; + DCFD7F622A45BC6E007BBBF7 /* libMoltenVK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMoltenVK.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -716,6 +851,7 @@ A98149821FB6B566005F00B4 /* libMoltenVKShaderConverter.a */, 2FEA0D1C249040CA00EEF3AD /* libMoltenVKShaderConverter.a */, A98149841FB6B566005F00B4 /* libMoltenVKShaderConverter.a */, + DCBC41222A45DB1000F49BD1 /* libMoltenVKShaderConverter.a */, ); name = Products; sourceTree = ""; @@ -783,6 +919,7 @@ A9B8EE0A1A98D796009C5A02 /* libMoltenVK.a */, A9CBEE011B6299D800E45FDC /* libMoltenVK.a */, 2FEA0ABA24902F9F00EEF3AD /* libMoltenVK.a */, + DCFD7F622A45BC6E007BBBF7 /* libMoltenVK.a */, ); name = Products; sourceTree = ""; @@ -1011,6 +1148,80 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCFD7EE32A45BC6E007BBBF7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7EE42A45BC6E007BBBF7 /* MVKExtensions.h in Headers */, + DCFD7EE52A45BC6E007BBBF7 /* vk_mvk_moltenvk.h in Headers */, + DCFD7EE62A45BC6E007BBBF7 /* MVKDeviceFeatureStructs.def in Headers */, + DCFD7EE72A45BC6E007BBBF7 /* mvk_datatypes.h in Headers */, + DCFD7EE82A45BC6E007BBBF7 /* mvk_vulkan.h in Headers */, + DCFD7EE92A45BC6E007BBBF7 /* MVKEnvironment.h in Headers */, + DCFD7EEA2A45BC6E007BBBF7 /* MVKSurface.h in Headers */, + DCFD7EEB2A45BC6E007BBBF7 /* MTLRenderPipelineDescriptor+MoltenVK.h in Headers */, + DCFD7EEC2A45BC6E007BBBF7 /* MVKInstance.h in Headers */, + DCFD7EED2A45BC6E007BBBF7 /* MVKCommandResourceFactory.h in Headers */, + DCFD7EEE2A45BC6E007BBBF7 /* MVKQueryPool.h in Headers */, + DCFD7EEF2A45BC6E007BBBF7 /* MVKCommandEncoderState.h in Headers */, + DCFD7EF02A45BC6E007BBBF7 /* MVKCommandPipelineStateFactoryShaderSource.h in Headers */, + DCFD7EF12A45BC6E007BBBF7 /* MVKDescriptorSet.h in Headers */, + DCFD7EF22A45BC6E007BBBF7 /* MVKBitArray.h in Headers */, + DCFD7EF32A45BC6E007BBBF7 /* NSString+MoltenVK.h in Headers */, + DCFD7EF42A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.h in Headers */, + DCFD7EF52A45BC6E007BBBF7 /* MVKCodec.h in Headers */, + DCFD7EF62A45BC6E007BBBF7 /* MVKRenderPass.h in Headers */, + DCFD7EF72A45BC6E007BBBF7 /* MVKLogging.h in Headers */, + DCFD7EF82A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h in Headers */, + DCFD7EF92A45BC6E007BBBF7 /* MVKQueue.h in Headers */, + DCFD7EFA2A45BC6E007BBBF7 /* MVKFramebuffer.h in Headers */, + DCFD7EFB2A45BC6E007BBBF7 /* MVKWatermarkShaderSource.h in Headers */, + DCFD7EFC2A45BC6E007BBBF7 /* MTLSamplerDescriptor+MoltenVK.h in Headers */, + DCFD7EFD2A45BC6E007BBBF7 /* MVKSync.h in Headers */, + DCFD7EFE2A45BC6E007BBBF7 /* MVKDevice.h in Headers */, + DCFD7EFF2A45BC6E007BBBF7 /* MVKSmallVector.h in Headers */, + DCFD7F002A45BC6E007BBBF7 /* MVKCommandPool.h in Headers */, + DCFD7F012A45BC6E007BBBF7 /* MVKShaderModule.h in Headers */, + DCFD7F022A45BC6E007BBBF7 /* MVKVulkanAPIObject.h in Headers */, + DCFD7F032A45BC6E007BBBF7 /* MVKCmdQueries.h in Headers */, + DCFD7F042A45BC6E007BBBF7 /* MVKCommand.h in Headers */, + DCFD7F052A45BC6E007BBBF7 /* MVKBaseObject.h in Headers */, + DCFD7F062A45BC6E007BBBF7 /* MVKMTLBufferAllocation.h in Headers */, + DCFD7F072A45BC6E007BBBF7 /* MVKObjectPool.h in Headers */, + DCFD7F082A45BC6E007BBBF7 /* MVKSwapchain.h in Headers */, + DCFD7F092A45BC6E007BBBF7 /* MVKGPUCapture.h in Headers */, + DCFD7F0A2A45BC6E007BBBF7 /* MVKBuffer.h in Headers */, + DCFD7F0B2A45BC6E007BBBF7 /* MVKCommonEnvironment.h in Headers */, + DCFD7F0C2A45BC6E007BBBF7 /* MVKWatermark.h in Headers */, + DCFD7F0D2A45BC6E007BBBF7 /* MVKOSExtensions.h in Headers */, + DCFD7F0E2A45BC6E007BBBF7 /* MVKCmdRenderPass.h in Headers */, + DCFD7F0F2A45BC6E007BBBF7 /* MVKCmdPipeline.h in Headers */, + DCFD7F102A45BC6E007BBBF7 /* MVKSmallVectorAllocator.h in Headers */, + DCFD7F112A45BC6E007BBBF7 /* MVKPipeline.h in Headers */, + DCFD7F122A45BC6E007BBBF7 /* MVKImage.h in Headers */, + DCFD7F132A45BC6E007BBBF7 /* MVKBlockObserver.h in Headers */, + DCFD7F142A45BC6E007BBBF7 /* MVKCmdTransfer.h in Headers */, + DCFD7F152A45BC6E007BBBF7 /* MVKDescriptor.h in Headers */, + DCFD7F162A45BC6E007BBBF7 /* MVKCmdDraw.h in Headers */, + DCFD7F172A45BC6E007BBBF7 /* MVKCommandBuffer.h in Headers */, + DCFD7F182A45BC6E007BBBF7 /* MTLRenderPassDescriptor+MoltenVK.h in Headers */, + DCFD7F192A45BC6E007BBBF7 /* MVKCmdDebug.h in Headers */, + DCFD7F1A2A45BC6E007BBBF7 /* MVKWatermarkTextureContent.h in Headers */, + DCFD7F1B2A45BC6E007BBBF7 /* MVKFoundation.h in Headers */, + DCFD7F1C2A45BC6E007BBBF7 /* MVKDeviceMemory.h in Headers */, + DCFD7F1D2A45BC6E007BBBF7 /* MVKMTLResourceBindings.h in Headers */, + DCFD7F1E2A45BC6E007BBBF7 /* MVKExtensions.def in Headers */, + DCFD7F1F2A45BC6E007BBBF7 /* mvk_datatypes.hpp in Headers */, + DCFD7F202A45BC6E007BBBF7 /* MVKCommandEncodingPool.h in Headers */, + DCFD7F212A45BC6E007BBBF7 /* MVKResource.h in Headers */, + DCFD7F222A45BC6E007BBBF7 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h in Headers */, + DCFD7F232A45BC6E007BBBF7 /* MTLTextureDescriptor+MoltenVK.h in Headers */, + DCFD7F242A45BC6E007BBBF7 /* MVKPixelFormats.h in Headers */, + DCFD7F252A45BC6E007BBBF7 /* MVKStrings.h in Headers */, + DCFD7F262A45BC6E007BBBF7 /* MVKLayers.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -1074,6 +1285,26 @@ productReference = A9CBEE011B6299D800E45FDC /* libMoltenVK.a */; productType = "com.apple.product-type.library.static"; }; + DCFD7EDF2A45BC6E007BBBF7 /* MoltenVK-xrOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = DCFD7F5F2A45BC6E007BBBF7 /* Build configuration list for PBXNativeTarget "MoltenVK-xrOS" */; + buildPhases = ( + DCFD7EE22A45BC6E007BBBF7 /* Generate Version Header */, + DCFD7EE32A45BC6E007BBBF7 /* Headers */, + DCFD7F272A45BC6E007BBBF7 /* Sources */, + DCFD7F5D2A45BC6E007BBBF7 /* Copy to Staging */, + DCFD7F5E2A45BC6E007BBBF7 /* Create Dynamic Library */, + ); + buildRules = ( + ); + dependencies = ( + DCA2CEAF2A45DFD400FB75B6 /* PBXTargetDependency */, + ); + name = "MoltenVK-xrOS"; + productName = MoltenVK; + productReference = DCFD7F622A45BC6E007BBBF7 /* libMoltenVK.a */; + productType = "com.apple.product-type.library.static"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -1114,6 +1345,7 @@ A9B8EE091A98D796009C5A02 /* MoltenVK-iOS */, 2FEA0A3B24902F9F00EEF3AD /* MoltenVK-tvOS */, A9CBED861B6299D800E45FDC /* MoltenVK-macOS */, + DCFD7EDF2A45BC6E007BBBF7 /* MoltenVK-xrOS */, ); }; /* End PBXProject section */ @@ -1147,6 +1379,13 @@ remoteRef = A98149831FB6B566005F00B4 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + DCBC41222A45DB1000F49BD1 /* libMoltenVKShaderConverter.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libMoltenVKShaderConverter.a; + remoteRef = DCBC41212A45DB1000F49BD1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXShellScriptBuildPhase section */ @@ -1317,6 +1556,63 @@ shellPath = /bin/sh; shellScript = ". \"${SRCROOT}/../Scripts/copy_to_staging.sh\"\n\n"; }; + DCFD7EE22A45BC6E007BBBF7 /* Generate Version Header */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Generate Version Header"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(BUILT_PRODUCTS_DIR)/mvkGitRevDerived.h", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/../Scripts/gen_moltenvk_rev_hdr.sh\"\n"; + }; + DCFD7F5D2A45BC6E007BBBF7 /* Copy to Staging */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${BUILT_PRODUCTS_DIR}/lib${PRODUCT_NAME}.a", + ); + name = "Copy to Staging"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/$(TARGET_NAME)/CopyPhaseDummyOutputFile", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ". \"${SRCROOT}/../Scripts/copy_to_staging.sh\"\n"; + }; + DCFD7F5E2A45BC6E007BBBF7 /* Create Dynamic Library */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${BUILT_PRODUCTS_DIR}/lib${PRODUCT_NAME}.a", + ); + name = "Create Dynamic Library"; + outputPaths = ( + "${BUILT_PRODUCTS_DIR}/dynamic/lib${PRODUCT_NAME}.dylib", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ". \"${SRCROOT}/../Scripts/create_dylib_xros.sh\"\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -1499,6 +1795,66 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCFD7F272A45BC6E007BBBF7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7F282A45BC6E007BBBF7 /* MVKBlockObserver.m in Sources */, + DCFD7F292A45BC6E007BBBF7 /* MTLRenderPipelineDescriptor+MoltenVK.m in Sources */, + DCFD7F2A2A45BC6E007BBBF7 /* MVKResource.mm in Sources */, + DCFD7F2B2A45BC6E007BBBF7 /* MVKDescriptorSet.mm in Sources */, + DCFD7F2C2A45BC6E007BBBF7 /* MVKVulkanAPIObject.mm in Sources */, + DCFD7F2D2A45BC6E007BBBF7 /* MTLTextureDescriptor+MoltenVK.m in Sources */, + DCFD7F2E2A45BC6E007BBBF7 /* MVKCommandResourceFactory.mm in Sources */, + DCFD7F2F2A45BC6E007BBBF7 /* MVKCommandEncodingPool.mm in Sources */, + DCFD7F302A45BC6E007BBBF7 /* MVKWatermark.mm in Sources */, + DCFD7F312A45BC6E007BBBF7 /* MVKBaseObject.mm in Sources */, + DCFD7F322A45BC6E007BBBF7 /* NSString+MoltenVK.mm in Sources */, + DCFD7F332A45BC6E007BBBF7 /* vulkan.mm in Sources */, + DCFD7F342A45BC6E007BBBF7 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m in Sources */, + DCFD7F352A45BC6E007BBBF7 /* MVKSurface.mm in Sources */, + DCFD7F362A45BC6E007BBBF7 /* MVKQueryPool.mm in Sources */, + DCFD7F372A45BC6E007BBBF7 /* MVKInstance.mm in Sources */, + DCFD7F382A45BC6E007BBBF7 /* MVKDeviceMemory.mm in Sources */, + DCFD7F392A45BC6E007BBBF7 /* MVKImage.mm in Sources */, + DCFD7F3A2A45BC6E007BBBF7 /* MVKCommandPool.mm in Sources */, + DCFD7F3B2A45BC6E007BBBF7 /* MVKCmdDraw.mm in Sources */, + DCFD7F3C2A45BC6E007BBBF7 /* MVKCommandBuffer.mm in Sources */, + DCFD7F3D2A45BC6E007BBBF7 /* MVKCmdRenderPass.mm in Sources */, + DCFD7F3E2A45BC6E007BBBF7 /* MVKBuffer.mm in Sources */, + DCFD7F3F2A45BC6E007BBBF7 /* MVKEnvironment.cpp in Sources */, + DCFD7F402A45BC6E007BBBF7 /* mvk_datatypes.mm in Sources */, + DCFD7F412A45BC6E007BBBF7 /* MVKExtensions.mm in Sources */, + DCFD7F422A45BC6E007BBBF7 /* MVKFoundation.cpp in Sources */, + DCFD7F432A45BC6E007BBBF7 /* MVKPixelFormats.mm in Sources */, + DCFD7F442A45BC6E007BBBF7 /* MVKDevice.mm in Sources */, + DCFD7F452A45BC6E007BBBF7 /* MTLRenderPassDescriptor+MoltenVK.m in Sources */, + DCFD7F462A45BC6E007BBBF7 /* MVKDescriptor.mm in Sources */, + DCFD7F472A45BC6E007BBBF7 /* MVKPipeline.mm in Sources */, + DCFD7F482A45BC6E007BBBF7 /* MVKQueue.mm in Sources */, + DCFD7F492A45BC6E007BBBF7 /* MTLSamplerDescriptor+MoltenVK.m in Sources */, + DCFD7F4A2A45BC6E007BBBF7 /* MVKRenderPass.mm in Sources */, + DCFD7F4B2A45BC6E007BBBF7 /* MVKCmdTransfer.mm in Sources */, + DCFD7F4C2A45BC6E007BBBF7 /* MVKCmdQueries.mm in Sources */, + DCFD7F4D2A45BC6E007BBBF7 /* vk_mvk_moltenvk.mm in Sources */, + DCFD7F4E2A45BC6E007BBBF7 /* MVKSwapchain.mm in Sources */, + DCFD7F4F2A45BC6E007BBBF7 /* MVKCommandEncoderState.mm in Sources */, + DCFD7F502A45BC6E007BBBF7 /* MVKGPUCapture.mm in Sources */, + DCFD7F512A45BC6E007BBBF7 /* MVKOSExtensions.mm in Sources */, + DCFD7F522A45BC6E007BBBF7 /* MVKShaderModule.mm in Sources */, + DCFD7F532A45BC6E007BBBF7 /* MVKSync.mm in Sources */, + DCFD7F542A45BC6E007BBBF7 /* MVKCodec.mm in Sources */, + DCFD7F552A45BC6E007BBBF7 /* MVKCmdPipeline.mm in Sources */, + DCFD7F562A45BC6E007BBBF7 /* MVKLayers.mm in Sources */, + DCFD7F572A45BC6E007BBBF7 /* MVKFramebuffer.mm in Sources */, + DCFD7F582A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */, + DCFD7F592A45BC6E007BBBF7 /* MVKMTLBufferAllocation.mm in Sources */, + DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.m in Sources */, + DCFD7F5B2A45BC6E007BBBF7 /* MVKCmdDispatch.mm in Sources */, + DCFD7F5C2A45BC6E007BBBF7 /* MVKCmdDebug.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -1517,6 +1873,11 @@ name = MoltenVKShaderConverter; targetProxy = A9B1C7F4251AA5AF001D12CC /* PBXContainerItemProxy */; }; + DCA2CEAF2A45DFD400FB75B6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "MoltenVKShaderConverter-xrOS"; + targetProxy = DCA2CEAE2A45DFD400FB75B6 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -1703,6 +2064,20 @@ }; name = Release; }; + DCFD7F602A45BC6E007BBBF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + SDKROOT = xros; + }; + name = Debug; + }; + DCFD7F612A45BC6E007BBBF7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + SDKROOT = xros; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1742,6 +2117,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + DCFD7F5F2A45BC6E007BBBF7 /* Build configuration list for PBXNativeTarget "MoltenVK-xrOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DCFD7F602A45BC6E007BBBF7 /* Debug */, + DCFD7F612A45BC6E007BBBF7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = A9F55D25198BE6A7004EC31B /* Project object */; diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-xrOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-xrOS.xcscheme new file mode 100644 index 000000000..e80fa8c3b --- /dev/null +++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-xrOS.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 3494740e7..14b5e0acd 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -154,7 +154,7 @@ .separateDepthStencilLayouts = true, .hostQueryReset = true, .timelineSemaphore = true, - .bufferDeviceAddress = mvkOSVersionIsAtLeast(12.05, 16.0), + .bufferDeviceAddress = mvkOSVersionIsAtLeast(12.05, 16.0, 1.0), .bufferDeviceAddressCaptureReplay = false, .bufferDeviceAddressMultiDevice = false, .vulkanMemoryModel = false, @@ -784,7 +784,7 @@ if (_features.tessellationShader) { pVk11Props->subgroupSupportedStages |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; } - if (mvkOSVersionIsAtLeast(10.15, 13.0)) { + if (mvkOSVersionIsAtLeast(10.15, 13.0, 1.0)) { pVk11Props->subgroupSupportedStages |= VK_SHADER_STAGE_FRAGMENT_BIT; } pVk11Props->subgroupSupportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 53aba660a..cc25d89d9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -503,14 +503,16 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin VkResult MVKSwapchain::getRefreshCycleDuration(VkRefreshCycleDurationGOOGLE *pRefreshCycleDuration) { if (_device->getConfigurationResult() != VK_SUCCESS) { return _device->getConfigurationResult(); } -#if MVK_IOS_OR_TVOS || MVK_MACCAT +#if MVK_VISIONOS + // TODO: See if this can be obtained from OS instead + NSInteger framesPerSecond = 90; +#elif MVK_IOS_OR_TVOS || MVK_MACCAT NSInteger framesPerSecond = 60; UIScreen* screen = _mtlLayer.screenMVK; if ([screen respondsToSelector: @selector(maximumFramesPerSecond)]) { framesPerSecond = screen.maximumFramesPerSecond; } -#endif -#if MVK_MACOS && !MVK_MACCAT +#elif MVK_MACOS && !MVK_MACCAT NSScreen* screen = _mtlLayer.screenMVK; CGDirectDisplayID displayId = [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 515029c95..c092a99aa 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -16,7 +16,7 @@ * limitations under the License. */ -// To use this file, define the macro MVK_EXTENSION(var, EXT, type, macos, ios), then #include this file. +// To use this file, define the macro MVK_EXTENSION(var, EXT, type, macos, ios, xros), then #include this file. // To add a new extension, simply add an MVK_EXTENSION line below. The macro takes the // portion of the extension name without the leading "VK_", both in lowercase and uppercase, // plus a value representing the extension type (instance/device/...). @@ -38,104 +38,104 @@ #endif #ifndef MVK_EXTENSION_LAST -#define MVK_EXTENSION_LAST(var, EXT, type, macos, ios) MVK_EXTENSION(var, EXT, type, macos, ios) +#define MVK_EXTENSION_LAST(var, EXT, type, macos, ios, xros) MVK_EXTENSION(var, EXT, type, macos, ios, xros) #endif -MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_bind_memory2, KHR_BIND_MEMORY_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_buffer_device_address, KHR_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) -MVK_EXTENSION(KHR_copy_commands2, KHR_COPY_COMMANDS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_create_renderpass2, KHR_CREATE_RENDERPASS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_dedicated_allocation, KHR_DEDICATED_ALLOCATION, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_depth_stencil_resolve, KHR_DEPTH_STENCIL_RESOLVE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_draw_indirect_count, KHR_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(KHR_driver_properties, KHR_DRIVER_PROPERTIES, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_dynamic_rendering, KHR_DYNAMIC_RENDERING, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_fence, KHR_EXTERNAL_FENCE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_fence_capabilities, KHR_EXTERNAL_FENCE_CAPABILITIES, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_memory, KHR_EXTERNAL_MEMORY, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_memory_capabilities, KHR_EXTERNAL_MEMORY_CAPABILITIES, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_semaphore, KHR_EXTERNAL_SEMAPHORE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_external_semaphore_capabilities, KHR_EXTERNAL_SEMAPHORE_CAPABILITIES, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_fragment_shader_barycentric, KHR_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0) -MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_imageless_framebuffer, KHR_IMAGELESS_FRAMEBUFFER, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_portability_subset, KHR_PORTABILITY_SUBSET, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_relaxed_block_layout, KHR_RELAXED_BLOCK_LAYOUT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_sampler_mirror_clamp_to_edge, KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, DEVICE, 10.11, 14.0) -MVK_EXTENSION(KHR_sampler_ycbcr_conversion, KHR_SAMPLER_YCBCR_CONVERSION, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_separate_depth_stencil_layouts, KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_shader_atomic_int64, KHR_SHADER_ATOMIC_INT64, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(KHR_shader_draw_parameters, KHR_SHADER_DRAW_PARAMETERS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_shader_float_controls, KHR_SHADER_FLOAT_CONTROLS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_shader_float16_int8, KHR_SHADER_FLOAT16_INT8, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_shader_subgroup_extended_types, KHR_SHADER_SUBGROUP_EXTENDED_TYPES, DEVICE, 10.14, 13.0) -MVK_EXTENSION(KHR_spirv_1_4, KHR_SPIRV_1_4, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_storage_buffer_storage_class, KHR_STORAGE_BUFFER_STORAGE_CLASS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_surface, KHR_SURFACE, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(KHR_swapchain, KHR_SWAPCHAIN, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_swapchain_mutable_format, KHR_SWAPCHAIN_MUTABLE_FORMAT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_timeline_semaphore, KHR_TIMELINE_SEMAPHORE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) -MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0) -MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA) -MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, DEVICE, 10.13, 11.0) -MVK_EXTENSION(EXT_metal_objects, EXT_METAL_OBJECTS, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(EXT_pipeline_creation_cache_control, EXT_PIPELINE_CREATION_CACHE_CONTROL, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE, 11.0, 11.0) -MVK_EXTENSION(EXT_private_data, EXT_PRIVATE_DATA, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_robustness2, EXT_ROBUSTNESS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_sample_locations, EXT_SAMPLE_LOCATIONS, DEVICE, 10.13, 11.0) -MVK_EXTENSION(EXT_sampler_filter_minmax, EXT_SAMPLER_FILTER_MINMAX, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_separate_stencil_usage, EXT_SEPARATE_STENCIL_USAGE, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_shader_atomic_float, EXT_SHADER_ATOMIC_FLOAT, DEVICE, 13.0, 16.0) -MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE, 10.14, 12.0) -MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_subgroup_size_control, EXT_SUBGROUP_SIZE_CONTROL, DEVICE, 10.14, 13.0) -MVK_EXTENSION(EXT_surface_maintenance1, EXT_SURFACE_MAINTENANCE_1, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE, INSTANCE, 10.11, 9.0) -MVK_EXTENSION(EXT_swapchain_maintenance1, EXT_SWAPCHAIN_MAINTENANCE_1, DEVICE, 10.11, 8.0) -MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT, DEVICE, 10.13, 11.0) -MVK_EXTENSION(EXT_texture_compression_astc_hdr, EXT_TEXTURE_COMPRESSION_ASTC_HDR, DEVICE, 11.0, 13.0) -MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR, DEVICE, 10.11, 8.0) -MVK_EXTENSION(AMD_draw_indirect_count, AMD_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(AMD_gpu_shader_half_float, AMD_GPU_SHADER_HALF_FLOAT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(AMD_negative_viewport_height, AMD_NEGATIVE_VIEWPORT_HEIGHT, DEVICE, 10.11, 8.0) -MVK_EXTENSION(AMD_shader_image_load_store_lod, AMD_SHADER_IMAGE_LOAD_STORE_LOD, DEVICE, 11.0, 8.0) -MVK_EXTENSION(AMD_shader_trinary_minmax, AMD_SHADER_TRINARY_MINMAX, DEVICE, 10.14, 12.0) -MVK_EXTENSION(IMG_format_pvrtc, IMG_FORMAT_PVRTC, DEVICE, 11.0, 8.0) -MVK_EXTENSION(INTEL_shader_integer_functions2, INTEL_SHADER_INTEGER_FUNCTIONS_2, DEVICE, 10.11, 8.0) -MVK_EXTENSION(GOOGLE_display_timing, GOOGLE_DISPLAY_TIMING, DEVICE, 10.11, 8.0) -MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, INSTANCE, MVK_NA, 8.0) -MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, INSTANCE, 10.11, MVK_NA) -MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, INSTANCE, 10.11, 8.0) -MVK_EXTENSION(NV_fragment_shader_barycentric, NV_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0) -MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_bind_memory2, KHR_BIND_MEMORY_2, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_buffer_device_address, KHR_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0, 1.0) +MVK_EXTENSION(KHR_copy_commands2, KHR_COPY_COMMANDS_2, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_create_renderpass2, KHR_CREATE_RENDERPASS_2, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_dedicated_allocation, KHR_DEDICATED_ALLOCATION, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_depth_stencil_resolve, KHR_DEPTH_STENCIL_RESOLVE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_draw_indirect_count, KHR_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA, MVK_NA) +MVK_EXTENSION(KHR_driver_properties, KHR_DRIVER_PROPERTIES, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_dynamic_rendering, KHR_DYNAMIC_RENDERING, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_external_fence, KHR_EXTERNAL_FENCE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_external_fence_capabilities, KHR_EXTERNAL_FENCE_CAPABILITIES, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_external_memory, KHR_EXTERNAL_MEMORY, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_external_memory_capabilities, KHR_EXTERNAL_MEMORY_CAPABILITIES, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_external_semaphore, KHR_EXTERNAL_SEMAPHORE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_external_semaphore_capabilities, KHR_EXTERNAL_SEMAPHORE_CAPABILITIES, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_fragment_shader_barycentric, KHR_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0, 1.0) +MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_imageless_framebuffer, KHR_IMAGELESS_FRAMEBUFFER, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_portability_subset, KHR_PORTABILITY_SUBSET, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_relaxed_block_layout, KHR_RELAXED_BLOCK_LAYOUT, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_sampler_mirror_clamp_to_edge, KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, DEVICE, 10.11, 14.0, 1.0) +MVK_EXTENSION(KHR_sampler_ycbcr_conversion, KHR_SAMPLER_YCBCR_CONVERSION, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_separate_depth_stencil_layouts, KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_shader_atomic_int64, KHR_SHADER_ATOMIC_INT64, DEVICE, MVK_NA, MVK_NA, MVK_NA) +MVK_EXTENSION(KHR_shader_draw_parameters, KHR_SHADER_DRAW_PARAMETERS, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_shader_float_controls, KHR_SHADER_FLOAT_CONTROLS, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_shader_float16_int8, KHR_SHADER_FLOAT16_INT8, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_shader_subgroup_extended_types, KHR_SHADER_SUBGROUP_EXTENDED_TYPES, DEVICE, 10.14, 13.0, 1.0) +MVK_EXTENSION(KHR_spirv_1_4, KHR_SPIRV_1_4, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_storage_buffer_storage_class, KHR_STORAGE_BUFFER_STORAGE_CLASS, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_surface, KHR_SURFACE, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_swapchain, KHR_SWAPCHAIN, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_swapchain_mutable_format, KHR_SWAPCHAIN_MUTABLE_FORMAT, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_timeline_semaphore, KHR_TIMELINE_SEMAPHORE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA, MVK_NA) +MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0, 1.0) +MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE, 10.11, 8.0, 1.0) +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_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_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) +MVK_EXTENSION(EXT_pipeline_creation_cache_control, EXT_PIPELINE_CREATION_CACHE_CONTROL, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE, 11.0, 11.0, 1.0) +MVK_EXTENSION(EXT_private_data, EXT_PRIVATE_DATA, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_robustness2, EXT_ROBUSTNESS_2, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_sample_locations, EXT_SAMPLE_LOCATIONS, DEVICE, 10.13, 11.0, 1.0) +MVK_EXTENSION(EXT_sampler_filter_minmax, EXT_SAMPLER_FILTER_MINMAX, DEVICE, MVK_NA, MVK_NA, MVK_NA) +MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_separate_stencil_usage, EXT_SEPARATE_STENCIL_USAGE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_shader_atomic_float, EXT_SHADER_ATOMIC_FLOAT, DEVICE, 13.0, 16.0, 1.0) +MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE, 10.14, 12.0, 1.0) +MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_subgroup_size_control, EXT_SUBGROUP_SIZE_CONTROL, DEVICE, 10.14, 13.0, 1.0) +MVK_EXTENSION(EXT_surface_maintenance1, EXT_SURFACE_MAINTENANCE_1, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE, INSTANCE, 10.11, 9.0, 1.0) +MVK_EXTENSION(EXT_swapchain_maintenance1, EXT_SWAPCHAIN_MAINTENANCE_1, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT, DEVICE, 10.13, 11.0, 1.0) +MVK_EXTENSION(EXT_texture_compression_astc_hdr, EXT_TEXTURE_COMPRESSION_ASTC_HDR, DEVICE, 11.0, 13.0, 1.0) +MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(AMD_draw_indirect_count, AMD_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA, MVK_NA) +MVK_EXTENSION(AMD_gpu_shader_half_float, AMD_GPU_SHADER_HALF_FLOAT, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(AMD_negative_viewport_height, AMD_NEGATIVE_VIEWPORT_HEIGHT, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(AMD_shader_image_load_store_lod, AMD_SHADER_IMAGE_LOAD_STORE_LOD, DEVICE, 11.0, 8.0, 1.0) +MVK_EXTENSION(AMD_shader_trinary_minmax, AMD_SHADER_TRINARY_MINMAX, DEVICE, 10.14, 12.0, 1.0) +MVK_EXTENSION(IMG_format_pvrtc, IMG_FORMAT_PVRTC, DEVICE, 11.0, 8.0, 1.0) +MVK_EXTENSION(INTEL_shader_integer_functions2, INTEL_SHADER_INTEGER_FUNCTIONS_2, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(GOOGLE_display_timing, GOOGLE_DISPLAY_TIMING, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, INSTANCE, MVK_NA, 8.0, MVK_NA) +MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, INSTANCE, 10.11, MVK_NA, MVK_NA) +MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, INSTANCE, 10.11, 8.0, 1.0) +MVK_EXTENSION(NV_fragment_shader_barycentric, NV_FRAGMENT_SHADER_BARYCENTRIC, DEVICE, 10.15, 14.0, 1.0) +MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER, DEVICE, 10.11, 8.0, 1.0) #undef MVK_EXTENSION #undef MVK_EXTENSION_LAST diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.h b/MoltenVK/MoltenVK/Layers/MVKExtensions.h index 64b35e360..c368da8c7 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.h +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.h @@ -52,7 +52,7 @@ class MVKExtensionList : public MVKBaseObject { union { struct { -#define MVK_EXTENSION(var, EXT, type, macos, ios) MVKExtension vk_ ##var; +#define MVK_EXTENSION(var, EXT, type, macos, ios, xros) MVKExtension vk_ ##var; #include "MVKExtensions.def" }; MVKExtension extensionArray; diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm index 596f5882a..97447ed5c 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm @@ -39,14 +39,14 @@ static VkExtensionProperties mvkMakeExtProps(const char* extensionName, uint32_t } // Extension properties -#define MVK_EXTENSION(var, EXT, type, macos, ios) \ +#define MVK_EXTENSION(var, EXT, type, macos, ios, xros) \ static VkExtensionProperties kVkExtProps_ ##EXT = mvkMakeExtProps(VK_ ##EXT ##_EXTENSION_NAME, VK_ ##EXT ##_SPEC_VERSION); #include "MVKExtensions.def" // Returns whether the specified properties are valid for this platform static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { -#define MVK_EXTENSION_MIN_OS(EXT, MAC, IOS) \ - if (pProperties == &kVkExtProps_##EXT) { return mvkOSVersionIsAtLeast(MAC, IOS); } +#define MVK_EXTENSION_MIN_OS(EXT, MAC, IOS, XROS) \ + if (pProperties == &kVkExtProps_##EXT) { return mvkOSVersionIsAtLeast(MAC, IOS, XROS); } // If the config indicates that not all supported extensions should be advertised, // only advertise those supported extensions that have been specifically configured. @@ -54,18 +54,18 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { if ( !mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL) ) { #define MVK_NA kMVKOSVersionUnsupported if (mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_MOLTENVK)) { - MVK_EXTENSION_MIN_OS(MVK_MOLTENVK, 10.11, 8.0) + MVK_EXTENSION_MIN_OS(MVK_MOLTENVK, 10.11, 8.0, 1.0) } if (mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_WSI)) { - MVK_EXTENSION_MIN_OS(EXT_METAL_SURFACE, 10.11, 8.0) - MVK_EXTENSION_MIN_OS(MVK_IOS_SURFACE, MVK_NA, 8.0) - MVK_EXTENSION_MIN_OS(MVK_MACOS_SURFACE, 10.11, MVK_NA) - MVK_EXTENSION_MIN_OS(KHR_SURFACE, 10.11, 8.0) - MVK_EXTENSION_MIN_OS(KHR_SWAPCHAIN, 10.11, 8.0) + MVK_EXTENSION_MIN_OS(EXT_METAL_SURFACE, 10.11, 8.0, 1.0) + MVK_EXTENSION_MIN_OS(MVK_IOS_SURFACE, MVK_NA, 8.0, 1.0) + MVK_EXTENSION_MIN_OS(MVK_MACOS_SURFACE, 10.11, MVK_NA, MVK_NA) + MVK_EXTENSION_MIN_OS(KHR_SURFACE, 10.11, 8.0, 1.0) + MVK_EXTENSION_MIN_OS(KHR_SWAPCHAIN, 10.11, 8.0, 1.0) } if (mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_PORTABILITY)) { - MVK_EXTENSION_MIN_OS(KHR_PORTABILITY_SUBSET, 10.11, 8.0) - MVK_EXTENSION_MIN_OS(KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, 10.11, 8.0) + MVK_EXTENSION_MIN_OS(KHR_PORTABILITY_SUBSET, 10.11, 8.0, 1.0) + MVK_EXTENSION_MIN_OS(KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, 10.11, 8.0, 1.0) } #undef MVK_NA @@ -73,7 +73,7 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { } // Otherwise, emumerate all available extensions to match the extension being validated for OS support. -#define MVK_EXTENSION(var, EXT, type, macos, ios) MVK_EXTENSION_MIN_OS(EXT, macos, ios) +#define MVK_EXTENSION(var, EXT, type, macos, ios, xros) MVK_EXTENSION_MIN_OS(EXT, macos, ios, xros) #include "MVKExtensions.def" #undef MVK_EXTENSION_MIN_OS @@ -91,8 +91,8 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { #pragma mark MVKExtensionList MVKExtensionList::MVKExtensionList(MVKVulkanAPIObject* apiObject, bool enableForPlatform) : -#define MVK_EXTENSION_LAST(var, EXT, type, macos, ios) vk_ ##var(&kVkExtProps_ ##EXT, enableForPlatform) -#define MVK_EXTENSION(var, EXT, type, macos, ios) MVK_EXTENSION_LAST(var, EXT, type, macos, ios), +#define MVK_EXTENSION_LAST(var, EXT, type, macos, ios, xros) vk_ ##var(&kVkExtProps_ ##EXT, enableForPlatform) +#define MVK_EXTENSION(var, EXT, type, macos, ios, xros) MVK_EXTENSION_LAST(var, EXT, type, macos, ios, xros), #include "MVKExtensions.def" , _apiObject(apiObject) { @@ -104,7 +104,7 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { void MVKExtensionList::initCount() { _count = 0; -#define MVK_EXTENSION(var, EXT, type, macos, ios) _count++; +#define MVK_EXTENSION(var, EXT, type, macos, ios, xros) _count++; #include "MVKExtensions.def" } @@ -113,14 +113,14 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { void MVKExtensionList::disableAllButEnabledInstanceExtensions() { #define MVK_EXTENSION_INSTANCE true #define MVK_EXTENSION_DEVICE false -#define MVK_EXTENSION(var, EXT, type, macos, ios) MVK_ENSURE_EXTENSION_TYPE(var, EXT, type) +#define MVK_EXTENSION(var, EXT, type, macos, ios, xros) MVK_ENSURE_EXTENSION_TYPE(var, EXT, type) #include "MVKExtensions.def" } void MVKExtensionList::disableAllButEnabledDeviceExtensions() { #define MVK_EXTENSION_INSTANCE false #define MVK_EXTENSION_DEVICE true -#define MVK_EXTENSION(var, EXT, type, macos, ios) MVK_ENSURE_EXTENSION_TYPE(var, EXT, type) +#define MVK_EXTENSION(var, EXT, type, macos, ios, xros) MVK_ENSURE_EXTENSION_TYPE(var, EXT, type) #include "MVKExtensions.def" } diff --git a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h index 7181b237c..61a5c4396 100644 --- a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h +++ b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h @@ -76,7 +76,9 @@ */ @property(nonatomic, readwrite) CFStringRef colorspaceNameMVK; +#if !MVK_VISIONOS /** Returns the screen on which this layer is rendering. */ @property(nonatomic, readonly) PLATFORM_SCREEN_CLASS* screenMVK; +#endif @end diff --git a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m index a9e5a009a..9a8b10d8d 100644 --- a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m +++ b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m @@ -80,7 +80,7 @@ -(void) setColorspaceNameMVK: (CFStringRef) name { CGColorSpaceRelease(csRef); } -#if MVK_IOS_OR_TVOS || MVK_MACCAT +#if (MVK_IOS_OR_TVOS || MVK_MACCAT) && !MVK_VISIONOS -(UIScreen*) screenMVK { return UIScreen.mainScreen; } diff --git a/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm b/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm index 785694cd2..7beed626d 100644 --- a/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm +++ b/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm @@ -69,7 +69,7 @@ MVKGPUCaptureScope::MVKGPUCaptureScope(MVKQueue* mvkQueue) { _mtlQueue = [mvkQueue->getMTLCommandQueue() retain]; // retained - if (mvkOSVersionIsAtLeast(10.13, 11.0)) { + if (mvkOSVersionIsAtLeast(10.13, 11.0, 1.0)) { _mtlCaptureScope = [[MTLCaptureManager sharedCaptureManager] newCaptureScopeWithCommandQueue: _mtlQueue]; // retained _mtlCaptureScope.label = @(mvkQueue->getName().c_str()); @@ -79,7 +79,7 @@ // that depends on Apple not taking internal references to capture scopes, but without it, // we could get hung up waiting for a new queue, because the old queues are still outstanding. // This bug was fixed by Apple in macOS 12.4 and iOS 15.4. - if ( !mvkOSVersionIsAtLeast(12.04, 15.04) ) { + if ( !mvkOSVersionIsAtLeast(12.04, 15.04, 1.0) ) { while (_mtlCaptureScope.retainCount > 1) { [_mtlCaptureScope release]; } diff --git a/MoltenVKPackaging.xcodeproj/project.pbxproj b/MoltenVKPackaging.xcodeproj/project.pbxproj index 3483c1361..29899ab6a 100644 --- a/MoltenVKPackaging.xcodeproj/project.pbxproj +++ b/MoltenVKPackaging.xcodeproj/project.pbxproj @@ -69,6 +69,18 @@ name = MoltenVK; productName = Package; }; + DCFD7ED52A45BC56007BBBF7 /* MoltenVK-xrOS */ = { + isa = PBXAggregateTarget; + buildConfigurationList = DCFD7ED92A45BC56007BBBF7 /* Build configuration list for PBXAggregateTarget "MoltenVK-xrOS" */; + buildPhases = ( + DCFD7ED82A45BC56007BBBF7 /* Package MoltenVK */, + ); + dependencies = ( + DCFD7F682A45BC81007BBBF7 /* PBXTargetDependency */, + ); + name = "MoltenVK-xrOS"; + productName = Package; + }; /* End PBXAggregateTarget section */ /* Begin PBXContainerItemProxy section */ @@ -170,6 +182,20 @@ remoteGlobalIDString = 2FEA0D142490381A00EEF3AD; remoteInfo = "MoltenVKSPIRVToMSLConverter-tvOS"; }; + DCFD7F652A45BC7D007BBBF7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A92DB3EE1CE0F72500FBC835 /* MoltenVK.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = DCFD7F622A45BC6E007BBBF7; + remoteInfo = "MoltenVK-xrOS"; + }; + DCFD7F672A45BC81007BBBF7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A92DB3EE1CE0F72500FBC835 /* MoltenVK.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = DCFD7EDF2A45BC6E007BBBF7; + remoteInfo = "MoltenVK-xrOS"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -229,6 +255,7 @@ A92DB3F51CE0F72500FBC835 /* libMoltenVK.a */, 2FEA0ABE2490302F00EEF3AD /* libMoltenVK.a */, A92DB3F71CE0F72500FBC835 /* libMoltenVK.a */, + DCFD7F662A45BC7D007BBBF7 /* libMoltenVK.a */, ); name = Products; sourceTree = ""; @@ -317,6 +344,7 @@ 2FEA0A2F24902F5E00EEF3AD /* MoltenVK-tvOS */, A975D58B2140586700D4834F /* MoltenVK-macOS */, A9AD700D2440ED3B00B9E254 /* MVKShaderConverterTool */, + DCFD7ED52A45BC56007BBBF7 /* MoltenVK-xrOS */, ); }; /* End PBXProject section */ @@ -371,6 +399,13 @@ remoteRef = A9FC5F5C249D2547003CB086 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + DCFD7F662A45BC7D007BBBF7 /* libMoltenVK.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libMoltenVK.a"; + remoteRef = DCFD7F652A45BC7D007BBBF7 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXShellScriptBuildPhase section */ @@ -458,6 +493,22 @@ shellPath = /bin/sh; shellScript = ". \"${SRCROOT}/Scripts/package_all.sh\"\n. \"${SRCROOT}/Scripts/package_shader_converter_tool.sh\"\n\n"; }; + DCFD7ED82A45BC56007BBBF7 /* Package MoltenVK */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${BUILT_PRODUCTS_DIR}/../XCFrameworkStaging", + ); + name = "Package MoltenVK"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/$(TARGET_NAME)/PackagePhaseDummyOutputFile", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ". \"${SRCROOT}/Scripts/package_all.sh\"\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -496,6 +547,11 @@ name = "MoltenVK-tvOS"; targetProxy = A9B1008424F84BA700EADC6E /* PBXContainerItemProxy */; }; + DCFD7F682A45BC81007BBBF7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "MoltenVK-xrOS"; + targetProxy = DCFD7F672A45BC81007BBBF7 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -583,6 +639,20 @@ }; name = Release; }; + DCFD7EDA2A45BC56007BBBF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + DCFD7EDB2A45BC56007BBBF7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -640,6 +710,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + DCFD7ED92A45BC56007BBBF7 /* Build configuration list for PBXAggregateTarget "MoltenVK-xrOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DCFD7EDA2A45BC56007BBBF7 /* Debug */, + DCFD7EDB2A45BC56007BBBF7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = A90B2B1D1A9B6170008EE819 /* Project object */; diff --git a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package (visionOS only).xcscheme b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package (visionOS only).xcscheme new file mode 100644 index 000000000..df10d0755 --- /dev/null +++ b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package (visionOS only).xcscheme @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj index 56957d746..4b64e66d0 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj +++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -65,6 +65,23 @@ A9B51BDD225E98BB00AC74D2 /* MVKOSExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9B51BDB225E98BB00AC74D2 /* MVKOSExtensions.mm */; }; A9F042B21FB4D060009FCCB8 /* MVKCommonEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F042AA1FB4D060009FCCB8 /* MVKCommonEnvironment.h */; }; A9F042B31FB4D060009FCCB8 /* MVKCommonEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F042AA1FB4D060009FCCB8 /* MVKCommonEnvironment.h */; }; + DCFD7F712A45BDA0007BBBF7 /* SPIRVReflection.h in Headers */ = {isa = PBXBuildFile; fileRef = 450A4F5E220CB180007203D7 /* SPIRVReflection.h */; }; + DCFD7F722A45BDA0007BBBF7 /* GLSLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = A920A8A0251B75B70076851C /* GLSLConversion.h */; }; + DCFD7F732A45BDA0007BBBF7 /* MVKStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149651FB6A98A005F00B4 /* MVKStrings.h */; }; + DCFD7F742A45BDA0007BBBF7 /* SPIRVSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = A9546B242672A3B8004BA3E6 /* SPIRVSupport.h */; }; + DCFD7F752A45BDA0007BBBF7 /* SPIRVConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = A928C9171D0488DC00071B88 /* SPIRVConversion.h */; }; + DCFD7F762A45BDA0007BBBF7 /* GLSLToSPIRVConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = A920A8A2251B75B70076851C /* GLSLToSPIRVConverter.h */; }; + DCFD7F772A45BDA0007BBBF7 /* SPIRVToMSLConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = A9093F5B1C58013E0094110D /* SPIRVToMSLConverter.h */; }; + DCFD7F782A45BDA0007BBBF7 /* MVKCommonEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F042AA1FB4D060009FCCB8 /* MVKCommonEnvironment.h */; }; + DCFD7F7A2A45BDA0007BBBF7 /* FileSupport.mm in Sources */ = {isa = PBXBuildFile; fileRef = A925B70A1C7754B2006E7ECD /* FileSupport.mm */; }; + DCFD7F7B2A45BDA0007BBBF7 /* GLSLConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = A920A8A1251B75B70076851C /* GLSLConversion.mm */; }; + DCFD7F7C2A45BDA0007BBBF7 /* GLSLToSPIRVConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A920A89F251B75B70076851C /* GLSLToSPIRVConverter.cpp */; }; + DCFD7F7D2A45BDA0007BBBF7 /* SPIRVToMSLConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9093F5A1C58013E0094110D /* SPIRVToMSLConverter.cpp */; }; + DCFD7F7E2A45BDA0007BBBF7 /* SPIRVConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = A928C9181D0488DC00071B88 /* SPIRVConversion.mm */; }; + DCFD7F7F2A45BDA0007BBBF7 /* SPIRVSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9546B232672A3B8004BA3E6 /* SPIRVSupport.cpp */; }; + DCFD7F812A45BDA0007BBBF7 /* SPIRVTools.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A983870224EEE94800199A05 /* SPIRVTools.xcframework */; }; + DCFD7F822A45BDA0007BBBF7 /* SPIRVCross.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A98386F824EEE91A00199A05 /* SPIRVCross.xcframework */; }; + DCFD7F832A45BDA0007BBBF7 /* glslang.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A98386FD24EEE93700199A05 /* glslang.xcframework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -108,6 +125,7 @@ A9B51BDB225E98BB00AC74D2 /* MVKOSExtensions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKOSExtensions.mm; sourceTree = ""; }; A9B51BDC225E98BB00AC74D2 /* MVKOSExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKOSExtensions.h; sourceTree = ""; }; A9F042AA1FB4D060009FCCB8 /* MVKCommonEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCommonEnvironment.h; sourceTree = ""; }; + DCFD7F882A45BDA0007BBBF7 /* libMoltenVKShaderConverter.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMoltenVKShaderConverter.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -150,6 +168,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCFD7F802A45BDA0007BBBF7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7F812A45BDA0007BBBF7 /* SPIRVTools.xcframework in Frameworks */, + DCFD7F822A45BDA0007BBBF7 /* SPIRVCross.xcframework in Frameworks */, + DCFD7F832A45BDA0007BBBF7 /* glslang.xcframework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -228,6 +256,7 @@ A9F042A81FB4D060009FCCB8 /* Common */, A964B28D1C57EBC400D930D8 /* Products */, A972AD2921CEE6A80013AB25 /* Frameworks */, + DCFD7F882A45BDA0007BBBF7 /* libMoltenVKShaderConverter.a */, ); sourceTree = ""; }; @@ -279,6 +308,21 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCFD7F702A45BDA0007BBBF7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7F712A45BDA0007BBBF7 /* SPIRVReflection.h in Headers */, + DCFD7F722A45BDA0007BBBF7 /* GLSLConversion.h in Headers */, + DCFD7F732A45BDA0007BBBF7 /* MVKStrings.h in Headers */, + DCFD7F742A45BDA0007BBBF7 /* SPIRVSupport.h in Headers */, + DCFD7F752A45BDA0007BBBF7 /* SPIRVConversion.h in Headers */, + DCFD7F762A45BDA0007BBBF7 /* GLSLToSPIRVConverter.h in Headers */, + DCFD7F772A45BDA0007BBBF7 /* SPIRVToMSLConverter.h in Headers */, + DCFD7F782A45BDA0007BBBF7 /* MVKCommonEnvironment.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -353,6 +397,24 @@ productReference = A93903C71C57E9ED00FE90DC /* libMoltenVKShaderConverter.a */; productType = "com.apple.product-type.library.static"; }; + DCFD7F6F2A45BDA0007BBBF7 /* MoltenVKShaderConverter-xrOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = DCFD7F852A45BDA0007BBBF7 /* Build configuration list for PBXNativeTarget "MoltenVKShaderConverter-xrOS" */; + buildPhases = ( + DCFD7F702A45BDA0007BBBF7 /* Headers */, + DCFD7F792A45BDA0007BBBF7 /* Sources */, + DCFD7F802A45BDA0007BBBF7 /* Frameworks */, + DCFD7F842A45BDA0007BBBF7 /* Copy to Staging */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "MoltenVKShaderConverter-xrOS"; + productName = "MetalGLShaderConverter-macOS"; + productReference = DCFD7F882A45BDA0007BBBF7 /* libMoltenVKShaderConverter.a */; + productType = "com.apple.product-type.library.static"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -391,6 +453,7 @@ A93903B81C57E9D700FE90DC /* MoltenVKShaderConverter-iOS */, 2FEA0CFF2490381A00EEF3AD /* MoltenVKShaderConverter-tvOS */, A93903C01C57E9ED00FE90DC /* MoltenVKShaderConverter-macOS */, + DCFD7F6F2A45BDA0007BBBF7 /* MoltenVKShaderConverter-xrOS */, ); }; /* End PBXProject section */ @@ -456,6 +519,26 @@ shellPath = /bin/sh; shellScript = ". \"${SRCROOT}/../Scripts/copy_to_staging.sh\"\n"; }; + DCFD7F842A45BDA0007BBBF7 /* Copy to Staging */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${BUILT_PRODUCTS_DIR}/lib${PRODUCT_NAME}.a", + ); + name = "Copy to Staging"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/$(TARGET_NAME)/CopyPhaseDummyOutputFile", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ". \"${SRCROOT}/../Scripts/copy_to_staging.sh\"\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -510,6 +593,19 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCFD7F792A45BDA0007BBBF7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFD7F7A2A45BDA0007BBBF7 /* FileSupport.mm in Sources */, + DCFD7F7B2A45BDA0007BBBF7 /* GLSLConversion.mm in Sources */, + DCFD7F7C2A45BDA0007BBBF7 /* GLSLToSPIRVConverter.cpp in Sources */, + DCFD7F7D2A45BDA0007BBBF7 /* SPIRVToMSLConverter.cpp in Sources */, + DCFD7F7E2A45BDA0007BBBF7 /* SPIRVConversion.mm in Sources */, + DCFD7F7F2A45BDA0007BBBF7 /* SPIRVSupport.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -707,6 +803,20 @@ }; name = Release; }; + DCFD7F862A45BDA0007BBBF7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + SDKROOT = xros; + }; + name = Debug; + }; + DCFD7F872A45BDA0007BBBF7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + SDKROOT = xros; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -755,6 +865,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + DCFD7F852A45BDA0007BBBF7 /* Build configuration list for PBXNativeTarget "MoltenVKShaderConverter-xrOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DCFD7F862A45BDA0007BBBF7 /* Debug */, + DCFD7F872A45BDA0007BBBF7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = A9F55D25198BE6A7004EC31B /* Project object */; diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter-xrOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter-xrOS.xcscheme new file mode 100644 index 000000000..b78877057 --- /dev/null +++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter-xrOS.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Scripts/create_dylib.sh b/Scripts/create_dylib.sh index 5ba75f67f..27acd1440 100755 --- a/Scripts/create_dylib.sh +++ b/Scripts/create_dylib.sh @@ -45,7 +45,7 @@ clang++ \ -stdlib=${CLANG_CXX_LIBRARY} \ -dynamiclib \ $(printf -- "-arch %s " ${ARCHS}) \ --m${MVK_OS_CLANG}-version-min=${MVK_MIN_OS_VERSION} \ +${MVK_CLANG_OS_MIN_VERSION} \ -compatibility_version 1.0.0 -current_version 1.0.0 \ -install_name "@rpath/${MVK_DYLIB_NAME}" \ -Wno-incompatible-sysroot \ diff --git a/Scripts/create_dylib_ios.sh b/Scripts/create_dylib_ios.sh index a3672f926..b3ae4b8d9 100755 --- a/Scripts/create_dylib_ios.sh +++ b/Scripts/create_dylib_ios.sh @@ -7,7 +7,6 @@ if [ "${IS_MACCATALYST}" == "YES" ]; then exit 0 fi -export MVK_OS_CLANG="ios" export MVK_UX_FWK="UIKit" export MVK_MIN_OS_VERSION=${IPHONEOS_DEPLOYMENT_TARGET} export MVK_IOSURFACE_FWK="-framework IOSurface" diff --git a/Scripts/create_dylib_macos.sh b/Scripts/create_dylib_macos.sh index 0f3447c52..0f72594ca 100755 --- a/Scripts/create_dylib_macos.sh +++ b/Scripts/create_dylib_macos.sh @@ -2,9 +2,9 @@ set -e -export MVK_OS_CLANG="macosx" export MVK_UX_FWK="AppKit" export MVK_MIN_OS_VERSION=${MACOSX_DEPLOYMENT_TARGET} +export MVK_CLANG_OS_MIN_VERSION="-mmacosx-version-min=${MVK_MIN_OS_VERSION}" export MVK_IOSURFACE_FWK="-framework IOSurface" export MVK_IOKIT_FWK="-framework IOKit" diff --git a/Scripts/create_dylib_tvos.sh b/Scripts/create_dylib_tvos.sh index 33cea2ec4..27c223529 100755 --- a/Scripts/create_dylib_tvos.sh +++ b/Scripts/create_dylib_tvos.sh @@ -2,9 +2,9 @@ set -e -export MVK_OS_CLANG="tvos" export MVK_UX_FWK="UIKit" export MVK_MIN_OS_VERSION=${TVOS_DEPLOYMENT_TARGET} +export MVK_CLANG_OS_MIN_VERSION="-mtvos-version-min=${MVK_MIN_OS_VERSION}" export MVK_IOSURFACE_FWK="-framework IOSurface" export MVK_IOKIT_FWK="" diff --git a/Scripts/create_dylib_xros.sh b/Scripts/create_dylib_xros.sh new file mode 100755 index 000000000..23cfacaef --- /dev/null +++ b/Scripts/create_dylib_xros.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +export MVK_UX_FWK="UIKit" +export MVK_MIN_OS_VERSION=${XROS_DEPLOYMENT_TARGET} +export MVK_CLANG_OS_MIN_VERSION="" #"-mxros-version-min=${MVK_MIN_OS_VERSION}" +export MVK_IOSURFACE_FWK="-framework IOSurface" +export MVK_IOKIT_FWK="-framework IOKit" + +. "${SRCROOT}/../Scripts/create_dylib.sh" diff --git a/Scripts/package_moltenvk.sh b/Scripts/package_moltenvk.sh index 396dd129f..cce0dfaf0 100755 --- a/Scripts/package_moltenvk.sh +++ b/Scripts/package_moltenvk.sh @@ -38,6 +38,8 @@ copy_dylib "-iphoneos" "iOS" copy_dylib "-iphonesimulator" "iOS-simulator" copy_dylib "-appletvos" "tvOS" copy_dylib "-appletvsimulator" "tvOS-simulator" +copy_dylib "-xrvos" "xrOS" +copy_dylib "-xrsimulator" "xrOS-simulator" # Remove and replace header include folder rm -rf "${MVK_PKG_PROD_PATH}/include" diff --git a/fetchDependencies b/fetchDependencies index 052cf6045..04e065fe1 100755 --- a/fetchDependencies +++ b/fetchDependencies @@ -26,8 +26,14 @@ # --tvossim # Build the external libraries for the tvOS Simulator platform. # +# --visionos +# Build the external libraries for the visionOS platform. +# +# --visionossim +# Build the external libraries for the visionOS Simulator platform. +# # --all -# Equivalent to specifying [--macos --ios --iossim --maccat --tvos --tvossim]. +# Equivalent to specifying [--macos --ios --iossim --maccat --tvos --tvossim --visionos --visionossim]. # Results in one XCFramework for each external library, each containing # binaries for all supported platforms. # @@ -94,6 +100,8 @@ BLD_IOS_SIM="" BLD_MAC_CAT="" BLD_TVOS="" BLD_TVOS_SIM="" +BLD_VISIONOS="" +BLD_VISIONOS_SIM="" BLD_MACOS="" BLD_SPECIFIED="" XC_CONFIG="Release" @@ -129,6 +137,14 @@ while (( "$#" )); do BLD_TVOS_SIM="Y" shift 1 ;; + --visionos) + BLD_VISIONOS="Y" + shift 1 + ;; + --visionossim) + BLD_VISIONOS_SIM="Y" + shift 1 + ;; --macos) BLD_MACOS="Y" shift 1 @@ -139,6 +155,8 @@ while (( "$#" )); do BLD_MAC_CAT="Y" BLD_TVOS="Y" BLD_TVOS_SIM="Y" + BLD_VISIONOS="Y" + BLD_VISIONOS_SIM="Y" BLD_MACOS="Y" shift 1 ;; @@ -477,6 +495,14 @@ if [ "$BLD_TVOS_SIM" != "" ]; then build "tvOS" "tvOS Simulator" fi +if [ "$BLD_VISIONOS" != "" ]; then + build "xrOS" "xrOS" +fi + +if [ "$BLD_VISIONOS_SIM" != "" ]; then + build "xrOS" "xrOS Simulator" +fi + # Wait for any background process (if selected) to finish if [ "$XC_USE_BCKGND" != "" ]; then wait @@ -495,7 +521,7 @@ else echo "WARNING: You did not specify a platform to build." echo "To build the external libraries, include one or" echo "more of the following platform options:" - echo " --macos --ios --iossim --maccat --tvos --tvossim --all" + echo " --macos --ios --iossim --maccat --tvos --tvossim --visionos --visionossim --all" echo "See the instructions in the fetchDependencies script for more info." fi fi From a756b8cd6e17394e53f3644b32d38f8c8e768503 Mon Sep 17 00:00:00 2001 From: Filip Lundgren Date: Fri, 23 Jun 2023 10:31:22 -0400 Subject: [PATCH 50/74] Fix MVK_MACOS_OR_IOS_OR_VISIONOS check --- Common/MVKCommonEnvironment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/MVKCommonEnvironment.h b/Common/MVKCommonEnvironment.h index 4a99df5b5..ac8c454b3 100644 --- a/Common/MVKCommonEnvironment.h +++ b/Common/MVKCommonEnvironment.h @@ -78,7 +78,7 @@ extern "C" { #endif /** Building for macOS, iOS or visionOS. */ -#ifndef MVK_MACOS_OR_IOS_ORVISIONOS +#ifndef MVK_MACOS_OR_IOS_OR_VISIONOS # define MVK_MACOS_OR_IOS_OR_VISIONOS (MVK_MACOS || MVK_IOS | MVK_VISIONOS) #endif From 67814ba3f319e7271ee9e2057280f98dfa9efe44 Mon Sep 17 00:00:00 2001 From: Filip Lundgren Date: Fri, 23 Jun 2023 10:51:28 -0400 Subject: [PATCH 51/74] Fix build with latest main --- 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 15d8e39e0..0c5ea9b8e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -409,7 +409,7 @@ } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT: { auto* demoteFeatures = (VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT*)next; - demoteFeatures->shaderDemoteToHelperInvocation = mvkOSVersionIsAtLeast(11.0, 14.0); + demoteFeatures->shaderDemoteToHelperInvocation = mvkOSVersionIsAtLeast(11.0, 14.0, 1.0); break; } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: { From 4540175a7dd187ba1d52836d584f0bd57ff05b39 Mon Sep 17 00:00:00 2001 From: Filip Lundgren Date: Fri, 23 Jun 2023 15:08:00 -0400 Subject: [PATCH 52/74] Fix mvkOSVersionIsAtLeast on Vision --- Common/MVKOSExtensions.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h index e28f7c455..58ce2d8e8 100644 --- a/Common/MVKOSExtensions.h +++ b/Common/MVKOSExtensions.h @@ -56,11 +56,10 @@ inline bool mvkOSVersionIsAtLeast(MVKOSVersion macOSMinVer, MVKOSVersion iOSMinV #if MVK_MACOS return mvkOSVersionIsAtLeast(macOSMinVer); #endif -#if MVK_IOS_OR_TVOS - return mvkOSVersionIsAtLeast(iOSMinVer); -#endif #if MVK_VISIONOS return mvkOSVersionIsAtLeast(visionOSMinVer); +#elif MVK_IOS_OR_TVOS + return mvkOSVersionIsAtLeast(iOSMinVer); #endif } From 4e3ac6930523349099a2bd348ac70a143835c39a Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Fri, 23 Jun 2023 01:15:32 -0700 Subject: [PATCH 53/74] Support the `VK_EXT_calibrated_timestamps` extension. This extension has a direct Metal equivalent in the `-[MTLDevice sampleTimestamps:gpuTimestamp:]` method. However, that method returns CPU timestamps in the Mach absolute time domain, which is *not* that of `CLOCK_MONOTONIC_RAW` but of `CLOCK_UPTIME_RAW`. The function that corresponds to `CLOCK_MONOTONIC_RAW` is `mach_continuous_time()`. Therefore, this implementation uses the `mach_continuous_time()` function for the CPU timestamp. Perhaps we should lobby the WG for `VK_TIME_DOMAIN_CLOCK_UPTIME_RAW_EXT`. --- Common/MVKOSExtensions.h | 3 ++ Common/MVKOSExtensions.mm | 8 ++-- Docs/MoltenVK_Runtime_UserGuide.md | 1 + Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 8 ++++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 48 +++++++++++++++++++++ MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 2 + MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Vulkan/vulkan.mm | 28 ++++++++++++ 9 files changed, 97 insertions(+), 3 deletions(-) diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h index 237083258..ff96991c9 100644 --- a/Common/MVKOSExtensions.h +++ b/Common/MVKOSExtensions.h @@ -84,6 +84,9 @@ double mvkGetTimestampPeriod(); */ 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); diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index ef98f0b5e..672335d79 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -40,6 +40,7 @@ MVKOSVersion mvkOSVersion() { static uint64_t _mvkTimestampBase; static double _mvkTimestampPeriod; +static mach_timebase_info_data_t _mvkMachTimebase; uint64_t mvkGetTimestamp() { return mach_absolute_time() - _mvkTimestampBase; } @@ -50,6 +51,8 @@ MVKOSVersion mvkOSVersion() { return (double)(endTimestamp - startTimestamp) * _mvkTimestampPeriod / 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. static bool _mvkTimestampsInitialized = false; @@ -58,9 +61,8 @@ MVKOSVersion mvkOSVersion() { _mvkTimestampsInitialized = true; _mvkTimestampBase = mach_absolute_time(); - mach_timebase_info_data_t timebase; - mach_timebase_info(&timebase); - _mvkTimestampPeriod = (double)timebase.numer / (double)timebase.denom; + mach_timebase_info(&_mvkMachTimebase); + _mvkTimestampPeriod = (double)_mvkMachTimebase.numer / (double)_mvkMachTimebase.denom; } void mvkDispatchToMainAndWait(dispatch_block_t block) { diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 3775a7493..aee9bfa97 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -352,6 +352,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_KHR_variable_pointers` - `VK_EXT_4444_formats` *(requires 16-bit formats and either native texture swizzling or manual swizzling to be enabled)* - `VK_EXT_buffer_device_address` *(requires GPU Tier 2 argument buffers support)* +- `VK_EXT_calibrated_timestamps` *(requires Metal 2.2)* - `VK_EXT_debug_marker` - `VK_EXT_debug_report` - `VK_EXT_debug_utils` diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 1a1284e06..565c96a1c 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -20,6 +20,7 @@ Released TBD - Add support for extensions: - `VK_EXT_4444_formats` + - `VK_EXT_calibrated_timestamps` - `VK_EXT_shader_demote_to_helper_invocation` - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. - Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index d136d7d58..5186fe4a0 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -175,6 +175,9 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { void getExternalSemaphoreProperties(const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); + /** Returns the supported time domains for calibration on this device. */ + VkResult getCalibrateableTimeDomains(uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains); + #pragma mark Surfaces /** @@ -515,6 +518,11 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject { const void* pHostPointer, VkMemoryHostPointerPropertiesEXT* pMemHostPtrProps); + /** Samples timestamps from the specified domains and returns the sampled values. */ + void getCalibratedTimestamps(uint32_t timestampCount, + const VkCalibratedTimestampInfoEXT* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation); #pragma mark Object lifecycle diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index e7186fe16..f18470bc9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -78,6 +78,8 @@ static const VkExtent2D kMetalSamplePositionGridSize = { 1, 1 }; static const VkExtent2D kMetalSamplePositionGridSizeNotSupported = { 0, 0 }; +static const uint32_t kMaxTimeDomains = 2; + #pragma clang diagnostic pop @@ -1120,6 +1122,22 @@ pExternalSemaphoreProperties->pNext = next; } +VkResult MVKPhysicalDevice::getCalibrateableTimeDomains(uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains) { + if (!pTimeDomains) { + *pTimeDomainCount = kMaxTimeDomains; + return VK_SUCCESS; + } + // XXX CLOCK_MONOTONIC_RAW is mach_continuous_time(), but + // -[MTLDevice sampleTimestamps:gpuTimestamp:] returns the CPU + // timestamp in the mach_absolute_time() domain, which is CLOCK_UPTIME_RAW + // (cf. Libc/gen/clock_gettime.c). + static const VkTimeDomainEXT domains[] = { VK_TIME_DOMAIN_DEVICE_EXT, VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT }; + std::copy_n(domains, min(*pTimeDomainCount, kMaxTimeDomains), pTimeDomains); + if (*pTimeDomainCount < kMaxTimeDomains) { return VK_INCOMPLETE; } + *pTimeDomainCount = kMaxTimeDomains; + return VK_SUCCESS; +} + #pragma mark Surfaces @@ -3544,6 +3562,36 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope return VK_SUCCESS; } +void MVKDevice::getCalibratedTimestamps(uint32_t timestampCount, + const VkCalibratedTimestampInfoEXT* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation) { + MTLTimestamp cpuStamp, gpuStamp; + uint64_t cpuStart, cpuEnd; + + cpuStart = mvkGetAbsoluteTime(); + [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(); + for (uint32_t tsIdx = 0; tsIdx < timestampCount; ++tsIdx) { + switch (pTimestampInfos[tsIdx].timeDomain) { + case VK_TIME_DOMAIN_DEVICE_EXT: + pTimestamps[tsIdx] = gpuStamp; + break; + // XXX Should be VK_TIME_DOMAIN_CLOCK_UPTIME_RAW_EXT + case VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT: + pTimestamps[tsIdx] = cpuStart; + break; + default: + continue; + } + } + *pMaxDeviation = cpuEnd - cpuStart; +} #pragma mark Object lifecycle diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 240e1cfe3..5c6e6cb9b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -736,6 +736,8 @@ ADD_DVC_EXT2_ENTRY_POINT(vkGetDeviceGroupSurfacePresentModesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); ADD_DVC_EXT2_ENTRY_POINT(vkGetPhysicalDevicePresentRectanglesKHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); ADD_DVC_EXT2_ENTRY_POINT(vkAcquireNextImage2KHR, KHR_SWAPCHAIN, KHR_DEVICE_GROUP); + ADD_DVC_EXT_ENTRY_POINT(vkGetCalibratedTimestampsEXT, EXT_CALIBRATED_TIMESTAMPS); + ADD_DVC_EXT_ENTRY_POINT(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, EXT_CALIBRATED_TIMESTAMPS); ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectTagEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectNameEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerBeginEXT, EXT_DEBUG_MARKER); diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 4fc208987..37461e624 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -95,6 +95,7 @@ MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, MVK_EXTENSION(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA) MVK_EXTENSION(EXT_4444_formats, EXT_4444_FORMATS, DEVICE, 11.0, 13.0) MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) +MVK_EXTENSION(EXT_calibrated_timestamps, EXT_CALIBRATED_TIMESTAMPS, DEVICE, 10.15, 14.0) MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0) MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE, 10.11, 8.0) diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index 39f8b02e1..27c0166f4 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -3116,6 +3116,34 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPhysicalDeviceSurfaceFormats2KHR( MVK_PUBLIC_VULKAN_CORE_ALIAS(vkGetBufferDeviceAddress, EXT); +#pragma mark - +#pragma mark VK_EXT_calibrated_timestamps extension + +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pTimeDomainCount, + VkTimeDomainEXT* pTimeDomains) { + MVKTraceVulkanCallStart(); + MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice); + mvkPD->getCalibrateableTimeDomains(pTimeDomainCount, pTimeDomains); + MVKTraceVulkanCallEnd(); + return VK_SUCCESS; +} + +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetCalibratedTimestampsEXT( + VkDevice device, + uint32_t timestampCount, + const VkCalibratedTimestampInfoEXT* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation) { + MVKTraceVulkanCallStart(); + MVKDevice* mvkDev = MVKDevice::getMVKDevice(device); + mvkDev->getCalibratedTimestamps(timestampCount, pTimestampInfos, pTimestamps, pMaxDeviation); + MVKTraceVulkanCallEnd(); + return VK_SUCCESS; +} + + #pragma mark - #pragma mark VK_EXT_debug_report extension From 5253e6f9e02843416d57313f5a9507e82d1ea95e Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Sat, 24 Jun 2023 16:46:22 -0700 Subject: [PATCH 54/74] Advertise the `VK_KHR_shader_non_semantic_info` extension. This just provides support for the `SPV_KHR_non_semantic_info` extension, which supports extended instruction sets that do not affect the semantics of a SPIR-V shader (e.g. debug info). SPIRV-Cross already handles these instruction sets, so no additional work is required on our part to support this extension. --- Docs/MoltenVK_Runtime_UserGuide.md | 1 + Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + 3 files changed, 3 insertions(+) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 3775a7493..fb6aae4f8 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -341,6 +341,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_KHR_shader_draw_parameters` - `VK_KHR_shader_float_controls` - `VK_KHR_shader_float16_int8` +- `VK_KHR_shader_non_semantic_info` - `VK_KHR_shader_subgroup_extended_types` *(requires Metal 2.1 on Mac or Metal 2.2 and Apple family 4 on iOS)* - `VK_KHR_spirv_1_4` - `VK_KHR_storage_buffer_storage_class` diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 1a1284e06..241df92b6 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -19,6 +19,7 @@ MoltenVK 1.2.5 Released TBD - Add support for extensions: + - `VK_KHR_shader_non_semantic_info` - `VK_EXT_4444_formats` - `VK_EXT_shader_demote_to_helper_invocation` - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 4fc208987..a72d3ee60 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -83,6 +83,7 @@ MVK_EXTENSION(KHR_shader_atomic_int64, KHR_SHADER_ATOMIC_INT64, MVK_EXTENSION(KHR_shader_draw_parameters, KHR_SHADER_DRAW_PARAMETERS, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_shader_float_controls, KHR_SHADER_FLOAT_CONTROLS, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_shader_float16_int8, KHR_SHADER_FLOAT16_INT8, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_shader_non_semantic_info, KHR_SHADER_NON_SEMANTIC_INFO, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_shader_subgroup_extended_types, KHR_SHADER_SUBGROUP_EXTENDED_TYPES, DEVICE, 10.14, 13.0) MVK_EXTENSION(KHR_spirv_1_4, KHR_SPIRV_1_4, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_storage_buffer_storage_class, KHR_STORAGE_BUFFER_STORAGE_CLASS, DEVICE, 10.11, 8.0) From b74feb7c77fa3343b6b217f50032ad6260b78431 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Sat, 24 Jun 2023 15:38:48 -0700 Subject: [PATCH 55/74] Support `VK_EXT_shader_subgroup_ballot` and `VK_EXT_shader_subgroup_vote`. Update SPIRV-Cross to pull in the needed support for these extensions. --- Docs/MoltenVK_Runtime_UserGuide.md | 2 ++ Docs/Whats_New.md | 2 ++ ExternalRevisions/SPIRV-Cross_repo_revision | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 ++ MoltenVK/MoltenVK/Layers/MVKExtensions.def | 2 ++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index aee9bfa97..c383c6e24 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -377,6 +377,8 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_shader_atomic_float` *(requires Metal 3.0)* - `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` *(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)* - `VK_EXT_shader_viewport_index_layer` - `VK_EXT_subgroup_size_control` *(requires Metal 2.1 on Mac or Metal 2.2 and Apple family 4 on iOS)* - `VK_EXT_surface_maintenance1` diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 565c96a1c..4fcf9f635 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -22,6 +22,8 @@ Released TBD - `VK_EXT_4444_formats` - `VK_EXT_calibrated_timestamps` - `VK_EXT_shader_demote_to_helper_invocation` + - `VK_EXT_shader_subgroup_ballot` + - `VK_EXT_shader_subgroup_vote` - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. - Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. - Support maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision index 6f1034c89..ce73e44aa 100644 --- a/ExternalRevisions/SPIRV-Cross_repo_revision +++ b/ExternalRevisions/SPIRV-Cross_repo_revision @@ -1 +1 @@ -55750be7886a96008b964e75e1eb4a5a6c369a2a +aafcc207ea82308722124db2575aa95f42cb99c9 diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index f18470bc9..623fab99e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -3112,6 +3112,8 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope } if (!_metalFeatures.simdPermute && !_metalFeatures.quadPermute) { pWritableExtns->vk_KHR_shader_subgroup_extended_types.enabled = false; + pWritableExtns->vk_EXT_shader_subgroup_ballot.enabled = false; + pWritableExtns->vk_EXT_shader_subgroup_vote.enabled = false; } if (!_metalFeatures.shaderBarycentricCoordinates) { pWritableExtns->vk_KHR_fragment_shader_barycentric.enabled = false; diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 37461e624..6bd5c9a13 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -120,6 +120,8 @@ MVK_EXTENSION(EXT_separate_stencil_usage, EXT_SEPARATE_STENCIL_USAGE MVK_EXTENSION(EXT_shader_atomic_float, EXT_SHADER_ATOMIC_FLOAT, DEVICE, 13.0, 16.0) MVK_EXTENSION(EXT_shader_demote_to_helper_invocation, EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, DEVICE, 11.0, 14.0) MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE, 10.14, 12.0) +MVK_EXTENSION(EXT_shader_subgroup_ballot, EXT_SHADER_SUBGROUP_BALLOT, DEVICE, 10.14, 13.0) +MVK_EXTENSION(EXT_shader_subgroup_vote, EXT_SHADER_SUBGROUP_VOTE, DEVICE, 10.14, 13.0) MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_subgroup_size_control, EXT_SUBGROUP_SIZE_CONTROL, DEVICE, 10.14, 13.0) MVK_EXTENSION(EXT_surface_maintenance1, EXT_SURFACE_MAINTENANCE_1, INSTANCE, 10.11, 8.0) From e5d3939322d1f791fbee9b528a6a6a0c3f4d5568 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 28 Jun 2023 00:01:12 -0400 Subject: [PATCH 56/74] Add support for VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN. To reduce complexity and repetitive copy-pasted spaghetti code, the design approach here was to implement triangle fan conversion on MVKCmdDrawIndexedIndirect, as the most general of the draw commands, and then populate and invoke a synthetic MVKCmdDrawIndexedIndirect command from the other draw commands. - Rename pipeline factory shader cmdDrawIndexedIndirectMultiviewConvertBuffers() to cmdDrawIndexedIndirectConvertBuffers, and in addition to original support for modifying indirect content to support multiview, add support for converting triangle fan indirect content and indexes to triangle list. - Modify MVKCmdDrawIndexedIndirect to track need to convert triangle fans to triangle list, and invoke kernel function when needed. - Modify MVKCmdDraw, MVKCmdDrawIndexed, and MVKCmdDrawIndirect to populate and invoke a synthetic MVKCmdDrawIndexedIndirect command to convert triangle fans to triangle lists. - Add pipeline factory shader cmdDrawIndirectPopulateIndexes() to convert non-indexed indirect content to indexed indirect content. - MVKCmdDrawIndexedIndirect add support for zero divisor vertex buffers potentially coming from MVKCmdDraw and MVKCmdDrawIndexed. - Rename pipeline factory shader cmdDrawIndexedIndirectConvertBuffers() to cmdDrawIndexedIndirectTessConvertBuffers() so it will be invoked from MVKCommandEncodingPool::getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState() (unrelated). --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/Commands/MVKCmdDraw.h | 12 + MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm | 251 +++++++++++++++--- .../MoltenVK/Commands/MVKCommandBuffer.mm | 2 +- .../Commands/MVKCommandEncodingPool.h | 10 +- .../Commands/MVKCommandEncodingPool.mm | 19 +- ...KCommandPipelineStateFactoryShaderSource.h | 137 ++++++++-- .../Commands/MVKCommandResourceFactory.h | 9 +- .../Commands/MVKCommandResourceFactory.mm | 12 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 5 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 14 +- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 2 +- MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 2 +- 14 files changed, 394 insertions(+), 84 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index a4cc4a538..5131889b8 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -25,6 +25,7 @@ Released TBD - `VK_EXT_shader_demote_to_helper_invocation` - `VK_EXT_shader_subgroup_ballot` - `VK_EXT_shader_subgroup_vote` +- Add support for `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN`. - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. - Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. - Support maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h index 2c3fca39c..c1e4a6936 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h @@ -91,6 +91,7 @@ class MVKCmdDraw : public MVKCommand { uint32_t firstInstance); void encode(MVKCommandEncoder* cmdEncoder) override; + void encodeIndexedIndirect(MVKCommandEncoder* cmdEncoder); protected: MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; @@ -120,6 +121,7 @@ class MVKCmdDrawIndexed : public MVKCommand { protected: MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + void encodeIndexedIndirect(MVKCommandEncoder* cmdEncoder); uint32_t _firstIndex; uint32_t _indexCount; @@ -146,6 +148,7 @@ class MVKCmdDrawIndirect : public MVKCommand { protected: MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + void encodeIndexedIndirect(MVKCommandEncoder* cmdEncoder); id _mtlIndirectBuffer; VkDeviceSize _mtlIndirectBufferOffset; @@ -167,7 +170,15 @@ class MVKCmdDrawIndexedIndirect : public MVKCommand { uint32_t count, uint32_t stride); + VkResult setContent(MVKCommandBuffer* cmdBuff, + id indirectMTLBuff, + VkDeviceSize indirectMTLBuffOffset, + uint32_t drawCount, + uint32_t stride, + uint32_t directCmdFirstInstance); + void encode(MVKCommandEncoder* cmdEncoder) override; + void encode(MVKCommandEncoder* cmdEncoder, const MVKIndexMTLBufferBinding& ibbOrig); protected: MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; @@ -176,4 +187,5 @@ class MVKCmdDrawIndexedIndirect : public MVKCommand { VkDeviceSize _mtlIndirectBufferOffset; uint32_t _mtlIndirectBufferStride; uint32_t _drawCount; + uint32_t _directCmdFirstInstance; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm index 83a48ed56..20d278151 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm @@ -101,6 +101,44 @@ return VK_SUCCESS; } +// Populates and encodes a MVKCmdDrawIndexedIndirect command, after populating indexed indirect buffers. +void MVKCmdDraw::encodeIndexedIndirect(MVKCommandEncoder* cmdEncoder) { + + // Create an indexed indirect buffer and populate it from the draw arguments. + uint32_t indirectIdxBuffStride = sizeof(MTLDrawIndexedPrimitivesIndirectArguments); + auto* indirectIdxBuff = cmdEncoder->getTempMTLBuffer(indirectIdxBuffStride); + auto* pIndArg = (MTLDrawIndexedPrimitivesIndirectArguments*)indirectIdxBuff->getContents(); + pIndArg->indexCount = _vertexCount; + pIndArg->indexStart = _firstVertex; + pIndArg->baseVertex = 0; + pIndArg->instanceCount = _instanceCount; + pIndArg->baseInstance = _firstInstance; + + // Create an index buffer populated with synthetic indexes. + // Start populating indexes below _firstVertex so that indexes align with their corresponding vertexes + MTLIndexType mtlIdxType = MTLIndexTypeUInt32; + auto* vtxIdxBuff = cmdEncoder->getTempMTLBuffer(mvkMTLIndexTypeSizeInBytes(mtlIdxType) * _vertexCount); + auto* pIdxBuff = (uint32_t*)vtxIdxBuff->getContents(); + uint32_t idxCnt = _firstVertex + _vertexCount; + for (uint32_t idx = 0; idx < idxCnt; idx++) { + pIdxBuff[idx] = idx; + } + + MVKIndexMTLBufferBinding ibb; + ibb.mtlIndexType = mtlIdxType; + ibb.mtlBuffer = vtxIdxBuff->_mtlBuffer; + ibb.offset = vtxIdxBuff->_offset; + + MVKCmdDrawIndexedIndirect diiCmd; + diiCmd.setContent(cmdEncoder->_cmdBuffer, + indirectIdxBuff->_mtlBuffer, + indirectIdxBuff->_offset, + 1, + indirectIdxBuffStride, + _firstInstance); + diiCmd.encode(cmdEncoder, ibb); +} + void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) { if (_vertexCount == 0 || _instanceCount == 0) { @@ -108,9 +146,15 @@ return; } - cmdEncoder->_isIndexedDraw = false; + auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); - auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); + // Metal doesn't support triangle fans, so encode it as triangles via an indexed indirect triangles command instead. + if (pipeline->getVkPrimitiveTopology() == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { + encodeIndexedIndirect(cmdEncoder); + return; + } + + cmdEncoder->_isIndexedDraw = false; MVKPiplineStages stages; pipeline->getStages(stages); @@ -297,6 +341,29 @@ return VK_SUCCESS; } +// Populates and encodes a MVKCmdDrawIndexedIndirect command, after populating an indexed indirect buffer. +void MVKCmdDrawIndexed::encodeIndexedIndirect(MVKCommandEncoder* cmdEncoder) { + + // Create an indexed indirect buffer and populate it from the draw arguments. + uint32_t indirectIdxBuffStride = sizeof(MTLDrawIndexedPrimitivesIndirectArguments); + auto* indirectIdxBuff = cmdEncoder->getTempMTLBuffer(indirectIdxBuffStride); + auto* pIndArg = (MTLDrawIndexedPrimitivesIndirectArguments*)indirectIdxBuff->getContents(); + pIndArg->indexCount = _indexCount; + pIndArg->indexStart = _firstIndex; + pIndArg->baseVertex = _vertexOffset; + pIndArg->instanceCount = _instanceCount; + pIndArg->baseInstance = _firstInstance; + + MVKCmdDrawIndexedIndirect diiCmd; + diiCmd.setContent(cmdEncoder->_cmdBuffer, + indirectIdxBuff->_mtlBuffer, + indirectIdxBuff->_offset, + 1, + indirectIdxBuffStride, + _firstInstance); + diiCmd.encode(cmdEncoder); +} + void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { if (_indexCount == 0 || _instanceCount == 0) { @@ -304,9 +371,15 @@ return; } - cmdEncoder->_isIndexedDraw = true; + auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); - auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); + // Metal doesn't support triangle fans, so encode it as triangles via an indexed indirect triangles command instead. + if (pipeline->getVkPrimitiveTopology() == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { + encodeIndexedIndirect(cmdEncoder); + return; + } + + cmdEncoder->_isIndexedDraw = true; MVKPiplineStages stages; pipeline->getStages(stages); @@ -480,6 +553,12 @@ } +// This is totally arbitrary, but we're forced to do this because we don't know how many vertices +// there are at encoding time. And this will probably be inadequate for large instanced draws. +// TODO: Consider breaking up such draws using different base instance values. But this will +// require yet more munging of the indirect buffers... +static const uint32_t kMVKMaxDrawIndirectVertexCount = 128 * KIBI; + #pragma mark - #pragma mark MVKCmdDrawIndirect @@ -506,17 +585,77 @@ return VK_SUCCESS; } -// This is totally arbitrary, but we're forced to do this because we don't know how many vertices -// there are at encoding time. And this will probably be inadequate for large instanced draws. -// TODO: Consider breaking up such draws using different base instance values. But this will -// require yet more munging of the indirect buffers... -static const uint32_t kMVKDrawIndirectVertexCountUpperBound = 131072; +// Populates and encodes a MVKCmdDrawIndexedIndirect command, after populating indexed indirect buffers. +void MVKCmdDrawIndirect::encodeIndexedIndirect(MVKCommandEncoder* cmdEncoder) { + + // Create an indexed indirect buffer to be populated from the non-indexed indirect buffer. + uint32_t indirectIdxBuffStride = sizeof(MTLDrawIndexedPrimitivesIndirectArguments); + auto* indirectIdxBuff = cmdEncoder->getTempMTLBuffer(indirectIdxBuffStride * _drawCount, true); + + // Create an index buffer to be populated with synthetic indexes. + MTLIndexType mtlIdxType = MTLIndexTypeUInt32; + auto* vtxIdxBuff = cmdEncoder->getTempMTLBuffer(mvkMTLIndexTypeSizeInBytes(mtlIdxType) * kMVKMaxDrawIndirectVertexCount, true); + MVKIndexMTLBufferBinding ibb; + ibb.mtlIndexType = mtlIdxType; + ibb.mtlBuffer = vtxIdxBuff->_mtlBuffer; + ibb.offset = vtxIdxBuff->_offset; + + // Schedule a compute action to populate indexed buffers from non-indexed buffers. + cmdEncoder->encodeStoreActions(true); + id mtlConvertEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDrawIndirectConvertBuffers); + id mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectPopulateIndexesMTLComputePipelineState(); + [mtlConvertEncoder setComputePipelineState: mtlConvertState]; + [mtlConvertEncoder setBuffer: _mtlIndirectBuffer + offset: _mtlIndirectBufferOffset + atIndex: 0]; + [mtlConvertEncoder setBuffer: indirectIdxBuff->_mtlBuffer + offset: indirectIdxBuff->_offset + atIndex: 1]; + cmdEncoder->setComputeBytes(mtlConvertEncoder, + &_mtlIndirectBufferStride, + sizeof(_mtlIndirectBufferStride), + 2); + cmdEncoder->setComputeBytes(mtlConvertEncoder, + &_drawCount, + sizeof(_drawCount), + 3); + [mtlConvertEncoder setBuffer: ibb.mtlBuffer + offset: ibb.offset + atIndex: 4]; + if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) { +#if MVK_MACOS_OR_IOS + [mtlConvertEncoder dispatchThreads: MTLSizeMake(_drawCount, 1, 1) + threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)]; +#endif + } else { + [mtlConvertEncoder dispatchThreadgroups: MTLSizeMake(mvkCeilingDivide(_drawCount, mtlConvertState.threadExecutionWidth), 1, 1) + threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)]; + } + // Switch back to rendering now. + cmdEncoder->beginMetalRenderPass(kMVKCommandUseRestartSubpass); + + MVKCmdDrawIndexedIndirect diiCmd; + diiCmd.setContent(cmdEncoder->_cmdBuffer, + indirectIdxBuff->_mtlBuffer, + indirectIdxBuff->_offset, + _drawCount, + indirectIdxBuffStride, + 0); + diiCmd.encode(cmdEncoder, ibb); +} void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { + auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); + + // Metal doesn't support triangle fans, so encode it as indexed indirect triangles instead. + if (pipeline->getVkPrimitiveTopology() == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { + encodeIndexedIndirect(cmdEncoder); + return; + } + cmdEncoder->_isIndexedDraw = false; - auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); bool needsInstanceAdjustment = cmdEncoder->getSubpass()->isMultiview() && cmdEncoder->getPhysicalDevice()->canUseInstancingForMultiview(); // The indirect calls for dispatchThreadgroups:... and drawPatches:... have different formats. @@ -546,7 +685,7 @@ // But not too many, or we'll exhaust available VRAM. inControlPointCount = pipeline->getInputControlPointCount(); outControlPointCount = pipeline->getOutputControlPointCount(); - vertexCount = kMVKDrawIndirectVertexCountUpperBound; + vertexCount = kMVKMaxDrawIndirectVertexCount; patchCount = mvkCeilingDivide(vertexCount, inControlPointCount); VkDeviceSize indirectSize = (2 * sizeof(MTLDispatchThreadgroupsIndirectArguments) + sizeof(MTLDrawPatchIndirectArguments)) * _drawCount; if (cmdEncoder->_pDeviceMetalFeatures->mslVersion >= 20100) { @@ -653,8 +792,8 @@ // Unfortunately, this requires switching to compute. // TODO: Consider using tile shaders to avoid this cost. cmdEncoder->encodeStoreActions(true); - id mtlConvertEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseMultiviewInstanceCountAdjust); - id mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(false); + id mtlConvertEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDrawIndirectConvertBuffers); + id mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectConvertBuffersMTLComputePipelineState(false); uint32_t viewCount; [mtlConvertEncoder setComputePipelineState: mtlConvertState]; [mtlConvertEncoder setBuffer: _mtlIndirectBuffer @@ -801,22 +940,45 @@ #pragma mark - #pragma mark MVKCmdDrawIndexedIndirect +typedef struct MVKVertexAdjustments { + uint8_t mtlIndexType = MTLIndexTypeUInt16; // Enum must match enum in shader + bool isMultiView = false; + bool isTriangleFan = false; + + bool needsAdjustment() { return isMultiView || isTriangleFan; } +} MVKVertexAdjustments; + VkResult MVKCmdDrawIndexedIndirect::setContent(MVKCommandBuffer* cmdBuff, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) { - MVKBuffer* mvkBuffer = (MVKBuffer*)buffer; - _mtlIndirectBuffer = mvkBuffer->getMTLBuffer(); - _mtlIndirectBufferOffset = mvkBuffer->getMTLBufferOffset() + offset; + auto* mvkBuff = (MVKBuffer*)buffer; + return setContent(cmdBuff, + mvkBuff->getMTLBuffer(), + mvkBuff->getMTLBufferOffset() + offset, + drawCount, + stride, + 0); +} + +VkResult MVKCmdDrawIndexedIndirect::setContent(MVKCommandBuffer* cmdBuff, + id indirectMTLBuff, + VkDeviceSize indirectMTLBuffOffset, + uint32_t drawCount, + uint32_t stride, + uint32_t directCmdFirstInstance) { + _mtlIndirectBuffer = indirectMTLBuff; + _mtlIndirectBufferOffset = indirectMTLBuffOffset; _mtlIndirectBufferStride = stride; _drawCount = drawCount; + _directCmdFirstInstance = directCmdFirstInstance; - // Validate + // Validate MVKDevice* mvkDvc = cmdBuff->getDevice(); - if ( !mvkDvc->_pMetalFeatures->indirectDrawing ) { - return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdDrawIndexedIndirect(): The current device does not support indirect drawing."); - } + if ( !mvkDvc->_pMetalFeatures->indirectDrawing ) { + return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdDrawIndexedIndirect(): The current device does not support indirect drawing."); + } if (cmdBuff->_lastTessellationPipeline && !mvkDvc->_pMetalFeatures->indirectTessellationDrawing) { return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdDrawIndexedIndirect(): The current device does not support indirect tessellated drawing."); } @@ -825,14 +987,24 @@ } void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) { + encode(cmdEncoder, cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding); +} + +void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder, const MVKIndexMTLBufferBinding& ibbOrig) { cmdEncoder->_isIndexedDraw = true; - MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding; + MVKIndexMTLBufferBinding ibb = ibbOrig; + MVKIndexMTLBufferBinding ibbTriFan = ibb; auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); - bool needsInstanceAdjustment = cmdEncoder->getSubpass()->isMultiview() && - cmdEncoder->getPhysicalDevice()->canUseInstancingForMultiview(); - // The indirect calls for dispatchThreadgroups:... and drawPatches:... have different formats. + + MVKVertexAdjustments vtxAdjmts; + vtxAdjmts.mtlIndexType = ibb.mtlIndexType; + vtxAdjmts.isMultiView = (cmdEncoder->getSubpass()->isMultiview() && + cmdEncoder->getPhysicalDevice()->canUseInstancingForMultiview()); + vtxAdjmts.isTriangleFan = pipeline->getVkPrimitiveTopology() == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; + + // The indirect calls for dispatchThreadgroups:... and drawPatches:... have different formats. // We have to convert from the drawIndexedPrimitives:... format to them. // While we're at it, we can create the temporary output buffers once and reuse them // for each draw. @@ -861,7 +1033,7 @@ // But not too many, or we'll exhaust available VRAM. inControlPointCount = pipeline->getInputControlPointCount(); outControlPointCount = pipeline->getOutputControlPointCount(); - vertexCount = kMVKDrawIndirectVertexCountUpperBound; + vertexCount = kMVKMaxDrawIndirectVertexCount; patchCount = mvkCeilingDivide(vertexCount, inControlPointCount); VkDeviceSize indirectSize = (sizeof(MTLDispatchThreadgroupsIndirectArguments) + sizeof(MTLDrawPatchIndirectArguments)) * _drawCount; if (cmdEncoder->_pDeviceMetalFeatures->mslVersion >= 20100) { @@ -896,12 +1068,17 @@ sgSize >>= 1; tcWorkgroupSize = mvkLeastCommonMultiple(outControlPointCount, sgSize); } - } else if (needsInstanceAdjustment) { + } else if (vtxAdjmts.needsAdjustment()) { // In this case, we need to adjust the instance count for the views being drawn. VkDeviceSize indirectSize = sizeof(MTLDrawIndexedPrimitivesIndirectArguments) * _drawCount; tempIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize, true); mtlIndBuff = tempIndirectBuff->_mtlBuffer; mtlTempIndBuffOfst = tempIndirectBuff->_offset; + if (vtxAdjmts.isTriangleFan) { + auto* triVtxBuff = cmdEncoder->getTempMTLBuffer(mvkMTLIndexTypeSizeInBytes((MTLIndexType)ibb.mtlIndexType) * kMVKMaxDrawIndirectVertexCount, true); + ibb.mtlBuffer = triVtxBuff->_mtlBuffer; + ibb.offset = triVtxBuff->_offset; + } } MVKPiplineStages stages; @@ -980,14 +1157,14 @@ cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass(); - } else if (drawIdx == 0 && needsInstanceAdjustment) { + } else if (drawIdx == 0 && vtxAdjmts.needsAdjustment()) { // Similarly, for multiview, we need to adjust the instance count now. // Unfortunately, this requires switching to compute. Luckily, we don't also // have to copy the index buffer. // TODO: Consider using tile shaders to avoid this cost. cmdEncoder->encodeStoreActions(true); - id mtlConvertEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseMultiviewInstanceCountAdjust); - id mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(true); + id mtlConvertEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDrawIndirectConvertBuffers); + id mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectConvertBuffersMTLComputePipelineState(true); uint32_t viewCount; [mtlConvertEncoder setComputePipelineState: mtlConvertState]; [mtlConvertEncoder setBuffer: _mtlIndirectBuffer @@ -1009,6 +1186,16 @@ &viewCount, sizeof(viewCount), 4); + cmdEncoder->setComputeBytes(mtlConvertEncoder, + &vtxAdjmts, + sizeof(vtxAdjmts), + 5); + [mtlConvertEncoder setBuffer: ibb.mtlBuffer + offset: ibb.offset + atIndex: 6]; + [mtlConvertEncoder setBuffer: ibbTriFan.mtlBuffer + offset: ibbTriFan.offset + atIndex: 7]; if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) { #if MVK_MACOS_OR_IOS [mtlConvertEncoder dispatchThreads: MTLSizeMake(_drawCount, 1, 1) @@ -1043,6 +1230,9 @@ indirectBufferOffset: mtlTempIndBuffOfst]; mtlTempIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments); } + // If this is a synthetic command that originated in a direct call, and there are vertex bindings with a zero vertex + // divisor, I need to offset them by _firstInstance * stride, since that is the expected behaviour for a divisor of 0. + cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _directCmdFirstInstance); [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff indirectBufferOffset: mtlTempIndBuffOfst threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)]; @@ -1121,13 +1311,14 @@ cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass(); } else { + cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _directCmdFirstInstance); [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType indexType: (MTLIndexType)ibb.mtlIndexType indexBuffer: ibb.mtlBuffer indexBufferOffset: ibb.offset indirectBuffer: mtlIndBuff indirectBufferOffset: mtlTempIndBuffOfst]; - mtlTempIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) : _mtlIndirectBufferStride; + mtlTempIndBuffOfst += vtxAdjmts.needsAdjustment() ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) : _mtlIndirectBufferStride; } break; } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 8ae3031d3..a58d6457d 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -1220,7 +1220,7 @@ case kMVKCommandUseClearColorImage: return @"vkCmdClearColorImage ComputeEncoder"; case kMVKCommandUseResolveImage: return @"Resolve Subpass Attachment ComputeEncoder"; case kMVKCommandUseTessellationVertexTessCtl: return @"vkCmdDraw (vertex and tess control stages) ComputeEncoder"; - case kMVKCommandUseMultiviewInstanceCountAdjust: return @"vkCmdDraw (multiview instance count adjustment) ComputeEncoder"; + case kMVKCommandUseDrawIndirectConvertBuffers: return @"vkCmdDraw (convert indirect buffers) ComputeEncoder"; case kMVKCommandUseCopyQueryPoolResults: return @"vkCmdCopyQueryPoolResults ComputeEncoder"; case kMVKCommandUseAccumOcclusionQuery: return @"Post-render-pass occlusion query accumulation ComputeEncoder"; default: return @"Unknown Use ComputeEncoder"; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h index ba9caf053..ca19abd0c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h @@ -118,8 +118,11 @@ class MVKCommandEncodingPool : public MVKBaseObject { /** Returns a MTLComputePipelineState for decompressing a buffer into a 3D image. */ id getCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needsTempBuff); - /** Returns a MTLComputePipelineState for converting an indirect buffer for use in a multiview draw. */ - id getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed); + /** Returns a MTLComputePipelineState for populating an indirect index buffer from a non-indexed indirect buffer. */ + id getCmdDrawIndirectPopulateIndexesMTLComputePipelineState(); + + /** Returns a MTLComputePipelineState for converting the contents of an indirect buffer. */ + id getCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed); /** Returns a MTLComputePipelineState for converting an indirect buffer for use in a tessellated draw. */ id getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed); @@ -162,10 +165,11 @@ class MVKCommandEncodingPool : public MVKBaseObject { id _cmdClearDefaultDepthStencilState = nil; id _mtlCopyBufferBytesComputePipelineState = nil; id _mtlFillBufferComputePipelineState = nil; + id _mtlDrawIndirectPopulateIndexesComputePipelineState = nil; id _mtlClearColorImageComputePipelineState[3] = {nil, nil, nil}; id _mtlResolveColorImageComputePipelineState[3] = {nil, nil, nil}; id _mtlCopyBufferToImage3DDecompressComputePipelineState[2] = {nil, nil}; - id _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[2] = {nil, nil}; + id _mtlDrawIndirectConvertBuffersComputePipelineState[2] = {nil, nil}; id _mtlDrawIndirectTessConvertBuffersComputePipelineState[2] = {nil, nil}; id _mtlDrawIndexedCopyIndexBufferComputePipelineState[2] = {nil, nil}; id _mtlCopyQueryPoolResultsComputePipelineState = nil; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm index 1d8c893d7..c2ca7b089 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm @@ -139,8 +139,12 @@ static constexpr uint32_t getRenderpassLoadStoreStateIndex(MVKFormatType type) { MVK_ENC_REZ_ACCESS(_mtlCopyBufferToImage3DDecompressComputePipelineState[needsTempBuff ? 1 : 0], newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(needsTempBuff, _commandPool)); } -id MVKCommandEncodingPool::getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed) { - MVK_ENC_REZ_ACCESS(_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[indexed ? 1 : 0], newCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(indexed, _commandPool)); +id MVKCommandEncodingPool::getCmdDrawIndirectPopulateIndexesMTLComputePipelineState() { + MVK_ENC_REZ_ACCESS(_mtlDrawIndirectPopulateIndexesComputePipelineState, newCmdDrawIndirectPopulateIndexesMTLComputePipelineState(_commandPool)); +} + +id MVKCommandEncodingPool::getCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed) { + MVK_ENC_REZ_ACCESS(_mtlDrawIndirectConvertBuffersComputePipelineState[indexed ? 1 : 0], newCmdDrawIndirectConvertBuffersMTLComputePipelineState(indexed, _commandPool)); } id MVKCommandEncodingPool::getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed) { @@ -217,6 +221,9 @@ static constexpr uint32_t getRenderpassLoadStoreStateIndex(MVKFormatType type) { [_mtlFillBufferComputePipelineState release]; _mtlFillBufferComputePipelineState = nil; + [_mtlDrawIndirectPopulateIndexesComputePipelineState release]; + _mtlDrawIndirectPopulateIndexesComputePipelineState = nil; + [_mtlClearColorImageComputePipelineState[0] release]; [_mtlClearColorImageComputePipelineState[1] release]; [_mtlClearColorImageComputePipelineState[2] release]; @@ -236,10 +243,10 @@ static constexpr uint32_t getRenderpassLoadStoreStateIndex(MVKFormatType type) { _mtlCopyBufferToImage3DDecompressComputePipelineState[0] = nil; _mtlCopyBufferToImage3DDecompressComputePipelineState[1] = nil; - [_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[0] release]; - [_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[1] release]; - _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[0] = nil; - _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[1] = nil; + [_mtlDrawIndirectConvertBuffersComputePipelineState[0] release]; + [_mtlDrawIndirectConvertBuffersComputePipelineState[1] release]; + _mtlDrawIndirectConvertBuffersComputePipelineState[0] = nil; + _mtlDrawIndirectConvertBuffersComputePipelineState[1] = nil; [_mtlDrawIndirectTessConvertBuffersComputePipelineState[0] release]; [_mtlDrawIndirectTessConvertBuffersComputePipelineState[1] release]; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h index acd492fc9..39060f537 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h @@ -222,28 +222,119 @@ struct MTLStageInRegionIndirectArguments { }; \n\ #endif \n\ \n\ -kernel void cmdDrawIndirectMultiviewConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\ - device MTLDrawPrimitivesIndirectArguments* destBuff [[buffer(1)]],\n\ - constant uint32_t& srcStride [[buffer(2)]], \n\ - constant uint32_t& drawCount [[buffer(3)]], \n\ - constant uint32_t& viewCount [[buffer(4)]], \n\ - uint idx [[thread_position_in_grid]]) { \n\ +typedef enum : uint8_t { \n\ + MTLIndexTypeUInt16 = 0, \n\ + MTLIndexTypeUInt32 = 1, \n\ +} MTLIndexType; \n\ + \n\ +typedef struct MVKVtxAdj { \n\ + MTLIndexType idxType; \n\ + bool isMultiView; \n\ + bool isTriFan; \n\ +} MVKVtxAdj; \n\ + \n\ +// Populates triangle vertex indexes for a triangle fan. \n\ +template \n\ +static inline void populateTriIndxsFromTriFan(device T* triIdxs, \n\ + constant T* triFanIdxs, \n\ + uint32_t triFanIdxCnt) { \n\ + T primRestartSentinel = (T)0xFFFFFFFF; \n\ + uint32_t triIdxIdx = 0; \n\ + uint32_t triFanBaseIdx = 0; \n\ + uint32_t triFanIdxIdx = triFanBaseIdx + 2; \n\ + while (triFanIdxIdx < triFanIdxCnt) { \n\ + uint32_t triFanBaseIdxCurr = triFanBaseIdx; \n\ + \n\ + // Detect primitive restart on any index, to catch possible consecutive restarts \n\ + T triIdx0 = triFanIdxs[triFanBaseIdx]; \n\ + if (triIdx0 == primRestartSentinel) \n\ + triFanBaseIdx++; \n\ + \n\ + T triIdx1 = triFanIdxs[triFanIdxIdx - 1]; \n\ + if (triIdx1 == primRestartSentinel) \n\ + triFanBaseIdx = triFanIdxIdx; \n\ + \n\ + T triIdx2 = triFanIdxs[triFanIdxIdx]; \n\ + if (triIdx2 == primRestartSentinel) \n\ + triFanBaseIdx = triFanIdxIdx + 1; \n\ + \n\ + if (triFanBaseIdx != triFanBaseIdxCurr) { // Restart the triangle fan \n\ + triFanIdxIdx = triFanBaseIdx + 2; \n\ + } else { \n\ + // Provoking vertex is 1 in triangle fan but 0 in triangle list \n\ + triIdxs[triIdxIdx++] = triIdx1; \n\ + triIdxs[triIdxIdx++] = triIdx2; \n\ + triIdxs[triIdxIdx++] = triIdx0; \n\ + triFanIdxIdx++; \n\ + } \n\ + } \n\ +} \n\ + \n\ +kernel void cmdDrawIndirectPopulateIndexes(const device char* srcBuff [[buffer(0)]], \n\ + device MTLDrawIndexedPrimitivesIndirectArguments* destBuff [[buffer(1)]],\n\ + constant uint32_t& srcStride [[buffer(2)]], \n\ + constant uint32_t& drawCount [[buffer(3)]], \n\ + device uint32_t* idxBuff [[buffer(4)]], \n\ + uint idx [[thread_position_in_grid]]) { \n\ + if (idx >= drawCount) { return; } \n\ + const device auto& src = *reinterpret_cast(srcBuff + idx * srcStride);\n\ + device auto& dst = destBuff[idx]; \n\ + dst.indexCount = src.vertexCount; \n\ + dst.indexStart = src.vertexStart; \n\ + dst.baseVertex = 0; \n\ + dst.instanceCount = src.instanceCount; \n\ + dst.baseInstance = src.baseInstance; \n\ + \n\ + for (uint32_t idxIdx = 0; idxIdx < dst.indexCount; idxIdx++) { \n\ + uint32_t idxBuffIdx = dst.indexStart + idxIdx; \n\ + idxBuff[idxBuffIdx] = idxBuffIdx; \n\ + } \n\ +} \n\ + \n\ +kernel void cmdDrawIndirectConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\ + device MTLDrawPrimitivesIndirectArguments* destBuff [[buffer(1)]], \n\ + constant uint32_t& srcStride [[buffer(2)]], \n\ + constant uint32_t& drawCount [[buffer(3)]], \n\ + constant uint32_t& viewCount [[buffer(4)]], \n\ + uint idx [[thread_position_in_grid]]) { \n\ if (idx >= drawCount) { return; } \n\ const device auto& src = *reinterpret_cast(srcBuff + idx * srcStride);\n\ destBuff[idx] = src; \n\ destBuff[idx].instanceCount *= viewCount; \n\ } \n\ \n\ -kernel void cmdDrawIndexedIndirectMultiviewConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\ - device MTLDrawIndexedPrimitivesIndirectArguments* destBuff [[buffer(1)]],\n\ - constant uint32_t& srcStride [[buffer(2)]], \n\ - constant uint32_t& drawCount [[buffer(3)]], \n\ - constant uint32_t& viewCount [[buffer(4)]], \n\ - uint idx [[thread_position_in_grid]]) { \n\ +kernel void cmdDrawIndexedIndirectConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\ + device MTLDrawIndexedPrimitivesIndirectArguments* destBuff [[buffer(1)]],\n\ + constant uint32_t& srcStride [[buffer(2)]], \n\ + constant uint32_t& drawCount [[buffer(3)]], \n\ + constant uint32_t& viewCount [[buffer(4)]], \n\ + constant MVKVtxAdj& vtxAdj [[buffer(5)]], \n\ + device void* triIdxs [[buffer(6)]], \n\ + constant void* triFanIdxs [[buffer(7)]], \n\ + uint idx [[thread_position_in_grid]]) { \n\ if (idx >= drawCount) { return; } \n\ const device auto& src = *reinterpret_cast(srcBuff + idx * srcStride);\n\ destBuff[idx] = src; \n\ - destBuff[idx].instanceCount *= viewCount; \n\ + \n\ + device auto& dst = destBuff[idx]; \n\ + if (vtxAdj.isMultiView) { \n\ + dst.instanceCount *= viewCount; \n\ + } \n\ + if (vtxAdj.isTriFan) { \n\ + dst.indexCount = (src.indexCount - 2) * 3; \n\ + switch (vtxAdj.idxType) { \n\ + case MTLIndexTypeUInt16: \n\ + populateTriIndxsFromTriFan(&((device uint16_t*)triIdxs)[dst.indexStart], \n\ + &((constant uint16_t*)triFanIdxs)[src.indexStart], \n\ + src.indexCount); \n\ + break; \n\ + case MTLIndexTypeUInt32: \n\ + populateTriIndxsFromTriFan(&((device uint32_t*)triIdxs)[dst.indexStart], \n\ + &((constant uint32_t*)triFanIdxs)[src.indexStart], \n\ + src.indexCount); \n\ + break; \n\ + } \n\ + } \n\ } \n\ \n\ #if __METAL_VERSION__ >= 120 \n\ @@ -292,16 +383,16 @@ kernel void cmdDrawIndirectTessConvertBuffers(const device char* srcBuff [[buffe #endif \n\ } \n\ \n\ -kernel void cmdDrawIndexedIndirectConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\ - device char* destBuff [[buffer(1)]], \n\ - device char* paramsBuff [[buffer(2)]], \n\ - constant uint32_t& srcStride [[buffer(3)]], \n\ - constant uint32_t& inControlPointCount [[buffer(4)]], \n\ - constant uint32_t& outControlPointCount [[buffer(5)]], \n\ - constant uint32_t& drawCount [[buffer(6)]], \n\ - constant uint32_t& vtxThreadExecWidth [[buffer(7)]], \n\ - constant uint32_t& tcWorkgroupSize [[buffer(8)]], \n\ - uint idx [[thread_position_in_grid]]) { \n\ +kernel void cmdDrawIndexedIndirectTessConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\ + device char* destBuff [[buffer(1)]], \n\ + device char* paramsBuff [[buffer(2)]], \n\ + constant uint32_t& srcStride [[buffer(3)]], \n\ + constant uint32_t& inControlPointCount [[buffer(4)]], \n\ + constant uint32_t& outControlPointCount [[buffer(5)]], \n\ + constant uint32_t& drawCount [[buffer(6)]], \n\ + constant uint32_t& vtxThreadExecWidth [[buffer(7)]], \n\ + constant uint32_t& tcWorkgroupSize [[buffer(8)]], \n\ + uint idx [[thread_position_in_grid]]) { \n\ if (idx >= drawCount) { return; } \n\ const device auto& src = *reinterpret_cast(srcBuff + idx * srcStride);\n\ device char* dest; \n\ diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index b7f679c7c..84fa37b64 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -469,9 +469,12 @@ class MVKCommandResourceFactory : public MVKBaseDeviceObject { id newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needTempBuf, MVKVulkanAPIDeviceObject* owner); - /** Returns a new MTLComputePipelineState for converting an indirect buffer for use in a multiview draw. */ - id newCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed, - MVKVulkanAPIDeviceObject* owner); + /** Returns a new MTLComputePipelineState for populating an indirect index buffer from a non-indexed indirect buffer. */ + id newCmdDrawIndirectPopulateIndexesMTLComputePipelineState(MVKVulkanAPIDeviceObject* owner); + + /** Returns a new MTLComputePipelineState for converting the contents of an indirect buffer. */ + id newCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed, + MVKVulkanAPIDeviceObject* owner); /** Returns a new MTLComputePipelineState for converting an indirect buffer for use in a tessellated draw. */ id newCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed, diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index 4e1ed93c0..b3003507c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -580,11 +580,15 @@ static void getSwizzleString(char swizzleStr[4], VkComponentMapping vkMapping) { : "cmdCopyBufferToImage3DDecompressDXTn", owner); } -id MVKCommandResourceFactory::newCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed, - MVKVulkanAPIDeviceObject* owner) { +id MVKCommandResourceFactory::newCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed, + MVKVulkanAPIDeviceObject* owner) { return newMTLComputePipelineState(indexed - ? "cmdDrawIndexedIndirectMultiviewConvertBuffers" - : "cmdDrawIndirectMultiviewConvertBuffers", owner); + ? "cmdDrawIndexedIndirectConvertBuffers" + : "cmdDrawIndirectConvertBuffers", owner); +} + +id MVKCommandResourceFactory::newCmdDrawIndirectPopulateIndexesMTLComputePipelineState(MVKVulkanAPIDeviceObject* owner) { + return newMTLComputePipelineState("cmdDrawIndirectPopulateIndexes", owner); } id MVKCommandResourceFactory::newCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 623fab99e..3723a8f16 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -369,7 +369,7 @@ portabilityFeatures->shaderSampleRateInterpolationFunctions = _metalFeatures.pullModelInterpolation; portabilityFeatures->tessellationIsolines = false; portabilityFeatures->tessellationPointMode = false; - portabilityFeatures->triangleFans = false; + portabilityFeatures->triangleFans = true; portabilityFeatures->vertexAttributeAccessBeyondStride = true; // Costs additional buffers. Should make configuration switch. break; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 0d763e266..e81f93df3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -274,6 +274,9 @@ class MVKGraphicsPipeline : public MVKPipeline { /** Returns whether this pipeline has custom sample positions enabled. */ bool isUsingCustomSamplePositions() { return _isUsingCustomSamplePositions; } + /** Returns the Vulkan primitive topology. */ + VkPrimitiveTopology getVkPrimitiveTopology() { return _vkPrimitiveTopology; } + bool usesPhysicalStorageBufferAddressesCapability(MVKShaderStage stage) override; /** @@ -380,10 +383,10 @@ class MVKGraphicsPipeline : public MVKPipeline { MTLWinding _mtlFrontWinding; MTLTriangleFillMode _mtlFillMode; MTLDepthClipMode _mtlDepthClipMode; - MTLPrimitiveType _mtlPrimitiveType; MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount; MVKShaderImplicitRezBinding _viewRangeBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex; + VkPrimitiveTopology _vkPrimitiveTopology; uint32_t _outputControlPointCount; uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index f8142936c..a9fc1ec10 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -300,7 +300,7 @@ cmdEncoder->_depthBiasState.setDepthBias(_rasterInfo); cmdEncoder->_viewportState.setViewports(_viewports.contents(), 0, false); cmdEncoder->_scissorState.setScissors(_scissors.contents(), 0, false); - cmdEncoder->_mtlPrimitiveType = _mtlPrimitiveType; + cmdEncoder->_mtlPrimitiveType = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(_vkPrimitiveTopology); [mtlCmdEnc setCullMode: _mtlCullMode]; [mtlCmdEnc setFrontFacingWinding: _mtlFrontWinding]; @@ -459,15 +459,9 @@ } // Topology - _mtlPrimitiveType = MTLPrimitiveTypePoint; - if (pCreateInfo->pInputAssemblyState && !isRenderingPoints(pCreateInfo)) { - _mtlPrimitiveType = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(pCreateInfo->pInputAssemblyState->topology); - // Explicitly fail creation with triangle fan topology. - if (pCreateInfo->pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { - setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support triangle fans.")); - return; - } - } + _vkPrimitiveTopology = (pCreateInfo->pInputAssemblyState && !isRenderingPoints(pCreateInfo) + ? pCreateInfo->pInputAssemblyState->topology + : VK_PRIMITIVE_TOPOLOGY_POINT_LIST); // Rasterization _mtlCullMode = MTLCullModeNone; diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index 269cc9f4c..b8f10720f 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -91,7 +91,7 @@ typedef enum : uint8_t { kMVKCommandUseResetQueryPool, /**< vkCmdResetQueryPool. */ kMVKCommandUseDispatch, /**< vkCmdDispatch. */ kMVKCommandUseTessellationVertexTessCtl, /**< vkCmdDraw* - vertex and tessellation control stages. */ - kMVKCommandUseMultiviewInstanceCountAdjust, /**< vkCmdDrawIndirect* - adjust instance count for multiview. */ + kMVKCommandUseDrawIndirectConvertBuffers, /**< vkCmdDrawIndirect* convert indirect buffers. */ kMVKCommandUseCopyQueryPoolResults, /**< vkCmdCopyQueryPoolResults. */ kMVKCommandUseAccumOcclusionQuery, /**< Any command terminating a Metal render pass with active visibility buffer. */ kMVKCommandUseRecordGPUCounterSample /**< Any command triggering the recording of a GPU counter sample. */ diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index 1aab82ebc..23c567ccb 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -451,13 +451,13 @@ MTLPrimitiveType mvkMTLPrimitiveTypeFromVkPrimitiveTopologyInObj(VkPrimitiveTopo case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: return MTLPrimitiveTypeTriangle; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: return MTLPrimitiveTypeTriangleStrip; - case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: default: MVKBaseObject::reportError(mvkObj, VK_ERROR_FORMAT_NOT_SUPPORTED, "VkPrimitiveTopology value %d is not supported for rendering.", vkTopology); return MTLPrimitiveTypePoint; From c34bb54d481c12a4088de50dc6a97dc2df12b4b4 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 29 Jun 2023 17:56:25 -0400 Subject: [PATCH 57/74] Fix unreachable code in MVKDeferredOperation::join(). - Fix unreachable code in MVKDeferredOperation::join(). - Refactor code so deferred functions call back to MVKDeferredOperation instance to update current status, and deferred function execution returns result of individual thread execution. - MVKDeferredOperation use MVKSmallVector for _functionParameters. - MVKDeferredOperation use a single mutex lock. - Add additional comments explaining design to developers of future extensions that use deferred operations. --- MoltenVK/MoltenVK/GPUObjects/MVKSync.h | 106 ++++++++++++++---------- MoltenVK/MoltenVK/GPUObjects/MVKSync.mm | 71 ++++++++++------ MoltenVK/MoltenVK/Vulkan/vulkan.mm | 2 +- 3 files changed, 108 insertions(+), 71 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h index a345b4c69..ad87f715a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h @@ -640,67 +640,85 @@ class MVKMetalCompiler : public MVKBaseObject { #pragma mark - #pragma mark MVKDeferredOperation +/** The maximum number of function parameters for all functions added to MVKDeferredOperationFunctionPointer. */ +static const int kMVKMaxDeferredFunctionParameters = 3; + /** Defines the function pointer for each dependent function. */ -union MVKDeferredOperationFunctionPointer -{ - // Empty until deferred functions from other extensions have been defined - // Planning to use std::functions +union MVKDeferredOperationFunctionPointer { + // Empty until deferred functions from other extensions have been defined. + // Planning to use std::functions + // Each function should take a pointer to a MVKDeferredOperation instance, to allow + // the function to call setMaxConcurrency() and setOperationResult(), and should + // return a VkResult representing the value returned by vkDeferredOperationJoinKHR(). }; /** Indicates what kind of function is being deferred. */ -enum MVKDeferredOperationFunctionType -{ +enum MVKDeferredOperationFunctionType { // Empty until deferred functions from other extensions have been defined }; +/** + * Holds and invokes a deferred operation. + * + * Deferred operations are added by as required by future extensions that require them, + * and are implemented by each of those extensions as a function pointer added to + * MVKDeferredOperationFunctionPointer, plus a corresponding type identifier added + * to MVKDeferredOperationFunctionType. + */ class MVKDeferredOperation : public MVKVulkanAPIDeviceObject { public: - /** Returns the Vulkan type of this object. */ VkObjectType getVkObjectType() override { return VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR; } - /** Returns the debug report object type of this object. */ VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; } /** Begins executing the deferred operation on the current thread. */ VkResult join(); - - /** Gets the max number of threads that can execute the deferred operation concurrently*/ - uint32_t getMaxConcurrency() { - std::lock_guard lock(_maxConcurrencyLock); - return _maxConcurrency; - } - - /** Gets the result of the execution of the deferred operation */ - VkResult getResult() { - std::lock_guard lock(_resultLock); - return _operationResult; - } - - static const int kMVKMaxDeferredFunctionParameters = 3; - - /** Sets all the variables needed for a deferred operation, however should never be called manually and only from other functions that take deferred operations*/ - void deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, void* parameters[kMVKMaxDeferredFunctionParameters]); + + /** Gets the result of the execution of the deferred operation */ + VkResult getOperationResult(); + + /** + * Sets the result of the execution of the deferred operation. + * Called from the function that is implementing the deferred operation. + */ + void setOperationResult(VkResult opResult); + + /** Gets the max number of threads that can execute the deferred operation concurrently. */ + uint32_t getMaxConcurrency(); + + /** + * Sets the max number of threads that can execute the deferred operation concurrently. + * Called from the function that is implementing the deferred operation. + */ + void setMaxConcurrency(uint32_t maxConCurr); + + /** + * Sets the result of the execution of the deferred operation, and updates the max concurrently. + * Equivalent to calling setOperationResult() and setMaxConcurrency(), but with a single concurrency mutex lock. + * Called from the function that is implementing the deferred operation. + */ + void updateResults(VkResult opResult, uint32_t maxConCurr); + + /** + * Sets all the variables needed for a deferred operation. + * Called from the code that implements a deferred operation. + */ + void deferOperation(const MVKDeferredOperationFunctionPointer& pointer, + MVKDeferredOperationFunctionType type, + void** parameters, + uint32_t paramCount); + #pragma mark Construction MVKDeferredOperation(MVKDevice* device) : MVKVulkanAPIDeviceObject(device) {} + protected: - /** Stores the result of the operation*/ - VkResult _operationResult = VK_SUCCESS; - /** The mutex for the operation result being used to ensure thread safety. */ - std::mutex _resultLock; - - /** Stores a pointer to the function*/ - MVKDeferredOperationFunctionPointer _functionPointer; - - /** Stores what functions is being deferred*/ - MVKDeferredOperationFunctionType _functionType; - - /** The parameters in the operation being deferred*/ - void* _functionParameters[kMVKMaxDeferredFunctionParameters] = {}; - - /** Stores the max amount of threads that should be used.. */ + void propagateDebugName() override {} + + std::mutex _lock; + MVKSmallVector _functionParameters; + MVKDeferredOperationFunctionPointer _functionPointer = {}; + MVKDeferredOperationFunctionType _functionType; + VkResult _operationResult = VK_SUCCESS; uint32_t _maxConcurrency = 0; - /** The mutex for the max concurrency being used to ensure thread safety. */ - std::mutex _maxConcurrencyLock; - - void propagateDebugName() override {} + }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index 9ad3456aa..efde21cb9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -623,35 +623,54 @@ VkResult mvkWaitSemaphores(MVKDevice* device, #pragma mark - #pragma mark MVKDeferredOperation +// Call appropriate function from MVKDeferredOperationFunctionPointer with parameters. +// While executing, the function can call setOperationResult() and setMaxConcurrency() +// to update status of the operation, and should return a VkResult that is returned here. VkResult MVKDeferredOperation::join() { - VkResult opResult; - switch(_functionType) - { - // Set operation result here by calling operation - default: return VK_THREAD_DONE_KHR; + switch(_functionType) { + // ..... + default: return VK_SUCCESS; }; - - _resultLock.lock(); - _operationResult = opResult; - _resultLock.unlock(); - - _maxConcurrencyLock.lock(); - _maxConcurrency = 0; - _maxConcurrencyLock.unlock(); - - return VK_SUCCESS; -} - -void MVKDeferredOperation::deferOperation(MVKDeferredOperationFunctionPointer pointer, MVKDeferredOperationFunctionType type, void* parameters[kMVKMaxDeferredFunctionParameters]) -{ +} + +void MVKDeferredOperation::deferOperation(const MVKDeferredOperationFunctionPointer& pointer, + MVKDeferredOperationFunctionType type, + void** parameters, + uint32_t paramCount) { _functionPointer = pointer; _functionType = type; - - for(int i = 0; i < kMVKMaxDeferredFunctionParameters; i++) { - _functionParameters[i] = parameters[i]; + + _functionParameters.reserve(paramCount); + for(int i = 0; i < paramCount; i++) { + _functionParameters.push_back(parameters[i]); } - - _maxConcurrencyLock.lock(); - _maxConcurrency = mvkGetAvaliableCPUCores(); - _maxConcurrencyLock.unlock(); + + updateResults(VK_SUCCESS, mvkGetAvaliableCPUCores()); +} + +VkResult MVKDeferredOperation::getOperationResult() { + lock_guard lock(_lock); + return _operationResult; +} + +void MVKDeferredOperation::setOperationResult(VkResult opResult) { + lock_guard lock(_lock); + _operationResult = opResult; } + +uint32_t MVKDeferredOperation::getMaxConcurrency() { + lock_guard lock(_lock); + return _maxConcurrency; +} + +void MVKDeferredOperation::setMaxConcurrency(uint32_t maxConCurr) { + lock_guard lock(_lock); + _maxConcurrency = maxConCurr; +} + +void MVKDeferredOperation::updateResults(VkResult opResult, uint32_t maxConCurr) { + lock_guard lock(_lock); + _operationResult = opResult; + _maxConcurrency = maxConCurr; +} + diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index 27c0166f4..44b0e5f69 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -2676,7 +2676,7 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetDeferredOperationResultKHR( MVKTraceVulkanCallStart(); MVKDeferredOperation* mvkDeferredOperation = (MVKDeferredOperation*)operation; - VkResult rslt = mvkDeferredOperation->getResult(); + VkResult rslt = mvkDeferredOperation->getOperationResult(); MVKTraceVulkanCallEnd(); return rslt; } From 6bca44c612cf99b32f545d91b2d00fbcd1e1e50a Mon Sep 17 00:00:00 2001 From: Antarctic Coder Date: Wed, 5 Jul 2023 09:47:38 -0400 Subject: [PATCH 58/74] Added MSL Version 3.1 for switch case In this commit, I've added support for Xcode 15, and added a case for MSL version 3.1. I added this because I noticed xcode was throwing some warnings about an unhandled switch case. --- Common/MVKCommonEnvironment.h | 4 ++++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/Common/MVKCommonEnvironment.h b/Common/MVKCommonEnvironment.h index c95992236..0e7d49656 100644 --- a/Common/MVKCommonEnvironment.h +++ b/Common/MVKCommonEnvironment.h @@ -88,6 +88,10 @@ extern "C" { #endif /** Building with Xcode versions. iOS version also covers tvOS. */ +#ifndef MVK_XCODE_15 +# define MVK_XCODE_15 ((__MAC_OS_X_VERSION_MAX_ALLOWED >= 140000) || \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 170000)) +#endif #ifndef MVK_XCODE_14_3 # define MVK_XCODE_14_3 ((__MAC_OS_X_VERSION_MAX_ALLOWED >= 130300) || \ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 160400)) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 3723a8f16..6f2759dcf 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2097,6 +2097,11 @@ _metalFeatures.mslVersion = SPIRV_CROSS_NAMESPACE::CompilerMSL::Options::make_msl_version(maj, min); switch (_metalFeatures.mslVersionEnum) { +#if MVK_XCODE_15 + case MTLLanguageVersion3_1: + setMSLVersion(3, 1); + break; +#endif #if MVK_XCODE_14 case MTLLanguageVersion3_0: setMSLVersion(3, 0); From 056dec80e625a0d9461f437264f6272ffde1fe34 Mon Sep 17 00:00:00 2001 From: Antarctic Coder Date: Wed, 5 Jul 2023 13:20:59 -0400 Subject: [PATCH 59/74] Completed the support for MSL 3.1 enum This commit adds some extra code that was needed to define to MSL 3.1 enum that was not included in the first commit. Based on PR: #1940 --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 16 ++++++++++++++++ .../MoltenVKShaderConverterTool/OSSupport.mm | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 6f2759dcf..df3f6844f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1780,6 +1780,12 @@ } #endif +#if MVK_XCODE_15 + if ( mvkOSVersionIsAtLeast(17.0) ) { + _metalFeatures.mslVersionEnum = MTLLanguageVersion3_1; + } +#endif + #endif #if MVK_IOS @@ -1897,6 +1903,11 @@ _metalFeatures.mslVersionEnum = MTLLanguageVersion3_0; } #endif +#if MVK_XCODE_15 + if ( mvkOSVersionIsAtLeast(17.0) ) { + _metalFeatures.mslVersionEnum = MTLLanguageVersion3_1; + } +#endif #endif @@ -1982,6 +1993,11 @@ _metalFeatures.mslVersionEnum = MTLLanguageVersion3_0; } #endif +#if MVK_XCODE_15 + if ( mvkOSVersionIsAtLeast(14.0) ) { + _metalFeatures.mslVersionEnum = MTLLanguageVersion3_1; + } +#endif // This is an Apple GPU--treat it accordingly. if (supportsMTLGPUFamily(Apple1)) { diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverterTool/OSSupport.mm b/MoltenVKShaderConverter/MoltenVKShaderConverterTool/OSSupport.mm index 965d6cb03..fda97f5f5 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverterTool/OSSupport.mm +++ b/MoltenVKShaderConverter/MoltenVKShaderConverterTool/OSSupport.mm @@ -71,6 +71,11 @@ #define mslVer(MJ, MN, PT) mslVersionMajor == MJ && mslVersionMinor == MN && mslVersionPoint == PT MTLLanguageVersion mslVerEnum = (MTLLanguageVersion)0; +#if MVK_XCODE_15 + if (mslVer(3, 1, 0)) { + mslVerEnum = MTLLanguageVersion3_1; + } else +#endif #if MVK_XCODE_14 if (mslVer(3, 0, 0)) { mslVerEnum = MTLLanguageVersion3_0; From 21ac7443b0d9a6e11877c81c03885abf73bf8bd9 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Fri, 7 Jul 2023 00:41:31 -0700 Subject: [PATCH 60/74] MVKDevice: Don't enable sample LoD depth array workaround for macOS Sonoma and up. Apple have indicated to me that they have fixed the bug. I've confirmed this. --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index df3f6844f..b2417f3f0 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1693,7 +1693,9 @@ break; case kAppleVendorId: // TODO: Other GPUs? - _metalFeatures.needsSampleDrefLodArrayWorkaround = true; + if (!mvkOSVersionIsAtLeast(14.0, 17.0)) { + _metalFeatures.needsSampleDrefLodArrayWorkaround = true; + } // fallthrough case kIntelVendorId: case kNVVendorId: From 3914b0f07db361228631e7b15e9c0e385f6be020 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Mon, 10 Jul 2023 00:54:17 -0700 Subject: [PATCH 61/74] Support the `VK_KHR_incremental_present` extension. This extension allows apps to provide a hint to the presentation engine indicating which parts of the surface need updating. To provide this hint, we call `-[CALayer setNeedsDisplayInRect:]`, which indicates that only the given rectangle needs updating. I'm not sure if this will have any effect, especially if `CAMetalLayer.presentsWithTransaction` is `NO`. Luckily for us, this is only a hint, and it is permissible for the presentation engine to do nothing with the hint. The tests don't work because they apparently can't handle `VK_SUBOPTIMAL_KHR` being returned. --- MoltenVK/MoltenVK/API/mvk_datatypes.h | 6 +++++ MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm | 9 ++++++++ MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h | 3 +++ MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 24 ++++++++++++++++++++ MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 13 +++++++---- 6 files changed, 52 insertions(+), 4 deletions(-) diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h index f5c103b49..b0e2dac7c 100644 --- a/MoltenVK/MoltenVK/API/mvk_datatypes.h +++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h @@ -434,6 +434,12 @@ VkExtent2D mvkVkExtent2DFromCGSize(CGSize cgSize); /** Returns a CGSize that corresponds to the specified VkExtent2D. */ CGSize mvkCGSizeFromVkExtent2D(VkExtent2D vkExtent); +/** Returns a CGPoint that corresponds to the specified VkOffset2D. */ +CGPoint mvkCGPointFromVkOffset2D(VkOffset2D vkOffset); + +/** Returns a CGRect that corresponds to the specified VkRectLayerKHR. The layer is ignored. */ +CGRect mvkCGRectFromVkRectLayerKHR(VkRectLayerKHR vkRect); + /** Returns a Metal MTLOrigin constructed from a VkOffset3D. */ static inline MTLOrigin mvkMTLOriginFromVkOffset3D(VkOffset3D vkOffset) { return MTLOriginMake(vkOffset.x, vkOffset.y, vkOffset.z); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index c60cb011c..96b34cc3b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -583,8 +583,12 @@ const VkPresentTimesInfoGOOGLE* pPresentTimesInfo = nullptr; const VkSwapchainPresentFenceInfoEXT* pPresentFenceInfo = nullptr; const VkSwapchainPresentModeInfoEXT* pPresentModeInfo = nullptr; + const VkPresentRegionsKHR* pPresentRegions = nullptr; for (auto* next = (const VkBaseInStructure*)pPresentInfo->pNext; next; next = next->pNext) { switch (next->sType) { + case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR: + pPresentRegions = (const VkPresentRegionsKHR*) next; + break; case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT: pPresentFenceInfo = (const VkSwapchainPresentFenceInfoEXT*) next; break; @@ -616,6 +620,10 @@ pFences = pPresentFenceInfo->pFences; MVKAssert(pPresentFenceInfo->swapchainCount == scCnt, "VkSwapchainPresentFenceInfoEXT swapchainCount must match VkPresentInfo swapchainCount."); } + const VkPresentRegionKHR* pRegions = nullptr; + if (pPresentRegions) { + pRegions = pPresentRegions->pRegions; + } VkResult* pSCRslts = pPresentInfo->pResults; _presentInfo.reserve(scCnt); @@ -630,6 +638,7 @@ presentInfo.presentID = pPresentTimes[scIdx].presentID; presentInfo.desiredPresentTime = pPresentTimes[scIdx].desiredPresentTime; } + mvkSC->setLayerNeedsDisplay(pRegions ? &pRegions[scIdx] : nullptr); _presentInfo.push_back(presentInfo); VkResult scRslt = mvkSC->getSurfaceStatus(); if (pSCRslts) { pSCRslts[scIdx] = scRslt; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h index 95bcb1377..523a58072 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h @@ -99,6 +99,9 @@ class MVKSwapchain : public MVKVulkanAPIDeviceObject { /** VK_GOOGLE_display_timing - returns past presentation times */ VkResult getPastPresentationTiming(uint32_t *pCount, VkPastPresentationTimingGOOGLE *pPresentationTimings); + /** Marks parts of the underlying CAMetalLayer as needing update. */ + void setLayerNeedsDisplay(const VkPresentRegionKHR* pRegion); + void destroy() override; #pragma mark Construction diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index c52896d05..8be023fb6 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -582,6 +582,30 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin _presentHistoryIndex = (_presentHistoryIndex + 1) % kMaxPresentationHistory; } +void MVKSwapchain::setLayerNeedsDisplay(const VkPresentRegionKHR* pRegion) { + if (!pRegion || pRegion->rectangleCount == 0) { + [_mtlLayer setNeedsDisplay]; + return; + } + + for (uint32_t i = 0; i < pRegion->rectangleCount; ++i) { + CGRect cgRect = mvkCGRectFromVkRectLayerKHR(pRegion->pRectangles[i]); +#if MVK_MACOS + // VK_KHR_incremental_present specifies an upper-left origin, but macOS by default + // uses a lower-left origin. + cgRect.origin.y = _mtlLayer.bounds.size.height - cgRect.origin.y; +#endif + // We were given rectangles in pixels, but -[CALayer setNeedsDisplayInRect:] wants them + // in points, which is pixels / contentsScale. + CGFloat scaleFactor = _mtlLayer.contentsScale; + cgRect.origin.x /= scaleFactor; + cgRect.origin.y /= scaleFactor; + cgRect.size.width /= scaleFactor; + cgRect.size.height /= scaleFactor; + [_mtlLayer setNeedsDisplayInRect:cgRect]; + } +} + // A retention loop exists between the swapchain and its images. The swapchain images // retain the swapchain because they can be in flight when the app destroys the swapchain. // Release the images now, when the app destroys the swapchain, so they will be destroyed when diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 4c6fe6f54..99e709a01 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -68,6 +68,7 @@ MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PR MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE, 10.11, 8.0) MVK_EXTENSION(KHR_imageless_framebuffer, KHR_IMAGELESS_FRAMEBUFFER, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_incremental_present, KHR_INCREMENTAL_PRESENT, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE, 10.11, 8.0) diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index 23c567ccb..caa776237 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -780,10 +780,15 @@ MVK_PUBLIC_SYMBOL VkExtent2D mvkVkExtent2DFromCGSize(CGSize cgSize) { } MVK_PUBLIC_SYMBOL CGSize mvkCGSizeFromVkExtent2D(VkExtent2D vkExtent) { - CGSize cgSize; - cgSize.width = vkExtent.width; - cgSize.height = vkExtent.height; - return cgSize; + return CGSizeMake(vkExtent.width, vkExtent.height); +} + +MVK_PUBLIC_SYMBOL CGPoint mvkCGPointFromVkOffset2D(VkOffset2D vkOffset) { + return CGPointMake(vkOffset.x, vkOffset.y); +} + +MVK_PUBLIC_SYMBOL CGRect mvkCGRectFromVkRectLayerKHR(VkRectLayerKHR vkRect) { + return { mvkCGPointFromVkOffset2D(vkRect.offset), mvkCGSizeFromVkExtent2D(vkRect.extent) }; } From 561e14ba6297810ffd7ef26dbe4d7a453632dfa1 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Fri, 7 Jul 2023 00:25:37 -0700 Subject: [PATCH 62/74] Support the `VK_EXT_pipeline_creation_feedback` extension. This provides feedback that indicates: * how long it took to compile each shader stage and the pipeline as a whole; * whether or not the pipeline or any shader stage were found in any supplied pipeline cache; and * whether or not any supplied base pipeline were used to accelerate pipeline creation. This is similar to the performance statistics that MoltenVK already collects. Since we don't use any supplied base pipeline at all, this implementation never sets `VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT`. However, I've identified several places where we could probably use the base pipeline to accelerate pipeline creation. One day, I should probably implement that. Likewise, because we don't yet support using `MTLBinaryArchive`s, `VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT` is never set on the whole pipeline, though it *is* set for individual stages, on the assumption that any shader found in a cache is likely to be found in Metal's own implicit cache. In this implementation, shader stage compilation time includes any time needed to build the `MTLComputePipelineState`s needed for vertex and tessellation control shaders in tessellated pipelines. This patch also changes compilation of the vertex stage `MTLComputePipelineState`s in tessellated pipelines to be eager instead of lazy. We really ought to have been doing this anyway, in order to report pipeline failures at creation time instead of draw time. I'm not happy, though, that we now pay the cost of all three pipeline states all the time, instead of just the ones that are used. This also gets rid of some fields of `MVKGraphicsPipeline` that were only used during pipeline construction, which should save some memory, particularly for apps that create lots of pipelines. --- Common/MVKOSExtensions.h | 8 + Common/MVKOSExtensions.mm | 8 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 43 +-- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 359 +++++++++++++----- .../MoltenVK/GPUObjects/MVKShaderModule.h | 14 +- .../MoltenVK/GPUObjects/MVKShaderModule.mm | 41 +- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + 7 files changed, 334 insertions(+), 140 deletions(-) diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h index ff96991c9..576eb4032 100644 --- a/Common/MVKOSExtensions.h +++ b/Common/MVKOSExtensions.h @@ -76,6 +76,14 @@ uint64_t mvkGetTimestamp(); /** Returns the number of nanoseconds between each increment of the value returned by mvkGetTimestamp(). */ double mvkGetTimestampPeriod(); +/** + * Returns the number of nanoseconds elapsed between startTimestamp and endTimestamp, + * each of which should be a value returned by mvkGetTimestamp(). + * If endTimestamp is zero or not supplied, it is taken to be the current time. + * If startTimestamp is zero or not supplied, it is taken to be the time the app was initialized. + */ +uint64_t mvkGetElapsedNanoseconds(uint64_t startTimestamp = 0, uint64_t endTimestamp = 0); + /** * Returns the number of milliseconds elapsed between startTimestamp and endTimestamp, * each of which should be a value returned by mvkGetTimestamp(). diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 672335d79..0f9643e1d 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -46,9 +46,13 @@ MVKOSVersion mvkOSVersion() { double mvkGetTimestampPeriod() { return _mvkTimestampPeriod; } -double mvkGetElapsedMilliseconds(uint64_t startTimestamp, uint64_t endTimestamp) { +uint64_t mvkGetElapsedNanoseconds(uint64_t startTimestamp, uint64_t endTimestamp) { if (endTimestamp == 0) { endTimestamp = mvkGetTimestamp(); } - return (double)(endTimestamp - startTimestamp) * _mvkTimestampPeriod / 1e6; + return (endTimestamp - startTimestamp) * _mvkTimestampPeriod; +} + +double mvkGetElapsedMilliseconds(uint64_t startTimestamp, uint64_t endTimestamp) { + return mvkGetElapsedNanoseconds(startTimestamp, endTimestamp) / 1e6; } uint64_t mvkGetAbsoluteTime() { return mach_continuous_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index e81f93df3..825ae6b89 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -233,7 +233,7 @@ class MVKGraphicsPipeline : public MVKPipeline { bool supportsDynamicState(VkDynamicState state); /** Returns whether this pipeline has tessellation shaders. */ - bool isTessellationPipeline() { return _pTessCtlSS && _pTessEvalSS && _tessInfo.patchControlPoints > 0; } + bool isTessellationPipeline() { return _tessInfo.patchControlPoints > 0; } /** Returns the number of input tessellation patch control points. */ uint32_t getInputControlPointCount() { return _tessInfo.patchControlPoints; } @@ -251,13 +251,13 @@ class MVKGraphicsPipeline : public MVKPipeline { uint32_t getTessCtlLevelBufferIndex() { return _tessCtlLevelBufferIndex; } /** Returns the MTLComputePipelineState object for the vertex stage of a tessellated draw with no indices. */ - id getTessVertexStageState(); + id getTessVertexStageState() { return _mtlTessVertexStageState; } /** Returns the MTLComputePipelineState object for the vertex stage of a tessellated draw with 16-bit indices. */ - id getTessVertexStageIndex16State(); + id getTessVertexStageIndex16State() { return _mtlTessVertexStageIndex16State; } /** Returns the MTLComputePipelineState object for the vertex stage of a tessellated draw with 32-bit indices. */ - id getTessVertexStageIndex32State(); + id getTessVertexStageIndex32State() { return _mtlTessVertexStageIndex32State; } /** Returns the MTLComputePipelineState object for the tessellation control stage of a tessellated draw. */ id getTessControlStageState() { return _mtlTessControlStageState; } @@ -318,22 +318,24 @@ class MVKGraphicsPipeline : public MVKPipeline { id getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id& plState); id getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id& plState, const char* compilerType); + bool compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, id* vtxFunctions, VkPipelineCreationFeedback* pVertexFB); + bool compileTessControlStageState(MTLComputePipelineDescriptor* tcPLDesc, VkPipelineCreationFeedback* pTessCtlFB); void initCustomSamplePositions(const VkGraphicsPipelineCreateInfo* pCreateInfo); - void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData); + void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, VkPipelineCreationFeedback* pPipelineFB, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); void initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData); void initReservedVertexAttributeBufferCount(const VkGraphicsPipelineCreateInfo* pCreateInfo); void addVertexInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo); void addNextStageInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& inputs); void addPrevStageOutputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& outputs); - MTLRenderPipelineDescriptor* newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData); - MTLComputePipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig); - MTLComputePipelineDescriptor* newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig); - MTLRenderPipelineDescriptor* newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig); - bool addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig); - bool addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& nextInputs); - bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, SPIRVShaderInputs& nextInputs); - bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput); - bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput); + MTLRenderPipelineDescriptor* newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); + MTLComputePipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, id* vtxFunctions); + MTLComputePipelineDescriptor* newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pVertexSS, const VkPipelineShaderStageCreateInfo* pTessEvalSS); + MTLRenderPipelineDescriptor* newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS); + bool addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo*& pFragmentSS); + bool addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& nextInputs, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, id* vtxFunctions); + bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, SPIRVShaderInputs& nextInputs, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB); + bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo*& pFragmentSS); + bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); template bool addVertexInputToPipeline(T* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, const SPIRVToMSLConversionConfiguration& shaderConfig); void adjustVertexInputForMultiview(MTLVertexDescriptor* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, uint32_t viewCount, uint32_t oldViewCount = 1); @@ -346,6 +348,7 @@ class MVKGraphicsPipeline : public MVKPipeline { uint32_t getImplicitBufferIndex(MVKShaderStage stage, uint32_t bufferIndexOffset); MVKMTLFunction getMTLFunction(SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pShaderStage, + VkPipelineCreationFeedback* pStageFB, const char* pStageName); void markIfUsingPhysicalStorageBufferAddressesCapability(SPIRVToMSLConversionResultInfo& resultsInfo, MVKShaderStage stage); @@ -365,13 +368,6 @@ class MVKGraphicsPipeline : public MVKPipeline { MVKSmallVector _stagesUsingPhysicalStorageBufferAddressesCapability; std::unordered_map> _multiviewMTLPipelineStates; - const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pTessEvalSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pFragmentSS = nullptr; - MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil; - id _mtlTessVertexFunctions[3] = {nil, nil, nil}; - id _mtlTessVertexStageState = nil; id _mtlTessVertexStageIndex16State = nil; id _mtlTessVertexStageIndex32State = nil; @@ -446,7 +442,8 @@ class MVKComputePipeline : public MVKPipeline { ~MVKComputePipeline() override; protected: - MVKMTLFunction getMTLFunction(const VkComputePipelineCreateInfo* pCreateInfo); + MVKMTLFunction getMTLFunction(const VkComputePipelineCreateInfo* pCreateInfo, + VkPipelineCreationFeedback* pStageFB); uint32_t getImplicitBufferIndex(uint32_t bufferIndexOffset); id _mtlPipelineState; @@ -490,6 +487,7 @@ class MVKPipelineCache : public MVKVulkanAPIDeviceObject { MVKShaderLibrary* getShaderLibrary(SPIRVToMSLConversionConfiguration* pContext, MVKShaderModule* shaderModule, MVKPipeline* pipeline, + VkPipelineCreationFeedback* pShaderFeedback = nullptr, uint64_t startTime = 0); /** Merges the contents of the specified number of pipeline caches into this cache. */ @@ -510,6 +508,7 @@ class MVKPipelineCache : public MVKVulkanAPIDeviceObject { MVKShaderLibrary* getShaderLibraryImpl(SPIRVToMSLConversionConfiguration* pContext, MVKShaderModule* shaderModule, MVKPipeline* pipeline, + VkPipelineCreationFeedback* pShaderFeedback, uint64_t startTime); VkResult writeDataImpl(size_t* pDataSize, void* pData); VkResult mergePipelineCachesImpl(uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index a9fc1ec10..75ebe8720 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -337,42 +337,54 @@ static const char vtxCompilerType[] = "Vertex stage pipeline for tessellation"; -id MVKGraphicsPipeline::getTessVertexStageState() { - MTLComputePipelineDescriptor* plDesc = [_mtlTessVertexStageDesc copy]; // temp retain a copy to be thread-safe. - plDesc.computeFunction = _mtlTessVertexFunctions[0]; - id plState = getOrCompilePipeline(plDesc, _mtlTessVertexStageState, vtxCompilerType); - [plDesc release]; // temp release - return plState; -} - -id MVKGraphicsPipeline::getTessVertexStageIndex16State() { - MTLComputePipelineDescriptor* plDesc = [_mtlTessVertexStageDesc copy]; // temp retain a copy to be thread-safe. - plDesc.computeFunction = _mtlTessVertexFunctions[1]; - plDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt16; +bool MVKGraphicsPipeline::compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, + id* vtxFunctions, + VkPipelineCreationFeedback* pVertexFB) { + uint64_t startTime = 0; + if (pVertexFB) { + startTime = mvkGetTimestamp(); + } + vtxPLDesc.computeFunction = vtxFunctions[0]; + bool res = !!getOrCompilePipeline(vtxPLDesc, _mtlTessVertexStageState, vtxCompilerType); + + vtxPLDesc.computeFunction = vtxFunctions[1]; + vtxPLDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt16; for (uint32_t i = 0; i < 31; i++) { - MTLBufferLayoutDescriptor* blDesc = plDesc.stageInputDescriptor.layouts[i]; + MTLBufferLayoutDescriptor* blDesc = vtxPLDesc.stageInputDescriptor.layouts[i]; if (blDesc.stepFunction == MTLStepFunctionThreadPositionInGridX) { blDesc.stepFunction = MTLStepFunctionThreadPositionInGridXIndexed; } } - id plState = getOrCompilePipeline(plDesc, _mtlTessVertexStageIndex16State, vtxCompilerType); - [plDesc release]; // temp release - return plState; + res |= !!getOrCompilePipeline(vtxPLDesc, _mtlTessVertexStageIndex16State, vtxCompilerType); + + vtxPLDesc.computeFunction = vtxFunctions[2]; + vtxPLDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt32; + res |= !!getOrCompilePipeline(vtxPLDesc, _mtlTessVertexStageIndex32State, vtxCompilerType); + + if (pVertexFB) { + if (!res) { + // Compilation of the shader will have enabled the flag, so I need to turn it off. + mvkDisableFlags(pVertexFB->flags, VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT); + } + pVertexFB->duration += mvkGetElapsedNanoseconds(startTime); + } + return res; } -id MVKGraphicsPipeline::getTessVertexStageIndex32State() { - MTLComputePipelineDescriptor* plDesc = [_mtlTessVertexStageDesc copy]; // temp retain a copy to be thread-safe. - plDesc.computeFunction = _mtlTessVertexFunctions[2]; - plDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt32; - for (uint32_t i = 0; i < 31; i++) { - MTLBufferLayoutDescriptor* blDesc = plDesc.stageInputDescriptor.layouts[i]; - if (blDesc.stepFunction == MTLStepFunctionThreadPositionInGridX) { - blDesc.stepFunction = MTLStepFunctionThreadPositionInGridXIndexed; - } - } - id plState = getOrCompilePipeline(plDesc, _mtlTessVertexStageIndex32State, vtxCompilerType); - [plDesc release]; // temp release - return plState; +bool MVKGraphicsPipeline::compileTessControlStageState(MTLComputePipelineDescriptor* tcPLDesc, + VkPipelineCreationFeedback* pTessCtlFB) { + uint64_t startTime = 0; + if (pTessCtlFB) { + startTime = mvkGetTimestamp(); + } + bool res = !!getOrCompilePipeline(tcPLDesc, _mtlTessControlStageState, "Tessellation control"); + if (pTessCtlFB) { + if (!res) { + mvkDisableFlags(pTessCtlFB->flags, VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT); + } + pTessCtlFB->duration += mvkGetElapsedNanoseconds(startTime); + } + return res; } @@ -407,26 +419,78 @@ _isRasterizing = !isRasterizationDisabled(pCreateInfo); _isRasterizingColor = _isRasterizing && mvkHasColorAttachments(pRendInfo); - // Get the tessellation shaders, if present. Do this now, because we need to extract + const VkPipelineCreationFeedbackCreateInfo* pFeedbackInfo = nullptr; + for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { + switch (next->sType) { + case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: + pFeedbackInfo = (VkPipelineCreationFeedbackCreateInfo*)next; + break; + default: + break; + } + } + + // Initialize feedback. The VALID bit must be initialized, either set or cleared. + // We'll set the VALID bits later, after successful compilation. + VkPipelineCreationFeedback* pPipelineFB = nullptr; + if (pFeedbackInfo) { + pPipelineFB = pFeedbackInfo->pPipelineCreationFeedback; + // n.b. Do *NOT* use mvkClear(). That would also clear the sType and pNext fields. + pPipelineFB->flags = 0; + pPipelineFB->duration = 0; + for (uint32_t i = 0; i < pFeedbackInfo->pipelineStageCreationFeedbackCount; ++i) { + pFeedbackInfo->pPipelineStageCreationFeedbacks[i].flags = 0; + pFeedbackInfo->pPipelineStageCreationFeedbacks[i].duration = 0; + } + } + + // Get the shader stages. Do this now, because we need to extract // reflection data from them that informs everything else. + const VkPipelineShaderStageCreateInfo* pVertexSS = nullptr; + const VkPipelineShaderStageCreateInfo* pTessCtlSS = nullptr; + const VkPipelineShaderStageCreateInfo* pTessEvalSS = nullptr; + const VkPipelineShaderStageCreateInfo* pFragmentSS = nullptr; + VkPipelineCreationFeedback* pVertexFB = nullptr; + VkPipelineCreationFeedback* pTessCtlFB = nullptr; + VkPipelineCreationFeedback* pTessEvalFB = nullptr; + VkPipelineCreationFeedback* pFragmentFB = nullptr; for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { const auto* pSS = &pCreateInfo->pStages[i]; - if (pSS->stage == VK_SHADER_STAGE_VERTEX_BIT) { - _pVertexSS = pSS; - } else if (pSS->stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) { - _pTessCtlSS = pSS; - } else if (pSS->stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) { - _pTessEvalSS = pSS; - } else if (pSS->stage == VK_SHADER_STAGE_FRAGMENT_BIT) { - _pFragmentSS = pSS; + switch (pSS->stage) { + case VK_SHADER_STAGE_VERTEX_BIT: + pVertexSS = pSS; + if (pFeedbackInfo && pFeedbackInfo->pPipelineStageCreationFeedbacks) { + pVertexFB = &pFeedbackInfo->pPipelineStageCreationFeedbacks[i]; + } + break; + case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: + pTessCtlSS = pSS; + if (pFeedbackInfo && pFeedbackInfo->pPipelineStageCreationFeedbacks) { + pTessCtlFB = &pFeedbackInfo->pPipelineStageCreationFeedbacks[i]; + } + break; + case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: + pTessEvalSS = pSS; + if (pFeedbackInfo && pFeedbackInfo->pPipelineStageCreationFeedbacks) { + pTessEvalFB = &pFeedbackInfo->pPipelineStageCreationFeedbacks[i]; + } + break; + case VK_SHADER_STAGE_FRAGMENT_BIT: + pFragmentSS = pSS; + if (pFeedbackInfo && pFeedbackInfo->pPipelineStageCreationFeedbacks) { + pFragmentFB = &pFeedbackInfo->pPipelineStageCreationFeedbacks[i]; + } + break; + default: + break; } } // Get the tessellation parameters from the shaders. SPIRVTessReflectionData reflectData; std::string reflectErrorLog; - if (_pTessCtlSS && _pTessEvalSS) { - if (!getTessReflectionData(((MVKShaderModule*)_pTessCtlSS->module)->getSPIRV(), _pTessCtlSS->pName, ((MVKShaderModule*)_pTessEvalSS->module)->getSPIRV(), _pTessEvalSS->pName, reflectData, reflectErrorLog) ) { + if (pTessCtlSS && pTessEvalSS) { + if (!getTessReflectionData(((MVKShaderModule*)pTessCtlSS->module)->getSPIRV(), pTessCtlSS->pName, ((MVKShaderModule*)pTessEvalSS->module)->getSPIRV(), pTessEvalSS->pName, reflectData, reflectErrorLog) ) { setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to reflect tessellation shaders: %s", reflectErrorLog.c_str())); return; } @@ -439,10 +503,10 @@ // Tessellation - must ignore allowed bad pTessellationState pointer if not tess pipeline _outputControlPointCount = reflectData.numControlPoints; - mvkSetOrClear(&_tessInfo, (_pTessCtlSS && _pTessEvalSS) ? pCreateInfo->pTessellationState : nullptr); + mvkSetOrClear(&_tessInfo, (pTessCtlSS && pTessEvalSS) ? pCreateInfo->pTessellationState : nullptr); // Render pipeline state. Do this as early as possible, to fail fast if pipeline requires a fail on cache-miss. - initMTLRenderPipelineState(pCreateInfo, reflectData); + initMTLRenderPipelineState(pCreateInfo, reflectData, pPipelineFB, pVertexSS, pVertexFB, pTessCtlSS, pTessCtlFB, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB); if ( !_hasValidMTLPipelineStates ) { return; } // Track dynamic state @@ -564,20 +628,33 @@ } // Constructs the underlying Metal render pipeline. -void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData) { +void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, + const SPIRVTessReflectionData& reflectData, + VkPipelineCreationFeedback* pPipelineFB, + const VkPipelineShaderStageCreateInfo* pVertexSS, + VkPipelineCreationFeedback* pVertexFB, + const VkPipelineShaderStageCreateInfo* pTessCtlSS, + VkPipelineCreationFeedback* pTessCtlFB, + const VkPipelineShaderStageCreateInfo* pTessEvalSS, + VkPipelineCreationFeedback* pTessEvalFB, + const VkPipelineShaderStageCreateInfo* pFragmentSS, + VkPipelineCreationFeedback* pFragmentFB) { _mtlTessVertexStageState = nil; _mtlTessVertexStageIndex16State = nil; _mtlTessVertexStageIndex32State = nil; _mtlTessControlStageState = nil; _mtlPipelineState = nil; - _mtlTessVertexStageDesc = nil; - for (uint32_t i = 0; i < 3; i++) { _mtlTessVertexFunctions[i] = nil; } + + uint64_t pipelineStart = 0; + if (pPipelineFB) { + pipelineStart = mvkGetTimestamp(); + } if (isUsingMetalArgumentBuffers()) { _descriptorBindingUse.resize(_descriptorSetCount); } if (isUsingPipelineStageMetalArgumentBuffers()) { _mtlArgumentEncoders.resize(_descriptorSetCount); } if (!isTessellationPipeline()) { - MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData); // temp retain + MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData, pVertexSS, pVertexFB, pFragmentSS, pFragmentFB); // temp retain if (plDesc) { const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); if (pRendInfo && mvkIsMultiview(pRendInfo->viewMask)) { @@ -613,30 +690,45 @@ } } else { // In this case, we need to create three render pipelines. But, the way Metal handles - // index buffers for compute stage-in means we have to defer creation of stage 1 until - // draw time. In the meantime, we'll create and retain a descriptor for it. + // index buffers for compute stage-in means we have to create three pipelines for + // stage 1 (five pipelines in total). SPIRVToMSLConversionConfiguration shaderConfig; initShaderConversionConfig(shaderConfig, pCreateInfo, reflectData); - _mtlTessVertexStageDesc = newMTLTessVertexStageDescriptor(pCreateInfo, reflectData, shaderConfig); // retained - MTLComputePipelineDescriptor* tcPLDesc = newMTLTessControlStageDescriptor(pCreateInfo, reflectData, shaderConfig); // temp retained - MTLRenderPipelineDescriptor* rastPLDesc = newMTLTessRasterStageDescriptor(pCreateInfo, reflectData, shaderConfig); // temp retained - if (_mtlTessVertexStageDesc && tcPLDesc && rastPLDesc) { - if (getOrCompilePipeline(tcPLDesc, _mtlTessControlStageState, "Tessellation control")) { - getOrCompilePipeline(rastPLDesc, _mtlPipelineState); + id vtxFunctions[3] = { nil }; + MTLComputePipelineDescriptor* vtxPLDesc = newMTLTessVertexStageDescriptor(pCreateInfo, reflectData, shaderConfig, pVertexSS, pVertexFB, pTessCtlSS, vtxFunctions); // temp retained + MTLComputePipelineDescriptor* tcPLDesc = newMTLTessControlStageDescriptor(pCreateInfo, reflectData, shaderConfig, pTessCtlSS, pTessCtlFB, pVertexSS, pTessEvalSS); // temp retained + MTLRenderPipelineDescriptor* rastPLDesc = newMTLTessRasterStageDescriptor(pCreateInfo, reflectData, shaderConfig, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB, pTessCtlSS); // temp retained + if (vtxPLDesc && tcPLDesc && rastPLDesc) { + if (compileTessVertexStageState(vtxPLDesc, vtxFunctions, pVertexFB)) { + if (compileTessControlStageState(tcPLDesc, pTessCtlFB)) { + getOrCompilePipeline(rastPLDesc, _mtlPipelineState); + } } } else { _hasValidMTLPipelineStates = false; } + [vtxPLDesc release]; // temp release [tcPLDesc release]; // temp release [rastPLDesc release]; // temp release } + + if (pPipelineFB) { + if ( _hasValidMTLPipelineStates ) { + mvkEnableFlags(pPipelineFB->flags, VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT); + } + pPipelineFB->duration = mvkGetElapsedNanoseconds(pipelineStart); + } } // Returns a retained MTLRenderPipelineDescriptor constructed from this instance, or nil if an error occurs. // It is the responsibility of the caller to release the returned descriptor. MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, - const SPIRVTessReflectionData& reflectData) { + const SPIRVTessReflectionData& reflectData, + const VkPipelineShaderStageCreateInfo* pVertexSS, + VkPipelineCreationFeedback* pVertexFB, + const VkPipelineShaderStageCreateInfo* pFragmentSS, + VkPipelineCreationFeedback* pFragmentFB) { SPIRVToMSLConversionConfiguration shaderConfig; initShaderConversionConfig(shaderConfig, pCreateInfo, reflectData); @@ -644,20 +736,20 @@ SPIRVShaderOutputs vtxOutputs; std::string errorLog; - if (!getShaderOutputs(((MVKShaderModule*)_pVertexSS->module)->getSPIRV(), spv::ExecutionModelVertex, _pVertexSS->pName, vtxOutputs, errorLog) ) { + if (!getShaderOutputs(((MVKShaderModule*)pVertexSS->module)->getSPIRV(), spv::ExecutionModelVertex, pVertexSS->pName, vtxOutputs, errorLog) ) { setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get vertex outputs: %s", errorLog.c_str())); return nil; } // Add shader stages. Compile vertex shader before others just in case conversion changes anything...like rasterizaion disable. - if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig)) { return nil; } + if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig, pVertexSS, pVertexFB, pFragmentSS)) { return nil; } // Vertex input // This needs to happen before compiling the fragment shader, or we'll lose information on vertex attributes. if (!addVertexInputToPipeline(plDesc.vertexDescriptor, pCreateInfo->pVertexInputState, shaderConfig)) { return nil; } // Fragment shader - only add if rasterization is enabled - if (!addFragmentShaderToPipeline(plDesc, pCreateInfo, shaderConfig, vtxOutputs)) { return nil; } + if (!addFragmentShaderToPipeline(plDesc, pCreateInfo, shaderConfig, vtxOutputs, pFragmentSS, pFragmentFB)) { return nil; } // Output addFragmentOutputToPipeline(plDesc, pCreateInfo); @@ -673,13 +765,17 @@ // Returns a retained MTLComputePipelineDescriptor for the vertex stage of a tessellated draw constructed from this instance, or nil if an error occurs. // It is the responsibility of the caller to release the returned descriptor. MTLComputePipelineDescriptor* MVKGraphicsPipeline::newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, - const SPIRVTessReflectionData& reflectData, - SPIRVToMSLConversionConfiguration& shaderConfig) { + const SPIRVTessReflectionData& reflectData, + SPIRVToMSLConversionConfiguration& shaderConfig, + const VkPipelineShaderStageCreateInfo* pVertexSS, + VkPipelineCreationFeedback* pVertexFB, + const VkPipelineShaderStageCreateInfo* pTessCtlSS, + id* vtxFunctions) { MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new]; // retained SPIRVShaderInputs tcInputs; std::string errorLog; - if (!getShaderInputs(((MVKShaderModule*)_pTessCtlSS->module)->getSPIRV(), spv::ExecutionModelTessellationControl, _pTessCtlSS->pName, tcInputs, errorLog) ) { + if (!getShaderInputs(((MVKShaderModule*)pTessCtlSS->module)->getSPIRV(), spv::ExecutionModelTessellationControl, pTessCtlSS->pName, tcInputs, errorLog) ) { setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation control inputs: %s", errorLog.c_str())); return nil; } @@ -691,7 +787,7 @@ }), tcInputs.end()); // Add shader stages. - if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig, tcInputs)) { return nil; } + if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig, tcInputs, pVertexSS, pVertexFB, vtxFunctions)) { return nil; } // Vertex input plDesc.stageInputDescriptor = [MTLStageInputOutputDescriptor stageInputOutputDescriptor]; @@ -811,17 +907,21 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 // It is the responsibility of the caller to release the returned descriptor. MTLComputePipelineDescriptor* MVKGraphicsPipeline::newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, - SPIRVToMSLConversionConfiguration& shaderConfig) { + SPIRVToMSLConversionConfiguration& shaderConfig, + const VkPipelineShaderStageCreateInfo* pTessCtlSS, + VkPipelineCreationFeedback* pTessCtlFB, + const VkPipelineShaderStageCreateInfo* pVertexSS, + const VkPipelineShaderStageCreateInfo* pTessEvalSS) { MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new]; // retained SPIRVShaderOutputs vtxOutputs; SPIRVShaderInputs teInputs; std::string errorLog; - if (!getShaderOutputs(((MVKShaderModule*)_pVertexSS->module)->getSPIRV(), spv::ExecutionModelVertex, _pVertexSS->pName, vtxOutputs, errorLog) ) { + if (!getShaderOutputs(((MVKShaderModule*)pVertexSS->module)->getSPIRV(), spv::ExecutionModelVertex, pVertexSS->pName, vtxOutputs, errorLog) ) { setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get vertex outputs: %s", errorLog.c_str())); return nil; } - if (!getShaderInputs(((MVKShaderModule*)_pTessEvalSS->module)->getSPIRV(), spv::ExecutionModelTessellationEvaluation, _pTessEvalSS->pName, teInputs, errorLog) ) { + if (!getShaderInputs(((MVKShaderModule*)pTessEvalSS->module)->getSPIRV(), spv::ExecutionModelTessellationEvaluation, pTessEvalSS->pName, teInputs, errorLog) ) { setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation evaluation inputs: %s", errorLog.c_str())); return nil; } @@ -833,7 +933,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 }), teInputs.end()); // Add shader stages. - if (!addTessCtlShaderToPipeline(plDesc, pCreateInfo, shaderConfig, vtxOutputs, teInputs)) { + if (!addTessCtlShaderToPipeline(plDesc, pCreateInfo, shaderConfig, vtxOutputs, teInputs, pTessCtlSS, pTessCtlFB)) { [plDesc release]; return nil; } @@ -850,29 +950,34 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 // It is the responsibility of the caller to release the returned descriptor. MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, - SPIRVToMSLConversionConfiguration& shaderConfig) { + SPIRVToMSLConversionConfiguration& shaderConfig, + const VkPipelineShaderStageCreateInfo* pTessEvalSS, + VkPipelineCreationFeedback* pTessEvalFB, + const VkPipelineShaderStageCreateInfo* pFragmentSS, + VkPipelineCreationFeedback* pFragmentFB, + const VkPipelineShaderStageCreateInfo* pTessCtlSS) { MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // retained SPIRVShaderOutputs tcOutputs, teOutputs; SPIRVShaderInputs teInputs; std::string errorLog; - if (!getShaderOutputs(((MVKShaderModule*)_pTessCtlSS->module)->getSPIRV(), spv::ExecutionModelTessellationControl, _pTessCtlSS->pName, tcOutputs, errorLog) ) { + if (!getShaderOutputs(((MVKShaderModule*)pTessCtlSS->module)->getSPIRV(), spv::ExecutionModelTessellationControl, pTessCtlSS->pName, tcOutputs, errorLog) ) { setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation control outputs: %s", errorLog.c_str())); return nil; } - if (!getShaderOutputs(((MVKShaderModule*)_pTessEvalSS->module)->getSPIRV(), spv::ExecutionModelTessellationEvaluation, _pTessEvalSS->pName, teOutputs, errorLog) ) { + if (!getShaderOutputs(((MVKShaderModule*)pTessEvalSS->module)->getSPIRV(), spv::ExecutionModelTessellationEvaluation, pTessEvalSS->pName, teOutputs, errorLog) ) { setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation evaluation outputs: %s", errorLog.c_str())); return nil; } // Add shader stages. Compile tessellation evaluation shader before others just in case conversion changes anything...like rasterizaion disable. - if (!addTessEvalShaderToPipeline(plDesc, pCreateInfo, shaderConfig, tcOutputs)) { + if (!addTessEvalShaderToPipeline(plDesc, pCreateInfo, shaderConfig, tcOutputs, pTessEvalSS, pTessEvalFB, pFragmentSS)) { [plDesc release]; return nil; } // Fragment shader - only add if rasterization is enabled - if (!addFragmentShaderToPipeline(plDesc, pCreateInfo, shaderConfig, teOutputs)) { + if (!addFragmentShaderToPipeline(plDesc, pCreateInfo, shaderConfig, teOutputs, pFragmentSS, pFragmentFB)) { [plDesc release]; return nil; } @@ -903,9 +1008,12 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 // Adds a vertex shader to the pipeline description. bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, - SPIRVToMSLConversionConfiguration& shaderConfig) { + SPIRVToMSLConversionConfiguration& shaderConfig, + const VkPipelineShaderStageCreateInfo* pVertexSS, + VkPipelineCreationFeedback* pVertexFB, + const VkPipelineShaderStageCreateInfo*& pFragmentSS) { shaderConfig.options.entryPointStage = spv::ExecutionModelVertex; - shaderConfig.options.entryPointName = _pVertexSS->pName; + shaderConfig.options.entryPointName = pVertexSS->pName; shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageVertex]; shaderConfig.options.mslOptions.indirect_params_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageVertex]; shaderConfig.options.mslOptions.shader_output_buffer_index = _outputBufferIndex.stages[kMVKShaderStageVertex]; @@ -916,7 +1024,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 shaderConfig.options.mslOptions.disable_rasterization = !_isRasterizing; addVertexInputToShaderConversionConfig(shaderConfig, pCreateInfo); - MVKMTLFunction func = getMTLFunction(shaderConfig, _pVertexSS, "Vertex"); + MVKMTLFunction func = getMTLFunction(shaderConfig, pVertexSS, pVertexFB, "Vertex"); id mtlFunc = func.getMTLFunction(); plDesc.vertexFunction = mtlFunc; if ( !mtlFunc ) { return false; } @@ -933,7 +1041,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 addMTLArgumentEncoders(func, pCreateInfo, shaderConfig, kMVKShaderStageVertex); if (funcRslts.isRasterizationDisabled) { - _pFragmentSS = nullptr; + pFragmentSS = nullptr; } // If we need the swizzle buffer and there's no place to put it, we're in serious trouble. @@ -965,9 +1073,12 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, - SPIRVShaderInputs& tcInputs) { + SPIRVShaderInputs& tcInputs, + const VkPipelineShaderStageCreateInfo* pVertexSS, + VkPipelineCreationFeedback* pVertexFB, + id* vtxFunctions) { shaderConfig.options.entryPointStage = spv::ExecutionModelVertex; - shaderConfig.options.entryPointName = _pVertexSS->pName; + shaderConfig.options.entryPointName = pVertexSS->pName; shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageVertex]; shaderConfig.options.mslOptions.shader_index_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageVertex]; shaderConfig.options.mslOptions.shader_output_buffer_index = _outputBufferIndex.stages[kMVKShaderStageVertex]; @@ -988,9 +1099,9 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 MVKMTLFunction func; for (uint32_t i = 0; i < sizeof(indexTypes)/sizeof(indexTypes[0]); i++) { shaderConfig.options.mslOptions.vertex_index_type = indexTypes[i]; - func = getMTLFunction(shaderConfig, _pVertexSS, "Vertex"); + func = getMTLFunction(shaderConfig, pVertexSS, pVertexFB, "Vertex"); id mtlFunc = func.getMTLFunction(); - _mtlTessVertexFunctions[i] = [mtlFunc retain]; + vtxFunctions[i] = mtlFunc; // not retained if ( !mtlFunc ) { return false; } auto& funcRslts = func.shaderConversionResults; @@ -1029,9 +1140,11 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& vtxOutputs, - SPIRVShaderInputs& teInputs) { + SPIRVShaderInputs& teInputs, + const VkPipelineShaderStageCreateInfo* pTessCtlSS, + VkPipelineCreationFeedback* pTessCtlFB) { shaderConfig.options.entryPointStage = spv::ExecutionModelTessellationControl; - shaderConfig.options.entryPointName = _pTessCtlSS->pName; + shaderConfig.options.entryPointName = pTessCtlSS->pName; shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageTessCtl]; shaderConfig.options.mslOptions.indirect_params_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageTessCtl]; shaderConfig.options.mslOptions.shader_input_buffer_index = getMetalBufferIndexForVertexAttributeBinding(kMVKTessCtlInputBufferBinding); @@ -1042,11 +1155,11 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 shaderConfig.options.mslOptions.dynamic_offsets_buffer_index = _dynamicOffsetBufferIndex.stages[kMVKShaderStageTessCtl]; shaderConfig.options.mslOptions.capture_output_to_buffer = true; shaderConfig.options.mslOptions.multi_patch_workgroup = true; - shaderConfig.options.mslOptions.fixed_subgroup_size = mvkIsAnyFlagEnabled(_pTessCtlSS->flags, VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT) ? 0 : _device->_pMetalFeatures->maxSubgroupSize; + shaderConfig.options.mslOptions.fixed_subgroup_size = mvkIsAnyFlagEnabled(pTessCtlSS->flags, VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT) ? 0 : _device->_pMetalFeatures->maxSubgroupSize; addPrevStageOutputToShaderConversionConfig(shaderConfig, vtxOutputs); addNextStageInputToShaderConversionConfig(shaderConfig, teInputs); - MVKMTLFunction func = getMTLFunction(shaderConfig, _pTessCtlSS, "Tessellation control"); + MVKMTLFunction func = getMTLFunction(shaderConfig, pTessCtlSS, pTessCtlFB, "Tessellation control"); id mtlFunc = func.getMTLFunction(); if ( !mtlFunc ) { return false; } plDesc.computeFunction = mtlFunc; @@ -1091,9 +1204,12 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, - SPIRVShaderOutputs& tcOutputs) { + SPIRVShaderOutputs& tcOutputs, + const VkPipelineShaderStageCreateInfo* pTessEvalSS, + VkPipelineCreationFeedback* pTessEvalFB, + const VkPipelineShaderStageCreateInfo*& pFragmentSS) { shaderConfig.options.entryPointStage = spv::ExecutionModelTessellationEvaluation; - shaderConfig.options.entryPointName = _pTessEvalSS->pName; + shaderConfig.options.entryPointName = pTessEvalSS->pName; shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageTessEval]; shaderConfig.options.mslOptions.shader_input_buffer_index = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalInputBufferBinding); shaderConfig.options.mslOptions.shader_patch_input_buffer_index = getMetalBufferIndexForVertexAttributeBinding(kMVKTessEvalPatchInputBufferBinding); @@ -1105,7 +1221,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 shaderConfig.options.mslOptions.disable_rasterization = !_isRasterizing; addPrevStageOutputToShaderConversionConfig(shaderConfig, tcOutputs); - MVKMTLFunction func = getMTLFunction(shaderConfig, _pTessEvalSS, "Tessellation evaluation"); + MVKMTLFunction func = getMTLFunction(shaderConfig, pTessEvalSS, pTessEvalFB, "Tessellation evaluation"); id mtlFunc = func.getMTLFunction(); plDesc.vertexFunction = mtlFunc; // Yeah, you read that right. Tess. eval functions are a kind of vertex function in Metal. if ( !mtlFunc ) { return false; } @@ -1120,7 +1236,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 addMTLArgumentEncoders(func, pCreateInfo, shaderConfig, kMVKShaderStageTessEval); if (funcRslts.isRasterizationDisabled) { - _pFragmentSS = nullptr; + pFragmentSS = nullptr; } if (!verifyImplicitBuffer(_needsTessEvalSwizzleBuffer, _swizzleBufferIndex, kMVKShaderStageTessEval, "swizzle")) { @@ -1138,16 +1254,18 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, - SPIRVShaderOutputs& shaderOutputs) { - if (_pFragmentSS) { + SPIRVShaderOutputs& shaderOutputs, + const VkPipelineShaderStageCreateInfo* pFragmentSS, + VkPipelineCreationFeedback* pFragmentFB) { + if (pFragmentSS) { shaderConfig.options.entryPointStage = spv::ExecutionModelFragment; shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageFragment]; shaderConfig.options.mslOptions.buffer_size_buffer_index = _bufferSizeBufferIndex.stages[kMVKShaderStageFragment]; shaderConfig.options.mslOptions.dynamic_offsets_buffer_index = _dynamicOffsetBufferIndex.stages[kMVKShaderStageFragment]; shaderConfig.options.mslOptions.view_mask_buffer_index = _viewRangeBufferIndex.stages[kMVKShaderStageFragment]; - shaderConfig.options.entryPointName = _pFragmentSS->pName; + shaderConfig.options.entryPointName = pFragmentSS->pName; shaderConfig.options.mslOptions.capture_output_to_buffer = false; - shaderConfig.options.mslOptions.fixed_subgroup_size = mvkIsAnyFlagEnabled(_pFragmentSS->flags, VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT) ? 0 : _device->_pMetalFeatures->maxSubgroupSize; + shaderConfig.options.mslOptions.fixed_subgroup_size = mvkIsAnyFlagEnabled(pFragmentSS->flags, VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT) ? 0 : _device->_pMetalFeatures->maxSubgroupSize; shaderConfig.options.mslOptions.check_discarded_frag_stores = true; if (_device->_pMetalFeatures->needsSampleDrefLodArrayWorkaround) { shaderConfig.options.mslOptions.sample_dref_lod_array_as_grad = true; @@ -1163,7 +1281,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 } addPrevStageOutputToShaderConversionConfig(shaderConfig, shaderOutputs); - MVKMTLFunction func = getMTLFunction(shaderConfig, _pFragmentSS, "Fragment"); + MVKMTLFunction func = getMTLFunction(shaderConfig, pFragmentSS, pFragmentFB, "Fragment"); id mtlFunc = func.getMTLFunction(); plDesc.fragmentFunction = mtlFunc; if ( !mtlFunc ) { return false; } @@ -1795,11 +1913,13 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 MVKMTLFunction MVKGraphicsPipeline::getMTLFunction(SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pShaderStage, + VkPipelineCreationFeedback* pStageFB, const char* pStageName) { MVKShaderModule* shaderModule = (MVKShaderModule*)pShaderStage->module; MVKMTLFunction func = shaderModule->getMTLFunction(&shaderConfig, pShaderStage->pSpecializationInfo, - this); + this, + pStageFB); if ( !func.getMTLFunction() ) { if (shouldFailOnPipelineCompileRequired()) { setConfigurationResult(VK_PIPELINE_COMPILE_REQUIRED); @@ -1823,15 +1943,11 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 MVKGraphicsPipeline::~MVKGraphicsPipeline() { @synchronized (getMTLDevice()) { - [_mtlTessVertexStageDesc release]; - [_mtlTessVertexStageState release]; [_mtlTessVertexStageIndex16State release]; [_mtlTessVertexStageIndex32State release]; [_mtlTessControlStageState release]; [_mtlPipelineState release]; - - for (id func : _mtlTessVertexFunctions) { [func release]; } } } @@ -1862,7 +1978,36 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 if (isUsingMetalArgumentBuffers()) { _descriptorBindingUse.resize(_descriptorSetCount); } if (isUsingPipelineStageMetalArgumentBuffers()) { _mtlArgumentEncoders.resize(_descriptorSetCount); } - MVKMTLFunction func = getMTLFunction(pCreateInfo); + const VkPipelineCreationFeedbackCreateInfo* pFeedbackInfo = nullptr; + for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { + switch (next->sType) { + case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: + pFeedbackInfo = (VkPipelineCreationFeedbackCreateInfo*)next; + break; + default: + break; + } + } + + // Initialize feedback. The VALID bit must be initialized, either set or cleared. + // We'll set the VALID bit on the stage feedback when we compile it. + VkPipelineCreationFeedback* pPipelineFB = nullptr; + VkPipelineCreationFeedback* pStageFB = nullptr; + uint64_t pipelineStart; + if (pFeedbackInfo) { + pPipelineFB = pFeedbackInfo->pPipelineCreationFeedback; + // n.b. Do *NOT* use mvkClear(). + pPipelineFB->flags = 0; + pPipelineFB->duration = 0; + for (uint32_t i = 0; i < pFeedbackInfo->pipelineStageCreationFeedbackCount; ++i) { + pFeedbackInfo->pPipelineStageCreationFeedbacks[i].flags = 0; + pFeedbackInfo->pPipelineStageCreationFeedbacks[i].duration = 0; + } + pStageFB = &pFeedbackInfo->pPipelineStageCreationFeedbacks[0]; + pipelineStart = mvkGetTimestamp(); + } + + MVKMTLFunction func = getMTLFunction(pCreateInfo, pStageFB); _mtlThreadgroupSize = func.threadGroupSize; _mtlPipelineState = nil; @@ -1890,6 +2035,10 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 } else { _hasValidMTLPipelineStates = false; } + if (pPipelineFB) { + if (_hasValidMTLPipelineStates) { mvkEnableFlags(pPipelineFB->flags, VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT); } + pPipelineFB->duration = mvkGetElapsedNanoseconds(pipelineStart); + } if (_needsSwizzleBuffer && _swizzleBufferIndex.stages[kMVKShaderStageCompute] > _device->_pMetalFeatures->maxPerStageBufferCount) { setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Compute shader requires swizzle buffer, but there is no free slot to pass it.")); @@ -1906,7 +2055,8 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 } // Returns a MTLFunction to use when creating the MTLComputePipelineState. -MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateInfo* pCreateInfo) { +MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateInfo* pCreateInfo, + VkPipelineCreationFeedback* pStageFB) { const VkPipelineShaderStageCreateInfo* pSS = &pCreateInfo->stage; if ( !mvkAreAllFlagsEnabled(pSS->stage, VK_SHADER_STAGE_COMPUTE_BIT) ) { return MVKMTLFunctionNull; } @@ -1956,7 +2106,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 shaderConfig.options.mslOptions.dynamic_offsets_buffer_index = _dynamicOffsetBufferIndex.stages[kMVKShaderStageCompute]; shaderConfig.options.mslOptions.indirect_params_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageCompute]; - MVKMTLFunction func = ((MVKShaderModule*)pSS->module)->getMTLFunction(&shaderConfig, pSS->pSpecializationInfo, this); + MVKMTLFunction func = ((MVKShaderModule*)pSS->module)->getMTLFunction(&shaderConfig, pSS->pSpecializationInfo, this, pStageFB); if ( !func.getMTLFunction() ) { if (shouldFailOnPipelineCompileRequired()) { setConfigurationResult(VK_PIPELINE_COMPILE_REQUIRED); @@ -1998,23 +2148,26 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 MVKShaderLibrary* MVKPipelineCache::getShaderLibrary(SPIRVToMSLConversionConfiguration* pContext, MVKShaderModule* shaderModule, MVKPipeline* pipeline, + VkPipelineCreationFeedback* pShaderFeedback, uint64_t startTime) { if (_isExternallySynchronized) { - return getShaderLibraryImpl(pContext, shaderModule, pipeline, startTime); + return getShaderLibraryImpl(pContext, shaderModule, pipeline, pShaderFeedback, startTime); } else { lock_guard lock(_shaderCacheLock); - return getShaderLibraryImpl(pContext, shaderModule, pipeline, startTime); + return getShaderLibraryImpl(pContext, shaderModule, pipeline, pShaderFeedback, startTime); } } MVKShaderLibrary* MVKPipelineCache::getShaderLibraryImpl(SPIRVToMSLConversionConfiguration* pContext, MVKShaderModule* shaderModule, MVKPipeline* pipeline, + VkPipelineCreationFeedback* pShaderFeedback, uint64_t startTime) { bool wasAdded = false; MVKShaderLibraryCache* slCache = getShaderLibraryCache(shaderModule->getKey()); - MVKShaderLibrary* shLib = slCache->getShaderLibrary(pContext, shaderModule, pipeline, &wasAdded, startTime); + MVKShaderLibrary* shLib = slCache->getShaderLibrary(pContext, shaderModule, pipeline, &wasAdded, pShaderFeedback, startTime); if (wasAdded) { markDirty(); } + else if (pShaderFeedback) { mvkEnableFlags(pShaderFeedback->flags, VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT); } return shLib; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h index a7e3417fb..87418edd1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h @@ -107,7 +107,9 @@ class MVKShaderLibrary : public MVKBaseObject { friend MVKShaderLibraryCache; friend MVKShaderModule; - MVKMTLFunction getMTLFunction(const VkSpecializationInfo* pSpecializationInfo, MVKShaderModule* shaderModule); + MVKMTLFunction getMTLFunction(const VkSpecializationInfo* pSpecializationInfo, + VkPipelineCreationFeedback* pShaderFeedback, + MVKShaderModule* shaderModule); void handleCompilationError(NSError* err, const char* opDesc); MTLFunctionConstant* getFunctionConstant(NSArray* mtlFCs, NSUInteger mtlFCID); void compileLibrary(const std::string& msl); @@ -144,7 +146,8 @@ class MVKShaderLibraryCache : public MVKBaseObject { */ MVKShaderLibrary* getShaderLibrary(SPIRVToMSLConversionConfiguration* pShaderConfig, MVKShaderModule* shaderModule, MVKPipeline* pipeline, - bool* pWasAdded, uint64_t startTime = 0); + bool* pWasAdded, VkPipelineCreationFeedback* pShaderFeedback, + uint64_t startTime = 0); MVKShaderLibraryCache(MVKVulkanAPIDeviceObject* owner) : _owner(owner) {}; @@ -155,7 +158,9 @@ class MVKShaderLibraryCache : public MVKBaseObject { friend MVKPipelineCache; friend MVKShaderModule; - MVKShaderLibrary* findShaderLibrary(SPIRVToMSLConversionConfiguration* pShaderConfig, uint64_t startTime = 0); + MVKShaderLibrary* findShaderLibrary(SPIRVToMSLConversionConfiguration* pShaderConfig, + VkPipelineCreationFeedback* pShaderFeedback = nullptr, + uint64_t startTime = 0); MVKShaderLibrary* addShaderLibrary(const SPIRVToMSLConversionConfiguration* pShaderConfig, const SPIRVToMSLConversionResult& conversionResult); MVKShaderLibrary* addShaderLibrary(const SPIRVToMSLConversionConfiguration* pShaderConfig, @@ -207,7 +212,8 @@ class MVKShaderModule : public MVKVulkanAPIDeviceObject { /** Returns the Metal shader function, possibly specialized. */ MVKMTLFunction getMTLFunction(SPIRVToMSLConversionConfiguration* pShaderConfig, const VkSpecializationInfo* pSpecializationInfo, - MVKPipeline* pipeline); + MVKPipeline* pipeline, + VkPipelineCreationFeedback* pShaderFeedback); /** Convert the SPIR-V to MSL, using the specified shader conversion configuration. */ bool convert(SPIRVToMSLConversionConfiguration* pShaderConfig, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm index 12ddbf4c5..a47a65b77 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm @@ -67,7 +67,9 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD return wgDim.size; } -MVKMTLFunction MVKShaderLibrary::getMTLFunction(const VkSpecializationInfo* pSpecializationInfo, MVKShaderModule* shaderModule) { +MVKMTLFunction MVKShaderLibrary::getMTLFunction(const VkSpecializationInfo* pSpecializationInfo, + VkPipelineCreationFeedback* pShaderFeedback, + MVKShaderModule* shaderModule) { if ( !_mtlLibrary ) { return MVKMTLFunctionNull; } @@ -76,9 +78,15 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD NSString* mtlFuncName = @(_shaderConversionResultInfo.entryPoint.mtlFunctionName.c_str()); MVKDevice* mvkDev = _owner->getDevice(); - uint64_t startTime = mvkDev->getPerformanceTimestamp(); + uint64_t startTime = pShaderFeedback ? mvkGetTimestamp() : mvkDev->getPerformanceTimestamp(); id mtlFunc = [[_mtlLibrary newFunctionWithName: mtlFuncName] autorelease]; mvkDev->addActivityPerformance(mvkDev->_performanceStatistics.shaderCompilation.functionRetrieval, startTime); + if (pShaderFeedback) { + if (mtlFunc) { + mvkEnableFlags(pShaderFeedback->flags, VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT); + } + pShaderFeedback->duration += mvkGetElapsedNanoseconds(startTime); + } if (mtlFunc) { // If the Metal device supports shader specialization, and the Metal function expects to be specialized, @@ -108,7 +116,13 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD // Compile the specialized Metal function, and use it instead of the unspecialized Metal function. MVKFunctionSpecializer fs(_owner); + if (pShaderFeedback) { + startTime = mvkGetTimestamp(); + } mtlFunc = [fs.newMTLFunction(_mtlLibrary, mtlFuncName, mtlFCVals) autorelease]; + if (pShaderFeedback) { + pShaderFeedback->duration += mvkGetElapsedNanoseconds(startTime); + } } } } @@ -240,13 +254,17 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD MVKShaderLibrary* MVKShaderLibraryCache::getShaderLibrary(SPIRVToMSLConversionConfiguration* pShaderConfig, MVKShaderModule* shaderModule, MVKPipeline* pipeline, - bool* pWasAdded, uint64_t startTime) { + bool* pWasAdded, VkPipelineCreationFeedback* pShaderFeedback, + uint64_t startTime) { bool wasAdded = false; - MVKShaderLibrary* shLib = findShaderLibrary(pShaderConfig, startTime); + MVKShaderLibrary* shLib = findShaderLibrary(pShaderConfig, pShaderFeedback, startTime); if ( !shLib && !pipeline->shouldFailOnPipelineCompileRequired() ) { SPIRVToMSLConversionResult conversionResult; if (shaderModule->convert(pShaderConfig, conversionResult)) { shLib = addShaderLibrary(pShaderConfig, conversionResult); + if (pShaderFeedback) { + pShaderFeedback->duration += mvkGetElapsedNanoseconds(startTime); + } wasAdded = true; } } @@ -259,12 +277,16 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD // Finds and returns a shader library matching the shader config, or returns nullptr if it doesn't exist. // If a match is found, the shader config is aligned with the shader config of the matching library. MVKShaderLibrary* MVKShaderLibraryCache::findShaderLibrary(SPIRVToMSLConversionConfiguration* pShaderConfig, + VkPipelineCreationFeedback* pShaderFeedback, uint64_t startTime) { for (auto& slPair : _shaderLibraries) { if (slPair.first.matches(*pShaderConfig)) { pShaderConfig->alignWith(slPair.first); MVKDevice* mvkDev = _owner->getDevice(); mvkDev->addActivityPerformance(mvkDev->_performanceStatistics.shaderCompilation.shaderLibraryFromCache, startTime); + if (pShaderFeedback) { + pShaderFeedback->duration += mvkGetElapsedNanoseconds(startTime); + } return slPair.second; } } @@ -309,23 +331,24 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD MVKMTLFunction MVKShaderModule::getMTLFunction(SPIRVToMSLConversionConfiguration* pShaderConfig, const VkSpecializationInfo* pSpecializationInfo, - MVKPipeline* pipeline) { + MVKPipeline* pipeline, + VkPipelineCreationFeedback* pShaderFeedback) { MVKShaderLibrary* mvkLib = _directMSLLibrary; if ( !mvkLib ) { - uint64_t startTime = _device->getPerformanceTimestamp(); + uint64_t startTime = pShaderFeedback ? mvkGetTimestamp() : _device->getPerformanceTimestamp(); MVKPipelineCache* pipelineCache = pipeline->getPipelineCache(); if (pipelineCache) { - mvkLib = pipelineCache->getShaderLibrary(pShaderConfig, this, pipeline, startTime); + mvkLib = pipelineCache->getShaderLibrary(pShaderConfig, this, pipeline, pShaderFeedback, startTime); } else { lock_guard lock(_accessLock); - mvkLib = _shaderLibraryCache.getShaderLibrary(pShaderConfig, this, pipeline, nullptr, startTime); + mvkLib = _shaderLibraryCache.getShaderLibrary(pShaderConfig, this, pipeline, nullptr, pShaderFeedback, startTime); } } else { mvkLib->setEntryPointName(pShaderConfig->options.entryPointName); pShaderConfig->markAllInterfaceVarsAndResourcesUsed(); } - return mvkLib ? mvkLib->getMTLFunction(pSpecializationInfo, this) : MVKMTLFunctionNull; + return mvkLib ? mvkLib->getMTLFunction(pSpecializationInfo, pShaderFeedback, this) : MVKMTLFunctionNull; } bool MVKShaderModule::convert(SPIRVToMSLConversionConfiguration* pShaderConfig, diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 4c6fe6f54..efa84e0f4 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -111,6 +111,7 @@ MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, MVK_EXTENSION(EXT_metal_objects, EXT_METAL_OBJECTS, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, INSTANCE, 10.11, 8.0) MVK_EXTENSION(EXT_pipeline_creation_cache_control, EXT_PIPELINE_CREATION_CACHE_CONTROL, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_pipeline_creation_feedback, EXT_PIPELINE_CREATION_FEEDBACK, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE, 11.0, 11.0) MVK_EXTENSION(EXT_private_data, EXT_PRIVATE_DATA, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_robustness2, EXT_ROBUSTNESS_2, DEVICE, 10.11, 8.0) From 6374d9d29b75c4a922d39ca2e8554402fafd0469 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 11 Jul 2023 14:22:59 -0400 Subject: [PATCH 63/74] Fix visionOS build errors and warnings where possible. - Remove visionOS from multi-platform builds because it requires Xcode 15+ and will abort a multi-platform build. - Define TARGET_OS_XR for older SDK's. - A number of SDK deprecation warnings remain when building for visionOS. These cannot be removed without significant refactoring. - Build visionOS dependencies for Release build by default. - Fix local variable initialization warning (unrelated). --- Common/MVKCommonEnvironment.h | 3 + Docs/Whats_New.md | 1 + .../ExternalDependencies-xrOS.xcscheme | 2 +- Makefile | 10 +-- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 2 +- README.md | 70 +++++++++++-------- fetchDependencies | 13 ++-- 7 files changed, 62 insertions(+), 39 deletions(-) diff --git a/Common/MVKCommonEnvironment.h b/Common/MVKCommonEnvironment.h index d75396b8b..a14ba91d0 100644 --- a/Common/MVKCommonEnvironment.h +++ b/Common/MVKCommonEnvironment.h @@ -63,6 +63,9 @@ extern "C" { #endif /** Building for visionOS. */ +#ifndef TARGET_OS_XR +# define TARGET_OS_XR 0 // Older SDK's don't define TARGET_OS_XR +#endif #ifndef MVK_VISIONOS # define MVK_VISIONOS TARGET_OS_XR #endif diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 5131889b8..755cb806a 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -26,6 +26,7 @@ Released TBD - `VK_EXT_shader_subgroup_ballot` - `VK_EXT_shader_subgroup_vote` - Add support for `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN`. +- Support building MoltenVK for visionOS. - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. - Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. - Support maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-xrOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-xrOS.xcscheme index 288332c83..27214297a 100644 --- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-xrOS.xcscheme +++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-xrOS.xcscheme @@ -30,7 +30,7 @@ shouldAutocreateTestPlan = "YES"> pPipelineCreationFeedback; // n.b. Do *NOT* use mvkClear(). diff --git a/README.md b/README.md index 8349a8caa..e44e34a61 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Table of Contents ----------------- - [Introduction to **MoltenVK**](#intro) -- [Developing Vulkan Applications on *macOS, iOS, and tvOS*](#developing_vulkan) +- [Developing Vulkan Applications on *macOS, iOS, tvOS, and visionOS*](#developing_vulkan) - [Using the *Vulkan SDK*](#sdk) - [Using MoltenVK Directly](#download) - [Fetching **MoltenVK** Source Code](#install) @@ -38,19 +38,20 @@ 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*, 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+*, and all *Apple* architectures, including *Apple Silicon*. +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 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 standard distribution -channels, including *Apple's App Store*. +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: @@ -67,8 +68,8 @@ The **MoltenVK** runtime package contains two products: -Developing *Vulkan* Applications for *macOS, iOS, and tvOS* ---------------------------------------------------------- +Developing *Vulkan* Applications for *macOS, iOS, tvOS, and visionOS* +--------------------------------------------------------------------- ### Using the *Vulkan SDK* @@ -96,10 +97,10 @@ extension in the *Vulkan* specification for more information about the use of th ### Using MoltenVK Directly -If you are developing a *Vulkan* application for *iOS* or *tvOS*, 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 +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. @@ -148,14 +149,21 @@ 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, -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, 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. Running `fetchDependencies` repeatedly with different platforms will accumulate targets in the `XCFramework`. @@ -196,11 +204,11 @@ _Xcode_ version. If you require support for earlier OS versions, modify the `MAC 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* or *tvOS* devices that support *Metal*, -or on the *Xcode* *iOS Simulator* or *tvOS Simulator*. +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*, or *tvOS 9* - (or *iOS 11* or *tvOS 11* if using `IOSurfaces`). +- 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 [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 @@ -220,6 +228,7 @@ platforms, or just one platform (in **_Release_** configuration): - **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` @@ -254,6 +263,8 @@ 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 @@ -262,12 +273,15 @@ 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. +- 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 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 @@ -346,14 +360,14 @@ the contents of that directory out of this **MoltenVK** repository into your own ------------------------------------ **MoltenVK** is designed to be an implementation of a *Vulkan 1.2* subset that runs on *macOS*, *iOS*, -and *tvOS* platforms by mapping *Vulkan* capability to native *Metal* capability. +*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 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*, and *tvOS* platforms. *Vulkan* compliance may fall into one of -the following categories: +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. @@ -376,7 +390,7 @@ be implemented or worked around. [*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*, and *tvOS*, where a native *Vulkan* driver is not available. +*macOS*, *iOS*, *tvOS*, and *visionOS*, where a native *Vulkan* driver is not available. diff --git a/fetchDependencies b/fetchDependencies index 04e065fe1..a340348be 100755 --- a/fetchDependencies +++ b/fetchDependencies @@ -4,7 +4,8 @@ # # fetchDependencies - Retrieves the correct versions of all dependencies # -# macOS usage: ./fetchDependencies [--macos] [--ios] [--iossim] [--tvos] [--tvossim] [--all] [--none] +# macOS usage: ./fetchDependencies [--macos] [--ios] [--iossim] [--tvos] [--tvossim] +# [--visionos] [--visionossim] [--all] [--none] # [-v] [--debug] [--build-spirv-tools] # [--v-headers-root path] [--spirv-cross-root path] [--glslang-root path] # @@ -33,9 +34,11 @@ # Build the external libraries for the visionOS Simulator platform. # # --all -# Equivalent to specifying [--macos --ios --iossim --maccat --tvos --tvossim --visionos --visionossim]. +# Equivalent to specifying [--macos --ios --iossim --maccat --tvos --tvossim]. # Results in one XCFramework for each external library, each containing # binaries for all supported platforms. +# Currently excludes --visionos and --visionossim targets because those +# require Xcode 15+ and will abort a multi-platform build. # # --none # Don't build the external libraries for any platform (this is the default). @@ -150,14 +153,14 @@ while (( "$#" )); do shift 1 ;; --all) + BLD_MACOS="Y" BLD_IOS="Y" BLD_IOS_SIM="Y" BLD_MAC_CAT="Y" BLD_TVOS="Y" BLD_TVOS_SIM="Y" - BLD_VISIONOS="Y" - BLD_VISIONOS_SIM="Y" - BLD_MACOS="Y" +# BLD_VISIONOS="Y" # Requires Xcode 15+ +# BLD_VISIONOS_SIM="Y" # Requires Xcode 15+ shift 1 ;; --none) From f6ba6f2dcc56ddbf399b24ebee5bb2282bfb9953 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 12 Jul 2023 16:38:32 -0400 Subject: [PATCH 64/74] Drop official support for using Xcode 11 to build MoltenVK. - Remove Xcode 11 build from GitHub CI. - Leave MVK_XCODE_12 guards in place to allow devs to possibly continue to attempt to build existing MoltenVK code using Xcode 11, even though it's not officially supported. Such devs may have to add their own additional MVK_XCODE_12 guards for any Xcode 12 API features added after this change. --- .github/workflows/CI.yml | 10 +++------- Docs/Whats_New.md | 1 + 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2b59eab01..aa78ff8b6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,21 +15,17 @@ jobs: build: strategy: matrix: - xcode: [ "14.3" ] + xcode: [ "14.3.1" ] platform: [ "all", "macos", "ios" ] os: [ "macos-13" ] upload_artifacts: [ true ] - # additional specific configurations + + # Legacy configurations include: - # "Legacy" Xcode 12.5.1 & 11.7 macOS builds - xcode: "12.5.1" platform: "macos" os: "macos-11" upload_artifacts: false - - xcode: "11.7" - platform: "macos" - os: "macos-11" - upload_artifacts: false fail-fast: false name: 'MoltenVK (Xcode ${{ matrix.xcode }} - ${{ matrix.platform }})' diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 755cb806a..9e0fc42ac 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -32,6 +32,7 @@ Released TBD - Support maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` - Add support for `VK_PRESENT_MODE_IMMEDIATE_KHR` to macOS Cube demo. - Log more info about SPIR-V to MSL conversion errors. +- Drop official support for using *Xcode 11* to build MoltenVK. From 817038e8d876c7e84464181399346020739d8bf2 Mon Sep 17 00:00:00 2001 From: Malcolm Bechard's MacMini M1 Date: Tue, 18 Jul 2023 20:19:23 -0400 Subject: [PATCH 65/74] Fix regression caused by #1922 Needed to complete fix for #1874 We can't wait until getMTLComputeEncoder() is called to dirty the state, because this call will be avoided by dirty checks themselves. Those checks are comparing against leftover and now incorrect state since the previous encoder has already ended. It needs to be dirtied on encoder end. --- MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index a58d6457d..5edc13aaa 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -839,6 +839,10 @@ void MVKCommandEncoder::endCurrentMetalEncoding() { endMetalRenderEncoding(); + _computePipelineState.markDirty(); + _computePushConstants.markDirty(); + _computeResourcesState.markDirty(); + if (_mtlComputeEncoder && _cmdBuffer->_hasStageCounterTimestampCommand) { [_mtlComputeEncoder updateFence: getStageCountersMTLFence()]; } endMetalEncoding(_mtlComputeEncoder); _mtlComputeEncoderUse = kMVKCommandUseNone; @@ -856,7 +860,7 @@ _mtlComputeEncoder = [_mtlCmdBuffer computeCommandEncoder]; retainIfImmediatelyEncoding(_mtlComputeEncoder); beginMetalComputeEncoding(cmdUse); - markCurrentComputeStateDirty = true; // Always mark current compute state dirty for new encoder + markCurrentComputeStateDirty = false; // Already marked dirty above in endCurrentMetalEncoding() } if(markCurrentComputeStateDirty) { _computePipelineState.markDirty(); From 5294c196874ea0bc242e5e58160dbc07c00a36bb Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 19 Jul 2023 18:53:41 -0400 Subject: [PATCH 66/74] Fix bad access regression to prematurely-deallocated MTLFunction. When compiling tessellation vertex shaders, MVKGraphicsPipeline pass array of MVKMTLFunction instead of MTLFunctions to retain MTLFunctions for duration of processing. --- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 6 +++--- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 22 ++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 825ae6b89..505e894c1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -318,7 +318,7 @@ class MVKGraphicsPipeline : public MVKPipeline { id getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id& plState); id getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id& plState, const char* compilerType); - bool compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, id* vtxFunctions, VkPipelineCreationFeedback* pVertexFB); + bool compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, MVKMTLFunction* pVtxFunctions, VkPipelineCreationFeedback* pVertexFB); bool compileTessControlStageState(MTLComputePipelineDescriptor* tcPLDesc, VkPipelineCreationFeedback* pTessCtlFB); void initCustomSamplePositions(const VkGraphicsPipelineCreateInfo* pCreateInfo); void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, VkPipelineCreationFeedback* pPipelineFB, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); @@ -328,11 +328,11 @@ class MVKGraphicsPipeline : public MVKPipeline { void addNextStageInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& inputs); void addPrevStageOutputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& outputs); MTLRenderPipelineDescriptor* newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); - MTLComputePipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, id* vtxFunctions); + MTLComputePipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, MVKMTLFunction* pVtxFunctions); MTLComputePipelineDescriptor* newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pVertexSS, const VkPipelineShaderStageCreateInfo* pTessEvalSS); MTLRenderPipelineDescriptor* newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS); bool addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo*& pFragmentSS); - bool addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& nextInputs, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, id* vtxFunctions); + bool addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& nextInputs, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, MVKMTLFunction* pVtxFunctions); bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, SPIRVShaderInputs& nextInputs, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB); bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo*& pFragmentSS); bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 66b61ad4b..13f59b6bc 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -338,16 +338,16 @@ static const char vtxCompilerType[] = "Vertex stage pipeline for tessellation"; bool MVKGraphicsPipeline::compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, - id* vtxFunctions, + MVKMTLFunction* pVtxFunctions, VkPipelineCreationFeedback* pVertexFB) { uint64_t startTime = 0; if (pVertexFB) { startTime = mvkGetTimestamp(); } - vtxPLDesc.computeFunction = vtxFunctions[0]; + vtxPLDesc.computeFunction = pVtxFunctions[0].getMTLFunction(); bool res = !!getOrCompilePipeline(vtxPLDesc, _mtlTessVertexStageState, vtxCompilerType); - vtxPLDesc.computeFunction = vtxFunctions[1]; + vtxPLDesc.computeFunction = pVtxFunctions[1].getMTLFunction(); vtxPLDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt16; for (uint32_t i = 0; i < 31; i++) { MTLBufferLayoutDescriptor* blDesc = vtxPLDesc.stageInputDescriptor.layouts[i]; @@ -357,7 +357,7 @@ } res |= !!getOrCompilePipeline(vtxPLDesc, _mtlTessVertexStageIndex16State, vtxCompilerType); - vtxPLDesc.computeFunction = vtxFunctions[2]; + vtxPLDesc.computeFunction = pVtxFunctions[2].getMTLFunction(); vtxPLDesc.stageInputDescriptor.indexType = MTLIndexTypeUInt32; res |= !!getOrCompilePipeline(vtxPLDesc, _mtlTessVertexStageIndex32State, vtxCompilerType); @@ -695,7 +695,7 @@ SPIRVToMSLConversionConfiguration shaderConfig; initShaderConversionConfig(shaderConfig, pCreateInfo, reflectData); - id vtxFunctions[3] = { nil }; + MVKMTLFunction vtxFunctions[3] = {}; MTLComputePipelineDescriptor* vtxPLDesc = newMTLTessVertexStageDescriptor(pCreateInfo, reflectData, shaderConfig, pVertexSS, pVertexFB, pTessCtlSS, vtxFunctions); // temp retained MTLComputePipelineDescriptor* tcPLDesc = newMTLTessControlStageDescriptor(pCreateInfo, reflectData, shaderConfig, pTessCtlSS, pTessCtlFB, pVertexSS, pTessEvalSS); // temp retained MTLRenderPipelineDescriptor* rastPLDesc = newMTLTessRasterStageDescriptor(pCreateInfo, reflectData, shaderConfig, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB, pTessCtlSS); // temp retained @@ -770,7 +770,7 @@ const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, - id* vtxFunctions) { + MVKMTLFunction* pVtxFunctions) { MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new]; // retained SPIRVShaderInputs tcInputs; @@ -787,7 +787,7 @@ }), tcInputs.end()); // Add shader stages. - if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig, tcInputs, pVertexSS, pVertexFB, vtxFunctions)) { return nil; } + if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig, tcInputs, pVertexSS, pVertexFB, pVtxFunctions)) { return nil; } // Vertex input plDesc.stageInputDescriptor = [MTLStageInputOutputDescriptor stageInputOutputDescriptor]; @@ -1076,7 +1076,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 SPIRVShaderInputs& tcInputs, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, - id* vtxFunctions) { + MVKMTLFunction* pVtxFunctions) { shaderConfig.options.entryPointStage = spv::ExecutionModelVertex; shaderConfig.options.entryPointName = pVertexSS->pName; shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageVertex]; @@ -1100,9 +1100,9 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 for (uint32_t i = 0; i < sizeof(indexTypes)/sizeof(indexTypes[0]); i++) { shaderConfig.options.mslOptions.vertex_index_type = indexTypes[i]; func = getMTLFunction(shaderConfig, pVertexSS, pVertexFB, "Vertex"); - id mtlFunc = func.getMTLFunction(); - vtxFunctions[i] = mtlFunc; // not retained - if ( !mtlFunc ) { return false; } + if ( !func.getMTLFunction() ) { return false; } + + pVtxFunctions[i] = func; auto& funcRslts = func.shaderConversionResults; _needsVertexSwizzleBuffer = funcRslts.needsSwizzleBuffer; From f7e0d7db3e8f71c391bc6220224e976cc9df6bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Fri, 28 Jul 2023 16:11:51 +0300 Subject: [PATCH 67/74] Don't fetch a submodule if the commit is already known This allows rebuilding without an internet connection and avoids random build failures on flaky connections. --- fetchDependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetchDependencies b/fetchDependencies index a340348be..f03f36c86 100755 --- a/fetchDependencies +++ b/fetchDependencies @@ -232,7 +232,7 @@ function update_repo() { if [ -d $1 -a -d $1/.git ]; then cd $1 - git fetch --all + git cat-file -e $3 || git fetch --all git checkout --force $3 cd - > /dev/null else From dd31587337b4b7017b72cd77cce54278fa7f4047 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Sat, 12 Aug 2023 13:32:28 -0400 Subject: [PATCH 68/74] Fix sync delay between calls to vkQueueSubmit() on non-Apple-Silicon devices. The [MTLDevice sampleTimestamps:gpuTimestamp:] function turns out to be synchronized with other queue activities, and can block GPU execution if it is called between MTLCommandBuffer submissions. On non-Apple-Silicon devices, it was called before and after every vkQueueSubmit() submission, to track the correlation between GPU and CPU timestamps, and was delaying the start of GPU work on the next submission (on Apple Silicon, both CPU & GPU timestamps are specified in nanoseconds, and the call was bypassed). Move timestamp correlation from vkQueueSubmit() to vkGetPhysicalDeviceProperties(), where it is used to update VkPhysicalDeviceLimits::timestampPeriod on non-Apple-Silicon devices. Delegate MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2*) to MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties*), plus minimize wasted effort if pNext is empty (unrelated). Move the declaration of several MVKPhysicalDevice member structs to potentially reduce member spacing (unrelated). --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 23 ++++--------- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 39 +++++++++++------------ MoltenVK/MoltenVK/GPUObjects/MVKQueue.h | 3 -- MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm | 7 ---- 5 files changed, 26 insertions(+), 47 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 9e0fc42ac..d473ae912 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -363,6 +363,7 @@ Released 2022/02/07 - Fix issue where *MSL 2.3* only available on *Apple Silicon*, even on *macOS*. - Fix memory leak of dummy `MTLTexture` in render subpasses that use no attachments. - Fix Metal object retain-release errors in assignment operators. +- Fix sync delay between calls to `vkQueueSubmit()` on non-Apple-Silicon devices. - Fix use of GPU counter sets on older versions of iOS running on the simulator. - `mvk::getShaderOutputs()` in `SPRIVReflection.h` support flattening nested structures. - Replaced ASL logging levels with `MVKConfigLogLevel`. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 5186fe4a0..450fad661 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -356,20 +356,6 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { return _metalFeatures.argumentBuffers && mvkConfig().useMetalArgumentBuffers != MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER; }; - /** - * Returns the start timestamps of a timestamp correlation. - * The returned values should be later passed back to updateTimestampPeriod(). - */ - void startTimestampCorrelation(MTLTimestamp& cpuStart, MTLTimestamp& gpuStart); - - /** - * Updates the current value of VkPhysicalDeviceLimits::timestampPeriod, based on the - * correlation between the CPU time tickes and GPU time ticks, from the specified start - * values, to the current values. The cpuStart and gpuStart values should have been - * retrieved from a prior call to startTimestampCorrelation(). - */ - void updateTimestampPeriod(MTLTimestamp cpuStart, MTLTimestamp gpuStart); - #pragma mark Construction @@ -416,6 +402,7 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { void initExtensions(); void initCounterSets(); bool needsCounterSetRetained(); + void updateTimestampsAndPeriod(); MVKArrayRef getQueueFamilies(); void initPipelineCacheUUID(); uint32_t getHighestGPUCapability(); @@ -435,16 +422,18 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { VkPhysicalDeviceMemoryProperties _memoryProperties; MVKSmallVector _queueFamilies; MVKPixelFormats _pixelFormats; + VkExternalMemoryProperties _hostPointerExternalMemoryProperties; + VkExternalMemoryProperties _mtlBufferExternalMemoryProperties; + VkExternalMemoryProperties _mtlTextureExternalMemoryProperties; id _timestampMTLCounterSet; MVKSemaphoreStyle _vkSemaphoreStyle; + MTLTimestamp _prevCPUTimestamp = 0; + MTLTimestamp _prevGPUTimestamp = 0; uint32_t _allMemoryTypes; uint32_t _hostVisibleMemoryTypes; uint32_t _hostCoherentMemoryTypes; uint32_t _privateMemoryTypes; uint32_t _lazilyAllocatedMemoryTypes; - VkExternalMemoryProperties _hostPointerExternalMemoryProperties; - VkExternalMemoryProperties _mtlBufferExternalMemoryProperties; - VkExternalMemoryProperties _mtlTextureExternalMemoryProperties; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 3c77519db..59f90df35 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -451,10 +451,17 @@ } void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties* properties) { + updateTimestampsAndPeriod(); *properties = _properties; } void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) { + + properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + getProperties(&properties->properties); + + if ( !properties->pNext ) { return; } + uint32_t uintMax = std::numeric_limits::max(); uint32_t maxSamplerCnt = getMaxSamplerCount(); bool isTier2 = supportsMetalArgumentBuffers() && (_metalFeatures.argumentBuffersTier >= MTLArgumentBuffersTier2); @@ -536,8 +543,6 @@ supportedProps12.maxTimelineSemaphoreValueDifference = std::numeric_limits::max(); supportedProps12.framebufferIntegerColorSampleCounts = _metalFeatures.supportedSampleCounts; - properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - properties->properties = _properties; for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) { switch ((uint32_t)next->sType) { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES: { @@ -1562,23 +1567,17 @@ return rslt; } -// Don't need to do this for Apple GPUs, where the GPU and CPU timestamps -// are the same, or if we're not using GPU timestamp counters. -void MVKPhysicalDevice::startTimestampCorrelation(MTLTimestamp& cpuStart, MTLTimestamp& gpuStart) { - if (_properties.vendorID == kAppleVendorId || !_timestampMTLCounterSet) { return; } - [_mtlDevice sampleTimestamps: &cpuStart gpuTimestamp: &gpuStart]; -} - -// Don't need to do this for Apple GPUs, where the GPU and CPU timestamps -// are the same, or if we're not using GPU timestamp counters. -void MVKPhysicalDevice::updateTimestampPeriod(MTLTimestamp cpuStart, MTLTimestamp gpuStart) { - if (_properties.vendorID == kAppleVendorId || !_timestampMTLCounterSet) { return; } - - MTLTimestamp cpuEnd; - MTLTimestamp gpuEnd; - [_mtlDevice sampleTimestamps: &cpuEnd gpuTimestamp: &gpuEnd]; - - _properties.limits.timestampPeriod = (double)(cpuEnd - cpuStart) / (double)(gpuEnd - gpuStart); +// Mark both CPU and GPU timestamps, and if needed, update the timestamp period for this device. +// On Apple GPUs, the CPU & GPU timestamps are the same, and the timestamp period never changes. +void MVKPhysicalDevice::updateTimestampsAndPeriod() { + if (_properties.vendorID == kAppleVendorId) { + _prevGPUTimestamp = _prevCPUTimestamp = mvkGetElapsedNanoseconds(); + } else { + MTLTimestamp earlierCPUTs = _prevCPUTimestamp; + MTLTimestamp earlierGPUTs = _prevGPUTimestamp; + [_mtlDevice sampleTimestamps: &_prevCPUTimestamp gpuTimestamp: &_prevGPUTimestamp]; + _properties.limits.timestampPeriod = (double)(_prevCPUTimestamp - earlierCPUTs) / (double)(_prevGPUTimestamp - earlierGPUTs); + } } @@ -2606,7 +2605,7 @@ _properties.limits.optimalBufferCopyRowPitchAlignment = 1; _properties.limits.timestampComputeAndGraphics = VK_TRUE; - _properties.limits.timestampPeriod = _metalFeatures.counterSamplingPoints ? 1.0 : mvkGetTimestampPeriod(); + _properties.limits.timestampPeriod = mvkGetTimestampPeriod(); // Will be 1.0 on Apple Silicon _properties.limits.pointSizeRange[0] = 1; switch (_properties.vendorID) { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h index 96d77bc18..bcefd2f37 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h @@ -255,11 +255,8 @@ class MVKQueueFullCommandBufferSubmission : public MVKQueueCommandBufferSubmissi protected: void submitCommandBuffers() override; - void finish() override; MVKSmallVector _cmdBuffers; - MTLTimestamp _cpuStart = 0; - MTLTimestamp _gpuStart = 0; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index 96b34cc3b..0ad143072 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -524,16 +524,9 @@ template void MVKQueueFullCommandBufferSubmission::submitCommandBuffers() { - _queue->getPhysicalDevice()->startTimestampCorrelation(_cpuStart, _gpuStart); for (auto& cb : _cmdBuffers) { cb->submit(this, &_encodingContext); } } -template -void MVKQueueFullCommandBufferSubmission::finish() { - _queue->getPhysicalDevice()->updateTimestampPeriod(_cpuStart, _gpuStart); - MVKQueueCommandBufferSubmission::finish(); -} - #pragma mark - #pragma mark MVKQueuePresentSurfaceSubmission From 41a5a97fefa27586a91d5aeb3369c27a9d26e942 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Sun, 13 Aug 2023 20:14:20 -0400 Subject: [PATCH 69/74] Ensure Xcode simulator always uses 256B buffer alignment. Xcode simulator always requires 256B buffer alignment, even when running on Apple Silicon. Previously, it was assumed that Apple Silicon would use it's native 16B buffer alignment. --- Docs/Whats_New.md | 3 ++- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 9e0fc42ac..6369370c7 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -28,9 +28,10 @@ Released TBD - Add support for `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN`. - Support building MoltenVK for visionOS. - Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands. -- Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. - Support maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` +- Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. - Add support for `VK_PRESENT_MODE_IMMEDIATE_KHR` to macOS Cube demo. +- Ensure Xcode simulator always uses 256B buffer alignment. - Log more info about SPIR-V to MSL conversion errors. - Drop official support for using *Xcode 11* to build MoltenVK. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 3c77519db..35d4a8eff 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2157,9 +2157,9 @@ #endif } -// iOS and tvOS adjustments necessary when running in the simulator on non-Apple GPUs. -#if MVK_OS_SIMULATOR && !MVK_APPLE_SILICON - _metalFeatures.mtlBufferAlignment = 256; +// iOS and tvOS adjustments necessary when running on the simulator. +#if MVK_OS_SIMULATOR + _metalFeatures.mtlBufferAlignment = 256; // Even on Apple Silicon #endif // Currently, Metal argument buffer support is in beta stage, and is only supported From 4fe88116657fb05e07e84428ea7228353cc482c0 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 15 Aug 2023 16:03:31 -0400 Subject: [PATCH 70/74] Update dependency libraries to match Vulkan SDK 1.3.261. - In MoltenVK Xcode projects, set iOS & tvOS deployment targets to 12.0, to avoid warnings while building MoltenVK. - Add DYLD_LIBRARY_PATH to runcts script, to ensure Vulkan and MoltenVK libraries are found during CTS runs. - Update Whats_New.md and MoltenVK_Runtime_UserGuide.md documents. --- Docs/MoltenVK_Runtime_UserGuide.md | 17 ++++++++++++ Docs/Whats_New.md | 25 ++++++++++++++++-- .../project.pbxproj | 8 +++--- ExternalRevisions/SPIRV-Cross_repo_revision | 2 +- .../Vulkan-Headers_repo_revision | 2 +- ExternalRevisions/Vulkan-Tools_repo_revision | 2 +- ExternalRevisions/glslang_repo_revision | 2 +- MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 12 ++++----- .../project.pbxproj | 8 +++--- Scripts/runcts | 3 +++ Templates/spirv-tools/build.zip | Bin 53948 -> 54542 bytes 11 files changed, 61 insertions(+), 20 deletions(-) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index f2434d10a..f236a7e97 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -32,6 +32,7 @@ Table of Contents - [Performance Considerations](#performance) - [Shader Loading Time](#shader_load_time) - [Swapchains](#swapchains) + - [Timestamping](#timestamping) - [Xcode Configuration](#xcode_config) - [Metal System Trace Tool](#trace_tool) - [Known **MoltenVK** Limitations](#limitations) @@ -327,6 +328,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_KHR_get_surface_capabilities2` - `VK_KHR_imageless_framebuffer` - `VK_KHR_image_format_list` +- `VK_KHR_incremental_present` - `VK_KHR_maintenance1` - `VK_KHR_maintenance2` - `VK_KHR_maintenance3` @@ -369,6 +371,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_metal_objects` - `VK_EXT_metal_surface` - `VK_EXT_pipeline_creation_cache_control` +- `VK_EXT_pipeline_creation_feedback` - `VK_EXT_post_depth_coverage` *(iOS and macOS, requires family 4 (A11) or better Apple GPU)* - `VK_EXT_private_data ` - `VK_EXT_robustness2` @@ -581,6 +584,20 @@ than when using an internal compositor, which increases the risk that a swapchai vailable when you request it, resulting in frame delays and visual stuttering. + +### Timestamping + +On non-Apple Silicon devices (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 +timestamps queried through the Vulkan API. + +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 diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 6a69083d9..68332ce77 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -16,12 +16,14 @@ Copyright (c) 2015-2023 [The Brenwill Workshop Ltd.](http://www.brenwill.com) MoltenVK 1.2.5 -------------- -Released TBD +Released 2023/08/15 - Add support for extensions: + - `VK_KHR_incremental_present` - `VK_KHR_shader_non_semantic_info` - `VK_EXT_4444_formats` - `VK_EXT_calibrated_timestamps` + - `VK_EXT_pipeline_creation_feedback` - `VK_EXT_shader_demote_to_helper_invocation` - `VK_EXT_shader_subgroup_ballot` - `VK_EXT_shader_subgroup_vote` @@ -31,9 +33,29 @@ Released TBD - Support maximizing the concurrent executing compilation tasks via `MVKConfiguration::shouldMaximizeConcurrentCompilation` - Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero. - Add support for `VK_PRESENT_MODE_IMMEDIATE_KHR` to macOS Cube demo. +- Allow both `renderPass` and `VkPipelineRenderingCreateInfo` to be missing. +- Fix sync delay between calls to `vkQueueSubmit()` on non-Apple-Silicon devices. - Ensure Xcode simulator always uses 256B buffer alignment. +- Don't attempt to force the window system to use the same high-power GPU as the app, on every swapchain creation. - Log more info about SPIR-V to MSL conversion errors. +- Implement Deferred Host Operations. +- Support _MSL Version 3.1_. - Drop official support for using *Xcode 11* to build MoltenVK. +- To allow building MoltenVK without an internet connection, don't fetch a submodule if the commit is already known. +- Update dependency libraries to match _Vulkan SDK 1.3.261_. +- Update to latest SPIRV-Cross: + - MSL: Fix argument buffer padding when content includes arrays. + - MSL: ray-query intersection params + - MSL: Support `SPV_KHR_shader_ballot` and `SPV_KHR_subgroup_vote`. + - Skip line directives when emitting loop condition blocks. + - MSL: Consider changed array types for array-of-constant-bool in struct. + - MSL: Consider bool-short remapping for constant expressions as well. + - Minor cleanup in constant_expression(). + - MSL: Add test for bool-in-struct edge cases. + - MSL: Handle more complex array copy scenarios with bool <-> short. + - MSL: Handle stores to struct bool[]. + - MSL: Consider bool/short remapping when dealing with composites. + - MSL: fix function constant deduplication misfire @@ -364,7 +386,6 @@ Released 2022/02/07 - Fix issue where *MSL 2.3* only available on *Apple Silicon*, even on *macOS*. - Fix memory leak of dummy `MTLTexture` in render subpasses that use no attachments. - Fix Metal object retain-release errors in assignment operators. -- Fix sync delay between calls to `vkQueueSubmit()` on non-Apple-Silicon devices. - Fix use of GPU counter sets on older versions of iOS running on the simulator. - `mvk::getShaderOutputs()` in `SPRIVReflection.h` support flattening nested structures. - Replaced ASL logging levels with `MVKConfigLogLevel`. diff --git a/ExternalDependencies.xcodeproj/project.pbxproj b/ExternalDependencies.xcodeproj/project.pbxproj index 8cdb8e767..fdbcf75f2 100644 --- a/ExternalDependencies.xcodeproj/project.pbxproj +++ b/ExternalDependencies.xcodeproj/project.pbxproj @@ -7204,11 +7204,11 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_PARAMETER = YES; GCC_WARN_UNUSED_VARIABLE = NO; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MACH_O_TYPE = staticlib; MACOSX_DEPLOYMENT_TARGET = 10.13; SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 11.0; + TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; }; @@ -7254,11 +7254,11 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_PARAMETER = YES; GCC_WARN_UNUSED_VARIABLE = NO; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MACH_O_TYPE = staticlib; MACOSX_DEPLOYMENT_TARGET = 10.13; SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 11.0; + TVOS_DEPLOYMENT_TARGET = 12.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision index ce73e44aa..590969e2f 100644 --- a/ExternalRevisions/SPIRV-Cross_repo_revision +++ b/ExternalRevisions/SPIRV-Cross_repo_revision @@ -1 +1 @@ -aafcc207ea82308722124db2575aa95f42cb99c9 +bccaa94db814af33d8ef05c153e7c34d8bd4d685 diff --git a/ExternalRevisions/Vulkan-Headers_repo_revision b/ExternalRevisions/Vulkan-Headers_repo_revision index e48127cb9..a8ebecec5 100644 --- a/ExternalRevisions/Vulkan-Headers_repo_revision +++ b/ExternalRevisions/Vulkan-Headers_repo_revision @@ -1 +1 @@ -9e61870ecbd32514113b467e0a0c46f60ed222c7 +85c2334e92e215cce34e8e0ed8b2dce4700f4a50 diff --git a/ExternalRevisions/Vulkan-Tools_repo_revision b/ExternalRevisions/Vulkan-Tools_repo_revision index 4359b342d..bf77fda05 100644 --- a/ExternalRevisions/Vulkan-Tools_repo_revision +++ b/ExternalRevisions/Vulkan-Tools_repo_revision @@ -1 +1 @@ -695887a994ef9cc00a7aa3f9c00b31a56ea79534 +300d9bf6b3cf7b237ee5e2c1d0ae10b9236f82d3 diff --git a/ExternalRevisions/glslang_repo_revision b/ExternalRevisions/glslang_repo_revision index d336b0428..aba7fbb10 100644 --- a/ExternalRevisions/glslang_repo_revision +++ b/ExternalRevisions/glslang_repo_revision @@ -1 +1 @@ -d1517d64cfca91f573af1bf7341dc3a5113349c0 +76b52ebf77833908dc4c0dd6c70a9c357ac720bd diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index c18c9b14c..202efa912 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -478,7 +478,7 @@ DCFD7F4A2A45BC6E007BBBF7 /* MVKRenderPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7941C7DFB4800632CA3 /* MVKRenderPass.mm */; }; DCFD7F4B2A45BC6E007BBBF7 /* MVKCmdTransfer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB76D1C7DFB4800632CA3 /* MVKCmdTransfer.mm */; }; DCFD7F4C2A45BC6E007BBBF7 /* MVKCmdQueries.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7711C7DFB4800632CA3 /* MVKCmdQueries.mm */; }; - DCFD7F4D2A45BC6E007BBBF7 /* vk_mvk_moltenvk.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* vk_mvk_moltenvk.mm */; }; + DCFD7F4D2A45BC6E007BBBF7 /* mvk_api.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7AC1C7DFB4800632CA3 /* mvk_api.mm */; }; DCFD7F4E2A45BC6E007BBBF7 /* MVKSwapchain.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB79C1C7DFB4800632CA3 /* MVKSwapchain.mm */; }; DCFD7F4F2A45BC6E007BBBF7 /* MVKCommandEncoderState.mm in Sources */ = {isa = PBXBuildFile; fileRef = A95B7D681D3EE486003183D3 /* MVKCommandEncoderState.mm */; }; DCFD7F502A45BC6E007BBBF7 /* MVKGPUCapture.mm in Sources */ = {isa = PBXBuildFile; fileRef = A93E83342121F0C8001FEBD4 /* MVKGPUCapture.mm */; }; @@ -1860,7 +1860,7 @@ DCFD7F4A2A45BC6E007BBBF7 /* MVKRenderPass.mm in Sources */, DCFD7F4B2A45BC6E007BBBF7 /* MVKCmdTransfer.mm in Sources */, DCFD7F4C2A45BC6E007BBBF7 /* MVKCmdQueries.mm in Sources */, - DCFD7F4D2A45BC6E007BBBF7 /* vk_mvk_moltenvk.mm in Sources */, + DCFD7F4D2A45BC6E007BBBF7 /* mvk_api.mm in Sources */, DCFD7F4E2A45BC6E007BBBF7 /* MVKSwapchain.mm in Sources */, DCFD7F4F2A45BC6E007BBBF7 /* MVKCommandEncoderState.mm in Sources */, DCFD7F502A45BC6E007BBBF7 /* MVKGPUCapture.mm in Sources */, @@ -2001,7 +2001,7 @@ "\"$(SRCROOT)/../External/cereal/include\"", "\"${BUILT_PRODUCTS_DIR}\"", ); - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MACH_O_TYPE = staticlib; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = YES; @@ -2011,7 +2011,7 @@ PRELINK_LIBS = "${CONFIGURATION_BUILD_DIR}/libMoltenVKShaderConverter.a"; PRODUCT_NAME = MoltenVK; SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 11.0; + TVOS_DEPLOYMENT_TARGET = 12.0; WARNING_CFLAGS = "-Wreorder"; }; name = Debug; @@ -2072,7 +2072,7 @@ "\"$(SRCROOT)/../External/cereal/include\"", "\"${BUILT_PRODUCTS_DIR}\"", ); - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MACH_O_TYPE = staticlib; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = NO; @@ -2082,7 +2082,7 @@ PRELINK_LIBS = "${CONFIGURATION_BUILD_DIR}/libMoltenVKShaderConverter.a"; PRODUCT_NAME = MoltenVK; SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 11.0; + TVOS_DEPLOYMENT_TARGET = 12.0; VALIDATE_PRODUCT = YES; WARNING_CFLAGS = "-Wreorder"; }; diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj index 4b64e66d0..6372955e5 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj +++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj @@ -732,12 +732,12 @@ "\"$(SRCROOT)/glslang\"", "\"$(SRCROOT)/glslang/External/spirv-tools/include\"", ); - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MACH_O_TYPE = staticlib; MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_NAME = MoltenVKShaderConverter; SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 11.0; + TVOS_DEPLOYMENT_TARGET = 12.0; WARNING_CFLAGS = "-Wreorder"; }; name = Debug; @@ -792,12 +792,12 @@ "\"$(SRCROOT)/glslang\"", "\"$(SRCROOT)/glslang/External/spirv-tools/include\"", ); - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MACH_O_TYPE = staticlib; MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_NAME = MoltenVKShaderConverter; SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 11.0; + TVOS_DEPLOYMENT_TARGET = 12.0; VALIDATE_PRODUCT = YES; WARNING_CFLAGS = "-Wreorder"; }; diff --git a/Scripts/runcts b/Scripts/runcts index 8b956422b..20ae1abe5 100755 --- a/Scripts/runcts +++ b/Scripts/runcts @@ -93,6 +93,9 @@ if [ "${is_portability}" != "" ]; then export MVK_CONFIG_ADVERTISE_EXTENSIONS=0xA fi +# ----- System settings ------ +export DYLD_LIBRARY_PATH="/usr/local/lib" + # ----- Metal validation settings ------ export METAL_DEVICE_WRAPPER_TYPE=1 export METAL_ERROR_MODE=3 diff --git a/Templates/spirv-tools/build.zip b/Templates/spirv-tools/build.zip index ee4797c80b3a8674043025bf4afff4bfb9b8082a..3879c9b8368fa5cf774fce1db6774bc26225b43d 100644 GIT binary patch delta 40692 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 delta 40112 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 Date: Thu, 17 Aug 2023 17:47:39 -0400 Subject: [PATCH 71/74] Fix VkPhysicalDeviceLimits::timestampPeriod calculations on Intel GPU. - Guard against Intel returning zero values for CPU & GPU timestamps. - Apply lowpass filter on timestampPeriod updates, to avoid wild temporary changes, particularly at startup before GPU has been really exercised. --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 26 +++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index b4527ae71..0b11d4dfe 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1567,16 +1567,24 @@ return rslt; } -// Mark both CPU and GPU timestamps, and if needed, update the timestamp period for this device. -// On Apple GPUs, the CPU & GPU timestamps are the same, and the timestamp period never changes. +// If needed, update the timestamp period for this device, using a crude lowpass filter to level out +// wild temporary changes, particularly during initial queries before much GPU activity has occurred. +// On Apple GPUs, CPU & GPU timestamps are the same, and timestamp period never changes. void MVKPhysicalDevice::updateTimestampsAndPeriod() { - if (_properties.vendorID == kAppleVendorId) { - _prevGPUTimestamp = _prevCPUTimestamp = mvkGetElapsedNanoseconds(); - } else { - MTLTimestamp earlierCPUTs = _prevCPUTimestamp; - MTLTimestamp earlierGPUTs = _prevGPUTimestamp; - [_mtlDevice sampleTimestamps: &_prevCPUTimestamp gpuTimestamp: &_prevGPUTimestamp]; - _properties.limits.timestampPeriod = (double)(_prevCPUTimestamp - earlierCPUTs) / (double)(_prevGPUTimestamp - earlierGPUTs); + if (_properties.vendorID == kAppleVendorId) { return; } + + MTLTimestamp earlierCPUTs = _prevCPUTimestamp; + MTLTimestamp earlierGPUTs = _prevGPUTimestamp; + [_mtlDevice sampleTimestamps: &_prevCPUTimestamp gpuTimestamp: &_prevGPUTimestamp]; + double elapsedCPUNanos = _prevCPUTimestamp - earlierCPUTs; + double elapsedGPUTicks = _prevGPUTimestamp - earlierGPUTs; + if (elapsedCPUNanos && elapsedGPUTicks) { // Ensure not zero + float tsPeriod = elapsedCPUNanos / elapsedGPUTicks; + + // Basic lowpass filter Y = (1 - a)Y + a*X. + // The lower a is, the slower Y will change over time. + static const float a = 0.05; + _properties.limits.timestampPeriod = ((1.0 - a) * _properties.limits.timestampPeriod) + (a * tsPeriod); } } From 7910083ffae7ca9d638c5bdc0c36ad71335e79de Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 23 Aug 2023 14:14:15 -0400 Subject: [PATCH 72/74] Fix rare case where vertex attribute buffers are not bound to Metal. In the rare case where vertex attribute buffers are bound to MVKCommandEncoder, are not used by first pipeline, but are used by a subsequent pipeline, and no other bindings are changed, the MVKResourcesCommandEncoderState will not appear to be dirty to the second pipeline, and the buffer will not be bound to Metal. When reverting a binding to dirty if it is not used by a pipeline, also revert the enclosing MVKResourcesCommandEncoderState to dirty state. Update MoltenVK to version 1.2.6 (unrelated). --- Docs/Whats_New.md | 10 ++++++++++ MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 68332ce77..82e9b1558 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -13,6 +13,16 @@ Copyright (c) 2015-2023 [The Brenwill Workshop Ltd.](http://www.brenwill.com) +MoltenVK 1.2.6 +-------------- + +Released TBD + +- Fix rare case where vertex attribute buffers are not bound to Metal + when no other bindings change between pipelines. + + + MoltenVK 1.2.5 -------------- diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index d8cf26ca5..06152dd7a 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -81,6 +81,8 @@ class MVKCommandEncoderState : public MVKBaseObject { /** * If the content of this instance is dirty, marks this instance as no longer dirty * and calls the encodeImpl() function to encode the content onto the Metal encoder. + * Marking dirty is done in advance so that subclass encodeImpl() implementations + * can override to leave this instance in a dirty state. * Subclasses must override the encodeImpl() function to do the actual work. */ void encode(uint32_t stage = 0) { @@ -430,7 +432,8 @@ class MVKResourcesCommandEncoderState : public MVKCommandEncoderState { // Template function that executes a lambda expression on each dirty element of // a vector of bindings, and marks the bindings and the vector as no longer dirty. - // Clear isDirty flag before operation to allow operation to possibly override. + // Clear binding isDirty flag before operation to allow operation to possibly override. + // If it does override, leave both the bindings and this instance as dirty. template void encodeBinding(V& bindings, bool& bindingsDirtyFlag, @@ -441,7 +444,7 @@ class MVKResourcesCommandEncoderState : public MVKCommandEncoderState { if (b.isDirty) { b.isDirty = false; mtlOperation(_cmdEncoder, b); - if (b.isDirty) { bindingsDirtyFlag = true; } + if (b.isDirty) { _isDirty = bindingsDirtyFlag = true; } } } } From 4544e76b265ce2aae80c086111c90456c40505fe Mon Sep 17 00:00:00 2001 From: Jan Sikorski Date: Fri, 8 Sep 2023 10:36:30 +0200 Subject: [PATCH 73/74] Implement geometry shaders using mesh pipelines. --- ExternalRevisions/SPIRV-Cross_repo_revision | 2 +- MoltenVK/MoltenVK/API/mvk_datatypes.h | 1 + MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm | 69 +++ MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm | 1 + MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h | 1 + .../MoltenVK/Commands/MVKCommandBuffer.mm | 8 +- .../Commands/MVKCommandEncoderState.h | 6 +- .../Commands/MVKCommandEncoderState.mm | 121 ++++- MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm | 10 +- .../MoltenVK/GPUObjects/MVKDescriptorSet.mm | 21 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 1 + MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 3 + MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 40 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 460 ++++++++++++++---- .../OS/MTLRenderPipelineDescriptor+MoltenVK.h | 10 + .../OS/MTLRenderPipelineDescriptor+MoltenVK.m | 15 + MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 4 +- .../SPIRVToMSLConverter.cpp | 48 +- 18 files changed, 654 insertions(+), 167 deletions(-) diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision index 590969e2f..05bf0fae3 100644 --- a/ExternalRevisions/SPIRV-Cross_repo_revision +++ b/ExternalRevisions/SPIRV-Cross_repo_revision @@ -1 +1 @@ -bccaa94db814af33d8ef05c153e7c34d8bd4d685 +7a1e3e7586b9b10a6286cad912940b7a501e93ea diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h index b0e2dac7c..a7098288f 100644 --- a/MoltenVK/MoltenVK/API/mvk_datatypes.h +++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h @@ -327,6 +327,7 @@ typedef enum { kMVKShaderStageVertex = 0, kMVKShaderStageTessCtl, kMVKShaderStageTessEval, + kMVKShaderStageGeometry, kMVKShaderStageFragment, kMVKShaderStageCompute, kMVKShaderStageCount, diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm index 20d278151..56750d23d 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm @@ -79,6 +79,14 @@ cmdEncoder->_graphicsResourcesState.bindIndexBuffer(_binding); } +#pragma mark - + +/* Describes the draw parameters for mesh pipelines. */ +struct DrawInfo { + int32_t indexed; + int32_t indexSize; + uint64_t indexBuffer; +}; #pragma mark - #pragma mark MVKCmdDraw @@ -290,6 +298,28 @@ cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass(); +#if MVK_XCODE_14 + } else if (pipeline->isGeometryPipeline()) { + DrawInfo drawInfo = {}; + drawInfo.indexed = false; + + [cmdEncoder->_mtlRenderEncoder setObjectBytes: &drawInfo length: sizeof(drawInfo) atIndex: pipeline->getDrawInfoBufferIndex()]; + + int threadCount = 0; + if (cmdEncoder->_mtlPrimitiveType == MTLPrimitiveTypeTriangle) + threadCount = _vertexCount / 3; + else if (cmdEncoder->_mtlPrimitiveType == MTLPrimitiveTypeTriangleStrip) + threadCount = _vertexCount - 2; + else + reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "Unsupported primitive type: %lu", cmdEncoder->_mtlPrimitiveType); + + if (_firstVertex) reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "First vertex not supported yet."); + if (_firstInstance) reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "First instance not supported yet."); + + [cmdEncoder->_mtlRenderEncoder drawMeshThreadgroups: MTLSizeMake(threadCount, _instanceCount, 1) + threadsPerObjectThreadgroup: MTLSizeMake(1, 1, 1) + threadsPerMeshThreadgroup: MTLSizeMake(1, 1, 1)]; +#endif } else { MVKRenderSubpass* subpass = cmdEncoder->getSubpass(); uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1; @@ -524,6 +554,31 @@ cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass(); +#if MVK_XCODE_14 + } else if (pipeline->isGeometryPipeline()) { + DrawInfo drawInfo = {}; + drawInfo.indexed = true; + drawInfo.indexSize = (int)idxSize; + drawInfo.indexBuffer = ibb.mtlBuffer.gpuAddress + idxBuffOffset; + + [cmdEncoder->_mtlRenderEncoder useResource: ibb.mtlBuffer usage: MTLResourceUsageRead stages: MTLRenderStageObject]; + [cmdEncoder->_mtlRenderEncoder setObjectBytes: &drawInfo length: sizeof(drawInfo) atIndex: pipeline->getDrawInfoBufferIndex()]; + + int threadCount = 0; + if (cmdEncoder->_mtlPrimitiveType == MTLPrimitiveTypeTriangle) + threadCount = _indexCount / 3; + else if (cmdEncoder->_mtlPrimitiveType == MTLPrimitiveTypeTriangleStrip) + threadCount = _indexCount - 2; + else + reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "Unsupported primitive type %lu.", cmdEncoder->_mtlPrimitiveType); + + if (_vertexOffset) reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "Vertex offset not supported yet."); + if (_firstInstance) reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "First instance not supported yet."); + + [cmdEncoder->_mtlRenderEncoder drawMeshThreadgroups:MTLSizeMake(threadCount, _instanceCount, 1) + threadsPerObjectThreadgroup:MTLSizeMake(1, 1, 1) + threadsPerMeshThreadgroup:MTLSizeMake(1, 1, 1)]; +#endif } else { MVKRenderSubpass* subpass = cmdEncoder->getSubpass(); uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1; @@ -648,6 +703,13 @@ auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); +#if MVK_XCODE_14 + if (pipeline->isGeometryPipeline()) { + reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "CmdDrawIndirect with geometry shader is not yet supported."); + return; + } +#endif + // Metal doesn't support triangle fans, so encode it as indexed indirect triangles instead. if (pipeline->getVkPrimitiveTopology() == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { encodeIndexedIndirect(cmdEncoder); @@ -998,6 +1060,13 @@ MVKIndexMTLBufferBinding ibbTriFan = ibb; auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); +#if MVK_XCODE_14 + if (pipeline->isGeometryPipeline()) { + reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "CmdDrawIndexedIndirect with geometry shader is not yet supported."); + return; + } +#endif + MVKVertexAdjustments vtxAdjmts; vtxAdjmts.mtlIndexType = ibb.mtlIndexType; vtxAdjmts.isMultiView = (cmdEncoder->getSubpass()->isMultiview() && diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm index 3efcab53c..5b44bef1f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm @@ -312,6 +312,7 @@ VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, + VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_COMPUTE_BIT }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 76274dad8..90082966f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -521,6 +521,7 @@ class MVKCommandEncoder : public MVKBaseDeviceObject { MVKPushConstantsCommandEncoderState _tessEvalPushConstants; MVKPushConstantsCommandEncoderState _fragmentPushConstants; MVKPushConstantsCommandEncoderState _computePushConstants; + MVKPushConstantsCommandEncoderState _geometryPushConstants; MVKOcclusionQueryCommandEncoderState _occlusionQueryState; MVKPrefillMetalCommandBuffersStyle _prefillStyle; VkSubpassContents _subpassContents; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 5edc13aaa..0832b6954 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -901,6 +901,7 @@ case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return &_tessEvalPushConstants; case VK_SHADER_STAGE_FRAGMENT_BIT: return &_fragmentPushConstants; case VK_SHADER_STAGE_COMPUTE_BIT: return &_computePushConstants; + case VK_SHADER_STAGE_GEOMETRY_BIT: return &_geometryPushConstants; default: MVKAssert(false, "Invalid shader stage: %u", shaderStage); return nullptr; @@ -1124,8 +1125,8 @@ MVKCommandEncoder::MVKCommandEncoder(MVKCommandBuffer* cmdBuffer, MVKPrefillMetalCommandBuffersStyle prefillStyle) : MVKBaseDeviceObject(cmdBuffer->getDevice()), _cmdBuffer(cmdBuffer), - _graphicsPipelineState(this), - _computePipelineState(this), + _graphicsPipelineState(this, VK_PIPELINE_BIND_POINT_GRAPHICS), + _computePipelineState(this, VK_PIPELINE_BIND_POINT_COMPUTE), _viewportState(this), _scissorState(this), _depthBiasState(this), @@ -1139,8 +1140,9 @@ _tessEvalPushConstants(this, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), _fragmentPushConstants(this, VK_SHADER_STAGE_FRAGMENT_BIT), _computePushConstants(this, VK_SHADER_STAGE_COMPUTE_BIT), + _geometryPushConstants(this, VK_SHADER_STAGE_GEOMETRY_BIT), _occlusionQueryState(this), - _prefillStyle(prefillStyle){ + _prefillStyle(prefillStyle){ _pDeviceFeatures = &_device->_enabledFeatures; _pDeviceMetalFeatures = _device->_pMetalFeatures; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 06152dd7a..53bc543b0 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -120,13 +120,14 @@ class MVKPipelineCommandEncoderState : public MVKCommandEncoderState { MVKPipeline* getPipeline(); /** Constructs this instance for the specified command encoder. */ - MVKPipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder) - : MVKCommandEncoderState(cmdEncoder) {} + MVKPipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder, VkPipelineBindPoint bindPoint) + : MVKCommandEncoderState(cmdEncoder), _bindPoint(bindPoint) {} protected: void encodeImpl(uint32_t stage) override; MVKPipeline* _pipeline = nullptr; + VkPipelineBindPoint _bindPoint; }; @@ -571,6 +572,7 @@ class MVKGraphicsResourcesCommandEncoderState : public MVKResourcesCommandEncode void endMetalRenderPass() override; void markDirty() override; + void markDirty(MVKShaderStage stage); #pragma mark Construction diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index 044dd96e3..078f35756 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -22,6 +22,7 @@ #include "MVKRenderPass.h" #include "MVKPipeline.h" #include "MVKQueryPool.h" +#include "MVKBuffer.h" using namespace std; @@ -37,8 +38,18 @@ #pragma mark MVKPipelineCommandEncoderState void MVKPipelineCommandEncoderState::bindPipeline(MVKPipeline* pipeline) { - if (pipeline != _pipeline) markDirty(); - _pipeline = pipeline; + if (pipeline != _pipeline) { + markDirty(); + if (_bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS) { + bool beforeGS = _pipeline && static_cast(_pipeline)->isGeometryPipeline(); + bool afterGS = pipeline && static_cast(pipeline)->isGeometryPipeline(); + // GS and VS use different bind points for vertex bindings (GS uses object shader, VS uses vertex shader) + // So we need to rebind everything if it changes + if (beforeGS != afterGS) + _cmdEncoder->_graphicsResourcesState.markDirty(kMVKShaderStageVertex); + } + } + _pipeline = pipeline; } MVKPipeline* MVKPipelineCommandEncoderState::getPipeline() { return _pipeline; } @@ -765,11 +776,15 @@ // Mark everything as dirty void MVKGraphicsResourcesCommandEncoderState::markDirty() { MVKResourcesCommandEncoderState::markDirty(); - for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) { - MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].bufferBindings, _shaderStageResourceBindings[i].areBufferBindingsDirty); - MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].textureBindings, _shaderStageResourceBindings[i].areTextureBindingsDirty); - MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].samplerStateBindings, _shaderStageResourceBindings[i].areSamplerStateBindingsDirty); - } + for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) { + markDirty(static_cast(i)); + } +} + +void MVKGraphicsResourcesCommandEncoderState::markDirty(MVKShaderStage stage) { + MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[stage].bufferBindings, _shaderStageResourceBindings[stage].areBufferBindingsDirty); + MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[stage].textureBindings, _shaderStageResourceBindings[stage].areTextureBindingsDirty); + MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[stage].samplerStateBindings, _shaderStageResourceBindings[stage].areSamplerStateBindingsDirty); } void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { @@ -811,8 +826,51 @@ }); } else if (!forTessellation && stage == kMVKGraphicsStageRasterization) { +#if MVK_XCODE_14 + if (pipeline->isGeometryPipeline()) { + encodeBindings(kMVKShaderStageGeometry, "geometry", fullImageViewSwizzle, + [pipeline](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { + if (b.isInline) + [cmdEncoder->_mtlRenderEncoder setMeshBytes: b.mtlBytes + length: b.size + atIndex: b.index]; + else + [cmdEncoder->_mtlRenderEncoder setMeshBuffer: b.mtlBuffer + offset: b.offset + atIndex: b.index]; + }, + [pipeline](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef s)->void { + [cmdEncoder->_mtlRenderEncoder setMeshBytes: s.data + length: s.size * sizeof(uint32_t) + atIndex: b.index]; + }, + [](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void { + [cmdEncoder->_mtlRenderEncoder setMeshTexture: b.mtlTexture + atIndex: b.index]; + }, + [](MVKCommandEncoder* cmdEncoder, MVKMTLSamplerStateBinding& b)->void { + [cmdEncoder->_mtlRenderEncoder setMeshSamplerState: b.mtlSamplerState + atIndex: b.index]; + }); + } +#endif encodeBindings(kMVKShaderStageVertex, "vertex", fullImageViewSwizzle, [pipeline](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { +#if MVK_XCODE_14 + if (pipeline->isGeometryPipeline()) { + if (b.isInline) + [cmdEncoder->_mtlRenderEncoder setObjectBytes: b.mtlBytes + length: b.size + atIndex: b.index]; + else + [cmdEncoder->_mtlRenderEncoder setObjectBuffer: b.mtlBuffer + offset: b.offset + atIndex: b.index]; + + return; + } +#endif + // The app may have bound more vertex attribute buffers than used by the pipeline. // We must not bind those extra buffers to the shader because they might overwrite // any implicit buffers used by the pipeline. @@ -846,19 +904,46 @@ b.isDirty = true; // We haven't written it out, so leave dirty until next time. } }, - [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef s)->void { - cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, - s.data, - s.size * sizeof(uint32_t), - b.index); + [pipeline](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef s)->void { +#if MVK_XCODE_14 + if (pipeline->isGeometryPipeline()) { + [cmdEncoder->_mtlRenderEncoder setObjectBytes: s.data + length: s.size * sizeof(uint32_t) + atIndex: b.index]; + } else +#endif + { + if (b.isInline) + cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, s.data, s.size * sizeof(uint32_t), b.index); + else + [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer + offset: b.offset + atIndex: b.index]; + } }, - [](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void { - [cmdEncoder->_mtlRenderEncoder setVertexTexture: b.mtlTexture - atIndex: b.index]; + [pipeline](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void { +#if MVK_XCODE_14 + if (pipeline->isGeometryPipeline()) { + [cmdEncoder->_mtlRenderEncoder setObjectTexture: b.mtlTexture + atIndex: b.index]; + } else +#endif + { + [cmdEncoder->_mtlRenderEncoder setVertexTexture: b.mtlTexture + atIndex: b.index]; + } }, - [](MVKCommandEncoder* cmdEncoder, MVKMTLSamplerStateBinding& b)->void { - [cmdEncoder->_mtlRenderEncoder setVertexSamplerState: b.mtlSamplerState - atIndex: b.index]; + [pipeline](MVKCommandEncoder* cmdEncoder, MVKMTLSamplerStateBinding& b)->void { +#if MVK_XCODE_14 + if (pipeline->isGeometryPipeline()) { + [cmdEncoder->_mtlRenderEncoder setObjectSamplerState: b.mtlSamplerState + atIndex: b.index]; + } else +#endif + { + [cmdEncoder->_mtlRenderEncoder setVertexSamplerState: b.mtlSamplerState + atIndex: b.index]; + } }); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm index a3f02ea89..556defa3f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm @@ -134,6 +134,7 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s spv::ExecutionModelVertex, spv::ExecutionModelTessellationControl, spv::ExecutionModelTessellationEvaluation, + spv::ExecutionModelGeometry, spv::ExecutionModelFragment, spv::ExecutionModelGLCompute }; @@ -526,8 +527,15 @@ void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& s case kMVKShaderStageTessCtl: case kMVKShaderStageTessEval: mtlStages |= MTLRenderStageVertex; +#if MVK_XCODE_14 + mtlStages |= MTLRenderStageObject; +#endif break; - +#if MVK_XCODE_14 + case kMVKShaderStageGeometry: + mtlStages |= MTLRenderStageMesh; + break; +#endif case kMVKShaderStageFragment: mtlStages |= MTLRenderStageFragment; break; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm index 1406ab179..ff5f0a4f4 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm @@ -185,24 +185,29 @@ } } +static const spv::ExecutionModel getExecModel(MVKShaderStage stage) { + switch (stage) { + case kMVKShaderStageVertex: return spv::ExecutionModelVertex; + case kMVKShaderStageTessCtl: return spv::ExecutionModelTessellationControl; + case kMVKShaderStageTessEval: return spv::ExecutionModelTessellationEvaluation; + case kMVKShaderStageGeometry: return spv::ExecutionModelGeometry; + case kMVKShaderStageFragment: return spv::ExecutionModelFragment; + case kMVKShaderStageCompute: return spv::ExecutionModelGLCompute; + case kMVKShaderStageCount: assert(0); __builtin_unreachable(); + } +} + bool MVKDescriptorSetLayout::populateBindingUse(MVKBitArray& bindingUse, SPIRVToMSLConversionConfiguration& context, MVKShaderStage stage, uint32_t descSetIndex) { - static const spv::ExecutionModel spvExecModels[] = { - spv::ExecutionModelVertex, - spv::ExecutionModelTessellationControl, - spv::ExecutionModelTessellationEvaluation, - spv::ExecutionModelFragment, - spv::ExecutionModelGLCompute - }; bool descSetIsUsed = false; uint32_t bindCnt = (uint32_t)_bindings.size(); bindingUse.resize(bindCnt); for (uint32_t bindIdx = 0; bindIdx < bindCnt; bindIdx++) { auto& dslBind = _bindings[bindIdx]; - if (context.isResourceUsed(spvExecModels[stage], descSetIndex, dslBind.getBinding())) { + if (context.isResourceUsed(getExecModel(stage), descSetIndex, dslBind.getBinding())) { bindingUse.setBit(bindIdx); descSetIsUsed = true; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 0b11d4dfe..769a1d79d 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2231,6 +2231,7 @@ _features.shaderInt16 = true; _features.multiDrawIndirect = true; _features.inheritedQueries = true; + _features.geometryShader = true; _features.shaderSampledImageArrayDynamicIndexing = _metalFeatures.arrayOfTextures; _features.textureCompressionBC = mvkSupportsBCTextureCompression(_mtlDevice); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 148702215..7db141221 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -934,6 +934,9 @@ (_hasMutableFormat && pixFmts->getViewClass(_vkFormat) == MVKMTLViewClass::Color32 && (getIsValidViewFormat(VK_FORMAT_R32_UINT) || getIsValidViewFormat(VK_FORMAT_R32_SINT))))); + if (mvkIsAnyFlagEnabled(getCombinedUsage(), VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) && !getDevice()->getPhysicalDevice()->getMetalFeatures()->renderLinearTextures) + _isLinearForAtomics = false; + _is3DCompressed = (getImageType() == VK_IMAGE_TYPE_3D) && (pixFmts->getFormatType(pCreateInfo->format) == kMVKFormatCompressed) && !_device->_pMetalFeatures->native3DCompressedTextures; _isDepthStencilAttachment = (mvkAreAllFlagsEnabled(pCreateInfo->usage, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) || mvkAreAllFlagsEnabled(pixFmts->getVkFormatProperties(pCreateInfo->format).optimalTilingFeatures, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 505e894c1..0cd3ccd60 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -208,14 +208,16 @@ struct MVKTranslatedVertexBinding { /** Describes a vertex buffer binding whose divisor is zero. */ typedef std::pair MVKZeroDivisorVertexBinding; -typedef MVKSmallVector MVKPiplineStages; +static constexpr uint32_t kMVKNumGraphicsShaderStages = kMVKShaderStageCompute; + +typedef MVKSmallVector MVKPiplineStages; struct MVKStagedMTLArgumentEncoders { - MVKMTLArgumentEncoder stages[4] = {}; + MVKMTLArgumentEncoder stages[kMVKNumGraphicsShaderStages] = {}; }; struct MVKStagedDescriptorBindingUse { - MVKBitArray stages[4] = {}; + MVKBitArray stages[kMVKNumGraphicsShaderStages] = {}; }; /** Represents an Vulkan graphics pipeline. */ @@ -235,6 +237,9 @@ class MVKGraphicsPipeline : public MVKPipeline { /** Returns whether this pipeline has tessellation shaders. */ bool isTessellationPipeline() { return _tessInfo.patchControlPoints > 0; } + /** Returns whether this pipeline has geometry shaders. */ + bool isGeometryPipeline() { return _isGeometryPipeline; } + /** Returns the number of input tessellation patch control points. */ uint32_t getInputControlPointCount() { return _tessInfo.patchControlPoints; } @@ -274,6 +279,9 @@ class MVKGraphicsPipeline : public MVKPipeline { /** Returns whether this pipeline has custom sample positions enabled. */ bool isUsingCustomSamplePositions() { return _isUsingCustomSamplePositions; } + /** Returns the current draw info buffer binding for the mesh shader. */ + uint32_t getDrawInfoBufferIndex() { return _meshDrawInfoBufferIndex; } + /** Returns the Vulkan primitive topology. */ VkPrimitiveTopology getVkPrimitiveTopology() { return _vkPrimitiveTopology; } @@ -317,17 +325,23 @@ class MVKGraphicsPipeline : public MVKPipeline { typedef MVKSmallVector SPIRVShaderInputs; id getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id& plState); +#if MVK_XCODE_14 + id getOrCompilePipeline(MTLMeshRenderPipelineDescriptor* plDesc, id& plState); +#endif id getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id& plState, const char* compilerType); bool compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, MVKMTLFunction* pVtxFunctions, VkPipelineCreationFeedback* pVertexFB); bool compileTessControlStageState(MTLComputePipelineDescriptor* tcPLDesc, VkPipelineCreationFeedback* pTessCtlFB); void initCustomSamplePositions(const VkGraphicsPipelineCreateInfo* pCreateInfo); - void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, VkPipelineCreationFeedback* pPipelineFB, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); + void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, VkPipelineCreationFeedback* pPipelineFB, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pGeometrySS, VkPipelineCreationFeedback* pGeometryFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); void initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData); void initReservedVertexAttributeBufferCount(const VkGraphicsPipelineCreateInfo* pCreateInfo); void addVertexInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo); void addNextStageInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& inputs); void addPrevStageOutputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& outputs); MTLRenderPipelineDescriptor* newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); +#if MVK_XCODE_14 + MTLMeshRenderPipelineDescriptor* newMTLMeshRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pGeometrySS, VkPipelineCreationFeedback* pGeometryFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); +#endif MTLComputePipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, MVKMTLFunction* pVtxFunctions); MTLComputePipelineDescriptor* newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pVertexSS, const VkPipelineShaderStageCreateInfo* pTessEvalSS); MTLRenderPipelineDescriptor* newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS); @@ -335,12 +349,19 @@ class MVKGraphicsPipeline : public MVKPipeline { bool addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderInputs& nextInputs, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, MVKMTLFunction* pVtxFunctions); bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, SPIRVShaderInputs& nextInputs, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB); bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo*& pFragmentSS); - bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); +#if MVK_XCODE_14 + bool addPreRasterShadersToPipeline(MTLMeshRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pGeometrySS, VkPipelineCreationFeedback* pGeometryFB); + bool addVertexShaderToPipeline(MTLMeshRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB); + bool addGeometryShaderToPipeline(MTLMeshRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, const VkPipelineShaderStageCreateInfo* pGeometrySS, VkPipelineCreationFeedback* pGeometryFB, SPIRVShaderOutputs &vertexOutputs); +#endif + template + bool addFragmentShaderToPipeline(T* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& prevOutput, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); template bool addVertexInputToPipeline(T* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, const SPIRVToMSLConversionConfiguration& shaderConfig); void adjustVertexInputForMultiview(MTLVertexDescriptor* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, uint32_t viewCount, uint32_t oldViewCount = 1); void addTessellationToPipeline(MTLRenderPipelineDescriptor* plDesc, const SPIRVTessReflectionData& reflectData, const VkPipelineTessellationStateCreateInfo* pTS); - void addFragmentOutputToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo); + template + void addFragmentOutputToPipeline(T* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo); bool isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo); bool isRasterizationDisabled(const VkGraphicsPipelineCreateInfo* pCreateInfo); bool verifyImplicitBuffer(bool needsBuffer, MVKShaderImplicitRezBinding& index, MVKShaderStage stage, const char* name); @@ -379,6 +400,7 @@ class MVKGraphicsPipeline : public MVKPipeline { MTLWinding _mtlFrontWinding; MTLTriangleFillMode _mtlFillMode; MTLDepthClipMode _mtlDepthClipMode; + MTLPrimitiveType _mtlPrimitiveType; MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount; MVKShaderImplicitRezBinding _viewRangeBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex; @@ -386,6 +408,7 @@ class MVKGraphicsPipeline : public MVKPipeline { uint32_t _outputControlPointCount; uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0; + uint32_t _meshDrawInfoBufferIndex = 20; bool _needsVertexSwizzleBuffer = false; bool _needsVertexBufferSizeBuffer = false; @@ -408,6 +431,7 @@ class MVKGraphicsPipeline : public MVKPipeline { bool _isRasterizing = false; bool _isRasterizingColor = false; bool _isUsingCustomSamplePositions = false; + bool _isGeometryPipeline = false; }; @@ -540,7 +564,9 @@ class MVKRenderPipelineCompiler : public MVKMetalCompiler { * nanoseconds, an error will be generated and logged, and nil will be returned. */ id newMTLRenderPipelineState(MTLRenderPipelineDescriptor* mtlRPLDesc); - +#if MVK_XCODE_14 + id newMTLRenderPipelineState(MTLMeshRenderPipelineDescriptor* mtlRPLDesc); +#endif #pragma mark Construction diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 13f59b6bc..f26dab6f2 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -449,11 +449,13 @@ const VkPipelineShaderStageCreateInfo* pVertexSS = nullptr; const VkPipelineShaderStageCreateInfo* pTessCtlSS = nullptr; const VkPipelineShaderStageCreateInfo* pTessEvalSS = nullptr; - const VkPipelineShaderStageCreateInfo* pFragmentSS = nullptr; + const VkPipelineShaderStageCreateInfo* pFragmentSS = nullptr; + const VkPipelineShaderStageCreateInfo* pGeometrySS = nullptr; VkPipelineCreationFeedback* pVertexFB = nullptr; VkPipelineCreationFeedback* pTessCtlFB = nullptr; VkPipelineCreationFeedback* pTessEvalFB = nullptr; VkPipelineCreationFeedback* pFragmentFB = nullptr; + VkPipelineCreationFeedback* pGeometryFB = nullptr; for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { const auto* pSS = &pCreateInfo->pStages[i]; switch (pSS->stage) { @@ -481,6 +483,17 @@ pFragmentFB = &pFeedbackInfo->pPipelineStageCreationFeedbacks[i]; } break; + case VK_SHADER_STAGE_GEOMETRY_BIT: +#if MVK_XCODE_14 + if (getDevice()->getPhysicalDevice()->mslVersionIsAtLeast(MTLLanguageVersion3_0)) { + pGeometrySS = pSS; + _isGeometryPipeline = true; + if (pFeedbackInfo && pFeedbackInfo->pPipelineStageCreationFeedbacks) { + pGeometryFB = &pFeedbackInfo->pPipelineStageCreationFeedbacks[i]; + } + } +#endif + break; default: break; } @@ -505,8 +518,19 @@ _outputControlPointCount = reflectData.numControlPoints; mvkSetOrClear(&_tessInfo, (pTessCtlSS && pTessEvalSS) ? pCreateInfo->pTessellationState : nullptr); + // Topology + _mtlPrimitiveType = MTLPrimitiveTypePoint; + if (pCreateInfo->pInputAssemblyState && !isRenderingPoints(pCreateInfo)) { + _mtlPrimitiveType = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(pCreateInfo->pInputAssemblyState->topology); + // Explicitly fail creation with triangle fan topology. + if (pCreateInfo->pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { + setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support triangle fans.")); + return; + } + } + // Render pipeline state. Do this as early as possible, to fail fast if pipeline requires a fail on cache-miss. - initMTLRenderPipelineState(pCreateInfo, reflectData, pPipelineFB, pVertexSS, pVertexFB, pTessCtlSS, pTessCtlFB, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB); + initMTLRenderPipelineState(pCreateInfo, reflectData, pPipelineFB, pVertexSS, pVertexFB, pTessCtlSS, pTessCtlFB, pTessEvalSS, pTessEvalFB, pGeometrySS, pGeometryFB, pFragmentSS, pFragmentFB); if ( !_hasValidMTLPipelineStates ) { return; } // Track dynamic state @@ -589,6 +613,20 @@ return plState; } +#if MVK_XCODE_14 +// Either returns an existing pipeline state or compiles a new one. +id MVKGraphicsPipeline::getOrCompilePipeline(MTLMeshRenderPipelineDescriptor* plDesc, + id& plState) { + if ( !plState ) { + MVKRenderPipelineCompiler* plc = new MVKRenderPipelineCompiler(this); + plState = plc->newMTLRenderPipelineState(plDesc); // retained + plc->destroy(); + if ( !plState ) { _hasValidMTLPipelineStates = false; } + } + return plState; +} +#endif + // Either returns an existing pipeline state or compiles a new one. id MVKGraphicsPipeline::getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id& plState, @@ -637,6 +675,8 @@ VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, + const VkPipelineShaderStageCreateInfo* pGeometrySS, + VkPipelineCreationFeedback* pGeometryFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB) { _mtlTessVertexStageState = nil; @@ -653,8 +693,37 @@ if (isUsingMetalArgumentBuffers()) { _descriptorBindingUse.resize(_descriptorSetCount); } if (isUsingPipelineStageMetalArgumentBuffers()) { _mtlArgumentEncoders.resize(_descriptorSetCount); } - if (!isTessellationPipeline()) { - MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData, pVertexSS, pVertexFB, pFragmentSS, pFragmentFB); // temp retain + if (isTessellationPipeline()) { + // In this case, we need to create three render pipelines. But, the way Metal handles + // index buffers for compute stage-in means we have to create three pipelines for + // stage 1 (five pipelines in total). + SPIRVToMSLConversionConfiguration shaderConfig; + initShaderConversionConfig(shaderConfig, pCreateInfo, reflectData); + + MVKMTLFunction vtxFunctions[3] = {}; + MTLComputePipelineDescriptor* vtxPLDesc = newMTLTessVertexStageDescriptor(pCreateInfo, reflectData, shaderConfig, pVertexSS, pVertexFB, pTessCtlSS, vtxFunctions); // temp retained + MTLComputePipelineDescriptor* tcPLDesc = newMTLTessControlStageDescriptor(pCreateInfo, reflectData, shaderConfig, pTessCtlSS, pTessCtlFB, pVertexSS, pTessEvalSS); // temp retained + MTLRenderPipelineDescriptor* rastPLDesc = newMTLTessRasterStageDescriptor(pCreateInfo, reflectData, shaderConfig, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB, pTessCtlSS); // temp retained + if (vtxPLDesc && tcPLDesc && rastPLDesc) { + if (compileTessVertexStageState(vtxPLDesc, vtxFunctions, pVertexFB)) { + if (compileTessControlStageState(tcPLDesc, pTessCtlFB)) { + getOrCompilePipeline(rastPLDesc, _mtlPipelineState); + } + } + } else { + _hasValidMTLPipelineStates = false; + } + [vtxPLDesc release]; // temp release + [tcPLDesc release]; // temp release + [rastPLDesc release]; // temp release +#if MVK_XCODE_14 + } else if (isGeometryPipeline()) { + MTLMeshRenderPipelineDescriptor* plDesc = newMTLMeshRenderPipelineDescriptor(pCreateInfo, reflectData, pVertexSS, pVertexFB, pGeometrySS, pGeometryFB, pFragmentSS, pFragmentFB); // temp retain + if (plDesc) getOrCompilePipeline(plDesc, _mtlPipelineState); + [plDesc release]; // temp release +#endif + } else { + MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData, pVertexSS, pVertexFB, pFragmentSS, pFragmentFB); // temp retain if (plDesc) { const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); if (pRendInfo && mvkIsMultiview(pRendInfo->viewMask)) { @@ -688,29 +757,6 @@ } else { _hasValidMTLPipelineStates = false; } - } else { - // In this case, we need to create three render pipelines. But, the way Metal handles - // index buffers for compute stage-in means we have to create three pipelines for - // stage 1 (five pipelines in total). - SPIRVToMSLConversionConfiguration shaderConfig; - initShaderConversionConfig(shaderConfig, pCreateInfo, reflectData); - - MVKMTLFunction vtxFunctions[3] = {}; - MTLComputePipelineDescriptor* vtxPLDesc = newMTLTessVertexStageDescriptor(pCreateInfo, reflectData, shaderConfig, pVertexSS, pVertexFB, pTessCtlSS, vtxFunctions); // temp retained - MTLComputePipelineDescriptor* tcPLDesc = newMTLTessControlStageDescriptor(pCreateInfo, reflectData, shaderConfig, pTessCtlSS, pTessCtlFB, pVertexSS, pTessEvalSS); // temp retained - MTLRenderPipelineDescriptor* rastPLDesc = newMTLTessRasterStageDescriptor(pCreateInfo, reflectData, shaderConfig, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB, pTessCtlSS); // temp retained - if (vtxPLDesc && tcPLDesc && rastPLDesc) { - if (compileTessVertexStageState(vtxPLDesc, vtxFunctions, pVertexFB)) { - if (compileTessControlStageState(tcPLDesc, pTessCtlFB)) { - getOrCompilePipeline(rastPLDesc, _mtlPipelineState); - } - } - } else { - _hasValidMTLPipelineStates = false; - } - [vtxPLDesc release]; // temp release - [tcPLDesc release]; // temp release - [rastPLDesc release]; // temp release } if (pPipelineFB) { @@ -762,6 +808,55 @@ return plDesc; } +#if MVK_XCODE_14 +// Returns a retained MTLRenderPipelineDescriptor constructed from this instance, or nil if an error occurs. +// It is the responsibility of the caller to release the returned descriptor. +MTLMeshRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLMeshRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, + const SPIRVTessReflectionData& reflectData, + const VkPipelineShaderStageCreateInfo* pVertexSS, + VkPipelineCreationFeedback* pVertexFB, + const VkPipelineShaderStageCreateInfo* pGeometrySS, + VkPipelineCreationFeedback* pGeometryFB, + const VkPipelineShaderStageCreateInfo* pFragmentSS, + VkPipelineCreationFeedback* pFragmentFB) { + SPIRVToMSLConversionConfiguration shaderConfig; + initShaderConversionConfig(shaderConfig, pCreateInfo, reflectData); + + MTLMeshRenderPipelineDescriptor* plDesc = [MTLMeshRenderPipelineDescriptor new]; // retained + + plDesc.rasterSampleCount = mvkSampleCountFromVkSampleCountFlagBits(pCreateInfo->pMultisampleState->rasterizationSamples); + + if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderConfig, pVertexSS, pVertexFB)) + return nullptr; + + std::string errorLog; + SPIRVShaderOutputs vertexOutputs, geometryOutputs; + if (!getShaderOutputs(((MVKShaderModule*)pVertexSS->module)->getSPIRV(), spv::ExecutionModelVertex, pVertexSS->pName, vertexOutputs, errorLog)) { + reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get vertex outputs: %s", errorLog.c_str()); + return nullptr; + } + + if (!addGeometryShaderToPipeline(plDesc, pCreateInfo, shaderConfig, pGeometrySS, pGeometryFB, vertexOutputs)) + return nullptr; + + if (!getShaderOutputs(((MVKShaderModule*)pGeometrySS->module)->getSPIRV(), spv::ExecutionModelGeometry, pGeometrySS->pName, geometryOutputs, errorLog)) { + reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get vertex outputs: %s", errorLog.c_str()); + return nullptr; + } + + if (!addFragmentShaderToPipeline(plDesc, pCreateInfo, shaderConfig, geometryOutputs, pFragmentSS, pFragmentFB)) { return nullptr; } + + addFragmentOutputToPipeline(plDesc, pCreateInfo); + + // Metal does not allow the name of the pipeline to be changed after it has been created, + // and we need to create the Metal pipeline immediately to provide error feedback to app. + // The best we can do at this point is set the pipeline name from the layout. + setLabelIfNotNil(plDesc, ((MVKPipelineLayout*)pCreateInfo->layout)->getDebugName()); + + return plDesc; +} +#endif + // Returns a retained MTLComputePipelineDescriptor for the vertex stage of a tessellated draw constructed from this instance, or nil if an error occurs. // It is the responsibility of the caller to release the returned descriptor. MTLComputePipelineDescriptor* MVKGraphicsPipeline::newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, @@ -1069,6 +1164,163 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 return true; } +#if MVK_XCODE_14 + +struct MSLVertexFormatInfo { + uint8_t num_elements : 7; + bool normalized : 1; +}; + +static constexpr MSLVertexFormatInfo vertexFormatInfo[] = { + [VK_FORMAT_R8_UNORM] = {1, true}, + [VK_FORMAT_R8_SNORM] = {1, true}, + [VK_FORMAT_R8_USCALED] = {1, false}, + [VK_FORMAT_R8_SSCALED] = {1, false}, + [VK_FORMAT_R8_UINT] = {1, false}, + [VK_FORMAT_R8_SINT] = {1, false}, + [VK_FORMAT_R8G8_UNORM] = {2, true}, + [VK_FORMAT_R8G8_SNORM] = {2, true}, + [VK_FORMAT_R8G8_USCALED] = {2, false}, + [VK_FORMAT_R8G8_SSCALED] = {2, false}, + [VK_FORMAT_R8G8_UINT] = {2, false}, + [VK_FORMAT_R8G8_SINT] = {2, false}, + [VK_FORMAT_R8G8B8_UNORM] = {3, true}, + [VK_FORMAT_R8G8B8_SNORM] = {3, true}, + [VK_FORMAT_R8G8B8_USCALED] = {3, false}, + [VK_FORMAT_R8G8B8_SSCALED] = {3, false}, + [VK_FORMAT_R8G8B8_UINT] = {3, false}, + [VK_FORMAT_R8G8B8_SINT] = {3, false}, + [VK_FORMAT_R8G8B8A8_UNORM] = {4, true}, + [VK_FORMAT_R8G8B8A8_SNORM] = {4, true}, + [VK_FORMAT_R8G8B8A8_USCALED] = {4, false}, + [VK_FORMAT_R8G8B8A8_SSCALED] = {4, false}, + [VK_FORMAT_R8G8B8A8_UINT] = {4, false}, + [VK_FORMAT_R8G8B8A8_SINT] = {4, false}, + [VK_FORMAT_B8G8R8A8_UNORM] = {4, true}, + [VK_FORMAT_B8G8R8A8_SNORM] = {4, true}, + [VK_FORMAT_B8G8R8A8_USCALED] = {4, false}, + [VK_FORMAT_B8G8R8A8_SSCALED] = {4, false}, + [VK_FORMAT_B8G8R8A8_UINT] = {4, false}, + [VK_FORMAT_B8G8R8A8_SINT] = {4, false}, + [VK_FORMAT_R16_UNORM] = {1, true}, + [VK_FORMAT_R16_SNORM] = {1, true}, + [VK_FORMAT_R16_USCALED] = {1, false}, + [VK_FORMAT_R16_SSCALED] = {1, false}, + [VK_FORMAT_R16_UINT] = {1, false}, + [VK_FORMAT_R16_SINT] = {1, false}, + [VK_FORMAT_R16_SFLOAT] = {1, false}, + [VK_FORMAT_R16G16_UNORM] = {2, true}, + [VK_FORMAT_R16G16_SNORM] = {2, true}, + [VK_FORMAT_R16G16_USCALED] = {2, false}, + [VK_FORMAT_R16G16_SSCALED] = {2, false}, + [VK_FORMAT_R16G16_UINT] = {2, false}, + [VK_FORMAT_R16G16_SINT] = {2, false}, + [VK_FORMAT_R16G16_SFLOAT] = {2, false}, + [VK_FORMAT_R16G16B16_UNORM] = {3, true}, + [VK_FORMAT_R16G16B16_SNORM] = {3, true}, + [VK_FORMAT_R16G16B16_USCALED] = {3, false}, + [VK_FORMAT_R16G16B16_SSCALED] = {3, false}, + [VK_FORMAT_R16G16B16_UINT] = {3, false}, + [VK_FORMAT_R16G16B16_SINT] = {3, false}, + [VK_FORMAT_R16G16B16_SFLOAT] = {3, false}, + [VK_FORMAT_R16G16B16A16_UNORM] = {4, true}, + [VK_FORMAT_R16G16B16A16_SNORM] = {4, true}, + [VK_FORMAT_R16G16B16A16_USCALED] = {4, false}, + [VK_FORMAT_R16G16B16A16_SSCALED] = {4, false}, + [VK_FORMAT_R16G16B16A16_UINT] = {4, false}, + [VK_FORMAT_R16G16B16A16_SINT] = {4, false}, + [VK_FORMAT_R16G16B16A16_SFLOAT] = {4, false}, + [VK_FORMAT_R32_UINT] = {1, false}, + [VK_FORMAT_R32_SINT] = {1, false}, + [VK_FORMAT_R32_SFLOAT] = {1, false}, + [VK_FORMAT_R32G32_UINT] = {2, false}, + [VK_FORMAT_R32G32_SINT] = {2, false}, + [VK_FORMAT_R32G32_SFLOAT] = {2, false}, + [VK_FORMAT_R32G32B32_UINT] = {3, false}, + [VK_FORMAT_R32G32B32_SINT] = {3, false}, + [VK_FORMAT_R32G32B32_SFLOAT] = {3, false}, + [VK_FORMAT_R32G32B32A32_UINT] = {4, false}, + [VK_FORMAT_R32G32B32A32_SINT] = {4, false}, + [VK_FORMAT_R32G32B32A32_SFLOAT] = {4, false}, +}; + +bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLMeshRenderPipelineDescriptor* plDesc, + const VkGraphicsPipelineCreateInfo* pCreateInfo, + SPIRVToMSLConversionConfiguration& shaderConfig, + const VkPipelineShaderStageCreateInfo* pVertexSS, + VkPipelineCreationFeedback* pVertexFB) { + + shaderConfig.options.entryPointStage = spv::ExecutionModelVertex; + shaderConfig.options.entryPointName = pVertexSS->pName; + shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageVertex]; + shaderConfig.options.mslOptions.indirect_params_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageVertex]; + shaderConfig.options.mslOptions.shader_output_buffer_index = _outputBufferIndex.stages[kMVKShaderStageVertex]; + shaderConfig.options.mslOptions.buffer_size_buffer_index = _bufferSizeBufferIndex.stages[kMVKShaderStageVertex]; + shaderConfig.options.mslOptions.dynamic_offsets_buffer_index = _dynamicOffsetBufferIndex.stages[kMVKShaderStageVertex]; + shaderConfig.options.mslOptions.view_mask_buffer_index = _viewRangeBufferIndex.stages[kMVKShaderStageVertex]; + shaderConfig.options.mslOptions.capture_output_to_buffer = false; + shaderConfig.options.mslOptions.disable_rasterization = !_isRasterizing; + shaderConfig.options.mslOptions.for_mesh_pipeline = true; + shaderConfig.options.mslOptions.msl_version = getDevice()->getPhysicalDevice()->getMetalFeatures()->mslVersion; + shaderConfig.options.shouldFlipVertexY = false; + + if (_mtlPrimitiveType == MTLPrimitiveTypeTriangleStrip) + shaderConfig.options.mslOptions.input_primitive_type = CompilerMSL::Options::PrimitiveTopology::TriangleStrip; + else if (_mtlPrimitiveType == MTLPrimitiveTypeTriangle) + shaderConfig.options.mslOptions.input_primitive_type = CompilerMSL::Options::PrimitiveTopology::Triangles; + else if (_mtlPrimitiveType == MTLPrimitiveTypePoint) + shaderConfig.options.mslOptions.input_primitive_type = CompilerMSL::Options::PrimitiveTopology::Points; + else + reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "Unsupported topology: %lu", _mtlPrimitiveType); + + addVertexInputToShaderConversionConfig(shaderConfig, pCreateInfo); + + MVKMTLFunction vertexFunc = getMTLFunction(shaderConfig, pVertexSS, pVertexFB, "Vertex"); + + plDesc.objectFunction = vertexFunc.getMTLFunction(); + return true; +} + +bool MVKGraphicsPipeline::addGeometryShaderToPipeline(MTLMeshRenderPipelineDescriptor* plDesc, + const VkGraphicsPipelineCreateInfo* pCreateInfo, + SPIRVToMSLConversionConfiguration& shaderConfig, + const VkPipelineShaderStageCreateInfo* pGeometrySS, + VkPipelineCreationFeedback* pGeometryFB, + SPIRVShaderOutputs &vertexOutputs) { + + shaderConfig.options.entryPointStage = spv::ExecutionModelGeometry; + shaderConfig.options.entryPointName = pGeometrySS->pName; + shaderConfig.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageGeometry]; + shaderConfig.options.mslOptions.indirect_params_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageGeometry]; + shaderConfig.options.mslOptions.shader_output_buffer_index = _outputBufferIndex.stages[kMVKShaderStageGeometry]; + shaderConfig.options.mslOptions.buffer_size_buffer_index = _bufferSizeBufferIndex.stages[kMVKShaderStageGeometry]; + shaderConfig.options.mslOptions.dynamic_offsets_buffer_index = _dynamicOffsetBufferIndex.stages[kMVKShaderStageGeometry]; + shaderConfig.options.mslOptions.view_mask_buffer_index = _viewRangeBufferIndex.stages[kMVKShaderStageGeometry]; + shaderConfig.options.mslOptions.capture_output_to_buffer = false; + shaderConfig.options.mslOptions.disable_rasterization = !_isRasterizing; + shaderConfig.options.mslOptions.for_mesh_pipeline = true; + shaderConfig.options.mslOptions.msl_version = getDevice()->getPhysicalDevice()->getMetalFeatures()->mslVersion; + shaderConfig.options.shouldFlipVertexY = true; + + if (_mtlPrimitiveType == MTLPrimitiveTypeTriangleStrip) + shaderConfig.options.mslOptions.input_primitive_type = CompilerMSL::Options::PrimitiveTopology::TriangleStrip; + else if (_mtlPrimitiveType == MTLPrimitiveTypeTriangle) + shaderConfig.options.mslOptions.input_primitive_type = CompilerMSL::Options::PrimitiveTopology::Triangles; + else if (_mtlPrimitiveType == MTLPrimitiveTypePoint) + shaderConfig.options.mslOptions.input_primitive_type = CompilerMSL::Options::PrimitiveTopology::Points; + else + reportMessage(MVK_CONFIG_LOG_LEVEL_ERROR, "Unsupported topology: %lu", _mtlPrimitiveType); + + addPrevStageOutputToShaderConversionConfig(shaderConfig, vertexOutputs); + + MVKMTLFunction geometryFunc = getMTLFunction(shaderConfig, pGeometrySS, pGeometryFB, "Geometry"); + + plDesc.meshFunction = geometryFunc.getMTLFunction(); + return true; +} + +#endif + // Adds a vertex shader compiled as a compute kernel to the pipeline description. bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, @@ -1251,7 +1503,8 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 return true; } -bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, +template +bool MVKGraphicsPipeline::addFragmentShaderToPipeline(T* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderConfig, SPIRVShaderOutputs& shaderOutputs, @@ -1270,6 +1523,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 if (_device->_pMetalFeatures->needsSampleDrefLodArrayWorkaround) { shaderConfig.options.mslOptions.sample_dref_lod_array_as_grad = true; } + shaderConfig.options.mslOptions.for_mesh_pipeline = false; if (_isRasterizing && pCreateInfo->pMultisampleState) { // Must ignore allowed bad pMultisampleState pointer if rasterization disabled if (pCreateInfo->pMultisampleState->pSampleMask && pCreateInfo->pMultisampleState->pSampleMask[0] != 0xffffffff) { shaderConfig.options.mslOptions.additional_fixed_sample_mask = pCreateInfo->pMultisampleState->pSampleMask[0]; @@ -1541,10 +1795,10 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 plDesc.tessellationPartitionMode = mvkMTLTessellationPartitionModeFromSpvExecutionMode(reflectData.partitionMode); } -void MVKGraphicsPipeline::addFragmentOutputToPipeline(MTLRenderPipelineDescriptor* plDesc, - const VkGraphicsPipelineCreateInfo* pCreateInfo) { +template +void MVKGraphicsPipeline::addFragmentOutputToPipeline(T* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo) { // Topology - if (pCreateInfo->pInputAssemblyState) { + if (pCreateInfo->pInputAssemblyState && !isGeometryPipeline()) { plDesc.inputPrimitiveTopologyMVK = isRenderingPoints(pCreateInfo) ? MTLPrimitiveTopologyClassPoint : mvkMTLPrimitiveTopologyClassFromVkPrimitiveTopology(pCreateInfo->pInputAssemblyState->topology); @@ -1607,7 +1861,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 // Multisampling - must ignore allowed bad pMultisampleState pointer if rasterization disabled if (_isRasterizing && pCreateInfo->pMultisampleState) { - plDesc.sampleCount = mvkSampleCountFromVkSampleCountFlagBits(pCreateInfo->pMultisampleState->rasterizationSamples); + plDesc.rasterSampleCount = mvkSampleCountFromVkSampleCountFlagBits(pCreateInfo->pMultisampleState->rasterizationSamples); plDesc.alphaToCoverageEnabled = pCreateInfo->pMultisampleState->alphaToCoverageEnable; plDesc.alphaToOneEnabled = pCreateInfo->pMultisampleState->alphaToOneEnable; @@ -1757,18 +2011,48 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 return mtlBufferIndex < _descriptorBufferCounts.stages[stage] || mtlBufferIndex > getImplicitBufferIndex(stage, 0); } +static MVK_spirv_cross::MSLShaderVariableFormat toMslShaderFormat(MVKFormatType type) { + switch (type) { + case kMVKFormatColorInt8: return MSL_SHADER_VARIABLE_FORMAT_INT8; + case kMVKFormatColorUInt8: return MSL_SHADER_VARIABLE_FORMAT_UINT8; + case kMVKFormatColorInt16: return MSL_SHADER_VARIABLE_FORMAT_INT16; + case kMVKFormatColorUInt16: return MSL_SHADER_VARIABLE_FORMAT_UINT16; + case kMVKFormatColorInt32: return MSL_SHADER_VARIABLE_FORMAT_INT32; + case kMVKFormatColorUInt32: return MSL_SHADER_VARIABLE_FORMAT_UINT32; + case kMVKFormatColorFloat: return MSL_SHADER_VARIABLE_FORMAT_FLOAT; + case kMVKFormatColorHalf: return MSL_SHADER_VARIABLE_FORMAT_HALF; + default: return MSL_SHADER_VARIABLE_FORMAT_OTHER; + } +} + // Initializes the vertex attributes in a shader conversion configuration. void MVKGraphicsPipeline::addVertexInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo) { // Set the shader conversion config vertex attribute information shaderConfig.shaderInputs.clear(); uint32_t vaCnt = pCreateInfo->pVertexInputState->vertexAttributeDescriptionCount; + uint32_t vbCnt = pCreateInfo->pVertexInputState->vertexBindingDescriptionCount; for (uint32_t vaIdx = 0; vaIdx < vaCnt; vaIdx++) { const VkVertexInputAttributeDescription* pVKVA = &pCreateInfo->pVertexInputState->pVertexAttributeDescriptions[vaIdx]; + const VkVertexInputBindingDescription* pVKVB = nullptr; + + for (uint32_t vbIdx = 0; vbIdx < vbCnt; vbIdx++) { + pVKVB = &pCreateInfo->pVertexInputState->pVertexBindingDescriptions[vbIdx]; + if (pVKVA->binding == pVKVB->binding) break; + } // Set binding and offset from Vulkan vertex attribute mvk::MSLShaderInput si; si.shaderVar.location = pVKVA->location; + si.shaderVar.offset = pVKVA->offset; + si.shaderVar.stride = pVKVB->stride; + + if (shaderConfig.options.mslOptions.for_mesh_pipeline) { + si.shaderVar.vecsize = vertexFormatInfo[pVKVA->format].num_elements; + si.shaderVar.normalized = vertexFormatInfo[pVKVA->format].normalized; + si.shaderVar.binding = getDevice()->getMetalBufferIndexForVertexAttributeBinding(pVKVA->binding); + } + si.binding = pVKVA->binding; // Metal can't do signedness conversions on vertex buffers (rdar://45922847). If the shader @@ -1776,33 +2060,29 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 // to match the vertex attribute. So tell SPIRV-Cross if we're expecting an unsigned format. // Only do this if the attribute could be reasonably expected to fit in the shader's // declared type. Programs that try to invoke undefined behavior are on their own. - switch (getPixelFormats()->getFormatType(pVKVA->format) ) { - case kMVKFormatColorUInt8: - si.shaderVar.format = MSL_VERTEX_FORMAT_UINT8; - break; - - case kMVKFormatColorUInt16: - si.shaderVar.format = MSL_VERTEX_FORMAT_UINT16; - break; - - case kMVKFormatDepthStencil: - // Only some depth/stencil formats have unsigned components. - switch (pVKVA->format) { - case VK_FORMAT_S8_UINT: - case VK_FORMAT_D16_UNORM_S8_UINT: - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - si.shaderVar.format = MSL_VERTEX_FORMAT_UINT8; + auto mvkFormat = getPixelFormats()->getFormatType(pVKVA->format); + si.shaderVar.format = toMslShaderFormat(mvkFormat); + + if (si.shaderVar.format == MSL_VERTEX_FORMAT_OTHER) { + switch (getPixelFormats()->getFormatType(pVKVA->format) ) { + case kMVKFormatDepthStencil: + // Only some depth/stencil formats have unsigned components. + switch (pVKVA->format) { + case VK_FORMAT_S8_UINT: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + si.shaderVar.format = MSL_VERTEX_FORMAT_UINT8; + break; + + default: + break; + } break; default: break; } - break; - - default: - break; - } shaderConfig.shaderInputs.push_back(si); @@ -1824,30 +2104,8 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 so.shaderVar.builtin = shaderInputs[soIdx].builtin; so.shaderVar.vecsize = shaderInputs[soIdx].vecWidth; so.shaderVar.rate = shaderInputs[soIdx].perPatch ? MSL_SHADER_VARIABLE_RATE_PER_PATCH : MSL_SHADER_VARIABLE_RATE_PER_VERTEX; - - switch (getPixelFormats()->getFormatType(mvkFormatFromOutput(shaderInputs[soIdx]) ) ) { - case kMVKFormatColorUInt8: - so.shaderVar.format = MSL_SHADER_INPUT_FORMAT_UINT8; - break; - - case kMVKFormatColorUInt16: - so.shaderVar.format = MSL_SHADER_INPUT_FORMAT_UINT16; - break; - - case kMVKFormatColorHalf: - case kMVKFormatColorInt16: - so.shaderVar.format = MSL_SHADER_INPUT_FORMAT_ANY16; - break; - - case kMVKFormatColorFloat: - case kMVKFormatColorInt32: - case kMVKFormatColorUInt32: - so.shaderVar.format = MSL_SHADER_INPUT_FORMAT_ANY32; - break; - - default: - break; - } + so.shaderVar.type = shaderInputs[soIdx].baseType; + so.shaderVar.format = toMslShaderFormat(getPixelFormats()->getFormatType(mvkFormatFromOutput(shaderInputs[soIdx]))); shaderConfig.shaderOutputs.push_back(so); } @@ -1867,31 +2125,9 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 si.shaderVar.component = shaderOutputs[siIdx].component; si.shaderVar.builtin = shaderOutputs[siIdx].builtin; si.shaderVar.vecsize = shaderOutputs[siIdx].vecWidth; + si.shaderVar.type = shaderOutputs[siIdx].baseType; si.shaderVar.rate = shaderOutputs[siIdx].perPatch ? MSL_SHADER_VARIABLE_RATE_PER_PATCH : MSL_SHADER_VARIABLE_RATE_PER_VERTEX; - - switch (getPixelFormats()->getFormatType(mvkFormatFromOutput(shaderOutputs[siIdx]) ) ) { - case kMVKFormatColorUInt8: - si.shaderVar.format = MSL_SHADER_INPUT_FORMAT_UINT8; - break; - - case kMVKFormatColorUInt16: - si.shaderVar.format = MSL_SHADER_INPUT_FORMAT_UINT16; - break; - - case kMVKFormatColorHalf: - case kMVKFormatColorInt16: - si.shaderVar.format = MSL_SHADER_INPUT_FORMAT_ANY16; - break; - - case kMVKFormatColorFloat: - case kMVKFormatColorInt32: - case kMVKFormatColorUInt32: - si.shaderVar.format = MSL_SHADER_INPUT_FORMAT_ANY32; - break; - - default: - break; - } + si.shaderVar.format = toMslShaderFormat(getPixelFormats()->getFormatType(mvkFormatFromOutput(shaderOutputs[siIdx]))); shaderConfig.shaderInputs.push_back(si); } @@ -2659,6 +2895,26 @@ void serialize(Archive & archive, MVKCompressor& comp) { return [_mtlRenderPipelineState retain]; } +#if MVK_XCODE_14 +id MVKRenderPipelineCompiler::newMTLRenderPipelineState(MTLMeshRenderPipelineDescriptor* mtlRPLDesc) { + unique_lock lock(_completionLock); + + compile(lock, ^{ + auto mtlDev = _owner->getMTLDevice(); + @synchronized (mtlDev) { + [mtlDev newRenderPipelineStateWithMeshDescriptor: mtlRPLDesc + options: MTLPipelineOptionNone + completionHandler: ^(id ps, MTLRenderPipelineReflection *refl, NSError* error) { + bool isLate = compileComplete(ps, error); + if (isLate) { destroy(); } + }]; + } + }); + + return [_mtlRenderPipelineState retain]; +} +#endif + bool MVKRenderPipelineCompiler::compileComplete(id mtlRenderPipelineState, NSError* compileError) { lock_guard lock(_completionLock); diff --git a/MoltenVK/MoltenVK/OS/MTLRenderPipelineDescriptor+MoltenVK.h b/MoltenVK/MoltenVK/OS/MTLRenderPipelineDescriptor+MoltenVK.h index b8cd92308..e889bafa0 100644 --- a/MoltenVK/MoltenVK/OS/MTLRenderPipelineDescriptor+MoltenVK.h +++ b/MoltenVK/MoltenVK/OS/MTLRenderPipelineDescriptor+MoltenVK.h @@ -34,3 +34,13 @@ @property(nonatomic, readwrite) MTLPrimitiveTopologyClass inputPrimitiveTopologyMVK; @end + +#if MVK_XCODE_14 + +@interface MTLMeshRenderPipelineDescriptor (MoltenVK) + +@property(nonatomic, readwrite) MTLPrimitiveTopologyClass inputPrimitiveTopologyMVK; + +@end + +#endif diff --git a/MoltenVK/MoltenVK/OS/MTLRenderPipelineDescriptor+MoltenVK.m b/MoltenVK/MoltenVK/OS/MTLRenderPipelineDescriptor+MoltenVK.m index ab46bcebf..3e2b9d7f8 100644 --- a/MoltenVK/MoltenVK/OS/MTLRenderPipelineDescriptor+MoltenVK.m +++ b/MoltenVK/MoltenVK/OS/MTLRenderPipelineDescriptor+MoltenVK.m @@ -32,3 +32,18 @@ -(void) setInputPrimitiveTopologyMVK: (MTLPrimitiveTopologyClass) topology { } @end + +#if MVK_XCODE_14 + +@implementation MTLMeshRenderPipelineDescriptor (MoltenVK) + +-(MTLPrimitiveTopologyClass) inputPrimitiveTopologyMVK { + return MTLPrimitiveTopologyClassUnspecified; +} + +-(void) setInputPrimitiveTopologyMVK: (MTLPrimitiveTopologyClass) topology { +} + +@end + +#endif diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index caa776237..1bb3d7e59 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -673,7 +673,7 @@ MVKShaderStage mvkShaderStageFromVkShaderStageFlagBitsInObj(VkShaderStageFlagBit case VK_SHADER_STAGE_VERTEX_BIT: return kMVKShaderStageVertex; case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return kMVKShaderStageTessCtl; case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return kMVKShaderStageTessEval; - /* FIXME: VK_SHADER_STAGE_GEOMETRY_BIT */ + case VK_SHADER_STAGE_GEOMETRY_BIT: return kMVKShaderStageGeometry; case VK_SHADER_STAGE_FRAGMENT_BIT: return kMVKShaderStageFragment; case VK_SHADER_STAGE_COMPUTE_BIT: return kMVKShaderStageCompute; default: @@ -687,7 +687,7 @@ MVK_PUBLIC_SYMBOL VkShaderStageFlagBits mvkVkShaderStageFlagBitsFromMVKShaderSta case kMVKShaderStageVertex: return VK_SHADER_STAGE_VERTEX_BIT; case kMVKShaderStageTessCtl: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; case kMVKShaderStageTessEval: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - /* FIXME: kMVKShaderStageGeometry */ + case kMVKShaderStageGeometry: return VK_SHADER_STAGE_GEOMETRY_BIT; case kMVKShaderStageFragment: return VK_SHADER_STAGE_FRAGMENT_BIT; case kMVKShaderStageCompute: return VK_SHADER_STAGE_COMPUTE_BIT; case kMVKShaderStageCount: diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp index ced660aa8..42c60e964 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp +++ b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp @@ -379,29 +379,31 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConversionConfigur } } - for (auto& ctxSI : shaderConfig.shaderInputs) { - if (ctxSI.shaderVar.builtin != spv::BuiltInMax) { - ctxSI.outIsUsedByShader = pMSLCompiler->has_active_builtin(ctxSI.shaderVar.builtin, spv::StorageClassInput); - } else { - ctxSI.outIsUsedByShader = pMSLCompiler->is_msl_shader_input_used(ctxSI.shaderVar.location); - } - } - for (auto& ctxSO : shaderConfig.shaderOutputs) { - if (ctxSO.shaderVar.builtin != spv::BuiltInMax) { - ctxSO.outIsUsedByShader = pMSLCompiler->has_active_builtin(ctxSO.shaderVar.builtin, spv::StorageClassOutput); - } else { - ctxSO.outIsUsedByShader = pMSLCompiler->is_msl_shader_output_used(ctxSO.shaderVar.location); - } - } - for (auto& ctxRB : shaderConfig.resourceBindings) { - if (ctxRB.resourceBinding.stage == shaderConfig.options.entryPointStage) { - ctxRB.outIsUsedByShader = pMSLCompiler->is_msl_resource_binding_used(ctxRB.resourceBinding.stage, - ctxRB.resourceBinding.desc_set, - ctxRB.resourceBinding.binding); - } - } - - delete pMSLCompiler; + if (pMSLCompiler) { + for (auto& ctxSI : shaderConfig.shaderInputs) { + if (ctxSI.shaderVar.builtin != spv::BuiltInMax) { + ctxSI.outIsUsedByShader = pMSLCompiler->has_active_builtin(ctxSI.shaderVar.builtin, spv::StorageClassInput); + } else { + ctxSI.outIsUsedByShader = pMSLCompiler->is_msl_shader_input_used(ctxSI.shaderVar.location); + } + } + for (auto& ctxSO : shaderConfig.shaderOutputs) { + if (ctxSO.shaderVar.builtin != spv::BuiltInMax) { + ctxSO.outIsUsedByShader = pMSLCompiler->has_active_builtin(ctxSO.shaderVar.builtin, spv::StorageClassOutput); + } else { + ctxSO.outIsUsedByShader = pMSLCompiler->is_msl_shader_output_used(ctxSO.shaderVar.location); + } + } + for (auto& ctxRB : shaderConfig.resourceBindings) { + if (ctxRB.resourceBinding.stage == shaderConfig.options.entryPointStage) { + ctxRB.outIsUsedByShader = pMSLCompiler->is_msl_resource_binding_used(ctxRB.resourceBinding.stage, + ctxRB.resourceBinding.desc_set, + ctxRB.resourceBinding.binding); + } + } + + delete pMSLCompiler; + } // To check GLSL conversion if (shouldLogGLSL) { From 8cbaaa69d8374dfda893c93e1569087fdd2e454c Mon Sep 17 00:00:00 2001 From: Jan Sikorski Date: Fri, 15 Sep 2023 17:18:24 +0200 Subject: [PATCH 74/74] Temporarily switch SPIRV-Cross repository. --- fetchDependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetchDependencies b/fetchDependencies index f03f36c86..e4b233015 100755 --- a/fetchDependencies +++ b/fetchDependencies @@ -325,7 +325,7 @@ if [ ! "$SPIRV_CROSS_ROOT" = "" ]; then rm -rf ${REPO_NAME} ln -sfn ${SPIRV_CROSS_ROOT} ${REPO_NAME} else - REPO_URL="https://github.com/KhronosGroup/${REPO_NAME}.git" + REPO_URL="https://github.com/js6i/${REPO_NAME}.git" REPO_REV=$(cat "${EXT_REV_DIR}/${REPO_NAME}_repo_revision") update_repo ${REPO_NAME} ${REPO_URL} ${REPO_REV}