From fe65485bfb672da4cad44209cd846bccd5177314 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 27 Dec 2023 18:38:23 -0500 Subject: [PATCH 1/2] Fix Metal vertex format lookup logic. - Remove MVKPixelFormats::_mtlFormatDescIndicesByMTLVertexFormats and index into _mtlVertexFormatDescriptions using MTLVertexFormat directly. - Fix assertion to test MTLVertexFormat < _mtlVertexFormatCount. --- .../MoltenVK/GPUObjects/MVKPixelFormats.h | 2 -- .../MoltenVK/GPUObjects/MVKPixelFormats.mm | 29 ++++++++----------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h index 5d23225b..1a73a59a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h @@ -459,6 +459,4 @@ protected: // Outliers are mapped by a map. uint16_t _mtlFormatDescIndicesByMTLPixelFormatsCore[_mtlPixelFormatCoreCount]; std::unordered_map _mtlFormatDescIndicesByMTLPixelFormatsExt; - - uint16_t _mtlFormatDescIndicesByMTLVertexFormats[_mtlVertexFormatCount]; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index 7b7e04cd..b1c65570 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -783,8 +783,7 @@ MVKMTLFormatDesc& MVKPixelFormats::getMTLPixelFormatDesc(MTLPixelFormat mtlForma // Return a reference to the Metal format descriptor corresponding to the MTLVertexFormat. MVKMTLFormatDesc& MVKPixelFormats::getMTLVertexFormatDesc(MTLVertexFormat mtlFormat) { - uint16_t fmtIdx = (mtlFormat < _mtlVertexFormatCount) ? _mtlFormatDescIndicesByMTLVertexFormats[mtlFormat] : 0; - return _mtlVertexFormatDescriptions[fmtIdx]; + return _mtlVertexFormatDescriptions[mtlFormat < _mtlVertexFormatCount ? mtlFormat : 0]; } @@ -1312,21 +1311,24 @@ void MVKPixelFormats::initMTLPixelFormatCapabilities() { } #define addMTLVertexFormatDesc(MTL_VTX_FMT, IOS_CAPS, MACOS_CAPS) \ - MVKAssert(fmtIdx < _mtlVertexFormatCount, "Attempting to describe %d MTLVertexFormats, but only have space for %d. Increase the value of _mtlVertexFormatCount", fmtIdx + 1, _mtlVertexFormatCount); \ - _mtlVertexFormatDescriptions[fmtIdx++] = { .mtlVertexFormat = MTLVertexFormat ##MTL_VTX_FMT, VK_FORMAT_UNDEFINED, \ - mvkSelectPlatformValue(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS), \ - MVKMTLViewClass::None, MTLPixelFormatInvalid, "MTLVertexFormat" #MTL_VTX_FMT } + mtlVtxFmt = MTLVertexFormat ##MTL_VTX_FMT; \ + if (mtlVtxFmt < _mtlVertexFormatCount) { \ + _mtlVertexFormatDescriptions[mtlVtxFmt] = { .mtlVertexFormat = mtlVtxFmt, VK_FORMAT_UNDEFINED, \ + mvkSelectPlatformValue(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS), \ + MVKMTLViewClass::None, MTLPixelFormatInvalid, "MTLVertexFormat" #MTL_VTX_FMT }; \ + } else { \ + MVKAssert(false, "Attempting to describe at least %lu MTLVertexFormats, but only have space for %d. Increase the value of _mtlVertexFormatCount", mtlVtxFmt + 1, _mtlVertexFormatCount); \ + } void MVKPixelFormats::initMTLVertexFormatCapabilities() { mvkClear(_mtlVertexFormatDescriptions, _mtlVertexFormatCount); - uint32_t fmtIdx = 0; + MTLVertexFormat mtlVtxFmt = MTLVertexFormatInvalid; // When adding to this list, be sure to ensure _mtlVertexFormatCount is large enough for the format count - // MTLVertexFormatInvalid must come first. - addMTLVertexFormatDesc( Invalid, None, None ); + addMTLVertexFormatDesc( Invalid, None, None ); // MTLVertexFormatInvalid must come first. addMTLVertexFormatDesc( UChar2Normalized, Vertex, Vertex ); addMTLVertexFormatDesc( Char2Normalized, Vertex, Vertex ); @@ -1399,9 +1401,8 @@ void MVKPixelFormats::initMTLVertexFormatCapabilities() { // Populates the Metal lookup maps void MVKPixelFormats::buildMTLFormatMaps() { - // Set all MTLPixelFormats and MTLVertexFormats to undefined/invalid + // Set all MTLPixelFormats lookups to undefined/invalid mvkClear(_mtlFormatDescIndicesByMTLPixelFormatsCore, _mtlPixelFormatCoreCount); - mvkClear(_mtlFormatDescIndicesByMTLVertexFormats, _mtlVertexFormatCount); // Build lookup table for MTLPixelFormat specs. // For most Metal format values, which are small and consecutive, use a simple lookup array. @@ -1416,12 +1417,6 @@ void MVKPixelFormats::buildMTLFormatMaps() { } } } - - // Build lookup table for MTLVertexFormat specs - for (uint32_t fmtIdx = 0; fmtIdx < _mtlVertexFormatCount; fmtIdx++) { - MTLVertexFormat fmt = _mtlVertexFormatDescriptions[fmtIdx].mtlVertexFormat; - if (fmt) { _mtlFormatDescIndicesByMTLVertexFormats[fmt] = fmtIdx; } - } } // If the device supports the feature set, add additional capabilities to a MTLPixelFormat From 88799cf25515add6a836cc8bfb0c60bc7a9ee88f Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 27 Dec 2023 19:34:23 -0500 Subject: [PATCH 2/2] Reduce memory used by MVKPixelFormats lookups. - Add MVKInflectionMap collection to manage lookups based on enums that have a large set of consecutive elements, plus additional enum values that are more sparsely assigned. - Recognize every MTLPixelFormat value can be held in uint16_t. - Reduce inflection-map sizes by calling shrink_to_fit(). - runcts script log completion time (unrelated). --- MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 12 +- .../MoltenVK/GPUObjects/MVKPixelFormats.h | 26 +-- .../MoltenVK/GPUObjects/MVKPixelFormats.mm | 181 ++++++------------ MoltenVK/MoltenVK/Utility/MVKInflectionMap.h | 105 ++++++++++ Scripts/runcts | 2 +- 5 files changed, 180 insertions(+), 146 deletions(-) create mode 100755 MoltenVK/MoltenVK/Utility/MVKInflectionMap.h diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index be7ca325..827e02ad 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -318,6 +318,10 @@ 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 */; }; + A9AB952B2B3EDFCC00C4E967 /* MVKInflectionMap.h in Headers */ = {isa = PBXBuildFile; fileRef = A9AB95292B3EDFCC00C4E967 /* MVKInflectionMap.h */; }; + A9AB952C2B3EDFCC00C4E967 /* MVKInflectionMap.h in Headers */ = {isa = PBXBuildFile; fileRef = A9AB95292B3EDFCC00C4E967 /* MVKInflectionMap.h */; }; + A9AB952D2B3EDFCC00C4E967 /* MVKInflectionMap.h in Headers */ = {isa = PBXBuildFile; fileRef = A9AB95292B3EDFCC00C4E967 /* MVKInflectionMap.h */; }; + A9AB952E2B3EDFCC00C4E967 /* MVKInflectionMap.h in Headers */ = {isa = PBXBuildFile; fileRef = A9AB95292B3EDFCC00C4E967 /* MVKInflectionMap.h */; }; 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 */; }; @@ -667,6 +671,7 @@ A99C91002295FAC500A061DA /* MVKVulkanAPIObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKVulkanAPIObject.mm; sourceTree = ""; }; 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 = ""; }; + A9AB95292B3EDFCC00C4E967 /* MVKInflectionMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKInflectionMap.h; 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 = ""; }; @@ -840,7 +845,6 @@ A98149401FB6A3F7005F00B4 /* Utility */ = { isa = PBXGroup; children = ( - A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */, A98149421FB6A3F7005F00B4 /* MVKBaseObject.h */, A98149411FB6A3F7005F00B4 /* MVKBaseObject.mm */, A9D7104E25CDE05E00E38106 /* MVKBitArray.h */, @@ -854,6 +858,8 @@ A98149431FB6A3F7005F00B4 /* MVKEnvironment.h */, A98149451FB6A3F7005F00B4 /* MVKFoundation.cpp */, A98149441FB6A3F7005F00B4 /* MVKFoundation.h */, + A9AB95292B3EDFCC00C4E967 /* MVKInflectionMap.h */, + A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */, A98149461FB6A3F7005F00B4 /* MVKObjectPool.h */, A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */, A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */, @@ -981,6 +987,7 @@ 2FEA0A5924902F9F00EEF3AD /* MVKDevice.h in Headers */, 2FEA0A5A24902F9F00EEF3AD /* MVKSmallVector.h in Headers */, 2FEA0A5C24902F9F00EEF3AD /* MVKCommandPool.h in Headers */, + A9AB952C2B3EDFCC00C4E967 /* MVKInflectionMap.h in Headers */, A9B3D74329F9BDEE00745CD4 /* mvk_private_api.h in Headers */, 2FEA0A5D24902F9F00EEF3AD /* MVKShaderModule.h in Headers */, 2FEA0A5E24902F9F00EEF3AD /* MVKVulkanAPIObject.h in Headers */, @@ -1060,6 +1067,7 @@ A9F3D9DE24732A4D00745190 /* MVKSmallVector.h in Headers */, A94FB7D41C7DFB4800632CA3 /* MVKCommandPool.h in Headers */, A94FB80C1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */, + A9AB952B2B3EDFCC00C4E967 /* MVKInflectionMap.h in Headers */, A99C91042295FAC600A061DA /* MVKVulkanAPIObject.h in Headers */, A94FB7C01C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */, A9B3D73B29F9B3B100745CD4 /* mvk_deprecated_api.h in Headers */, @@ -1138,6 +1146,7 @@ A94FB7D51C7DFB4800632CA3 /* MVKCommandPool.h in Headers */, A94FB80D1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */, A99C91052295FAC600A061DA /* MVKVulkanAPIObject.h in Headers */, + A9AB952D2B3EDFCC00C4E967 /* MVKInflectionMap.h in Headers */, A94FB7C11C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */, A94FB7CD1C7DFB4800632CA3 /* MVKCommand.h in Headers */, A9B3D73D29F9B3B100745CD4 /* mvk_deprecated_api.h in Headers */, @@ -1237,6 +1246,7 @@ DCFD7F142A45BC6E007BBBF7 /* MVKCmdTransfer.h in Headers */, DCFD7F152A45BC6E007BBBF7 /* MVKDescriptor.h in Headers */, DCFD7F162A45BC6E007BBBF7 /* MVKCmdDraw.h in Headers */, + A9AB952E2B3EDFCC00C4E967 /* MVKInflectionMap.h in Headers */, DCFD7F172A45BC6E007BBBF7 /* MVKCommandBuffer.h in Headers */, DCFD7F182A45BC6E007BBBF7 /* MTLRenderPassDescriptor+MoltenVK.h in Headers */, DCFD7F192A45BC6E007BBBF7 /* MVKCmdDebug.h in Headers */, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h index 1a73a59a..2d446eb1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h @@ -20,6 +20,7 @@ #include "MVKBaseObject.h" #include "MVKOSExtensions.h" +#include "MVKInflectionMap.h" #include "mvk_datatypes.hpp" #include #include @@ -29,14 +30,6 @@ class MVKPhysicalDevice; -// Validate these values periodically as new formats are added over time. -static const uint32_t _vkFormatCount = 256; -static const uint32_t _vkFormatCoreCount = VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1; -static const uint32_t _mtlPixelFormatCount = 256; -static const uint32_t _mtlPixelFormatCoreCount = MTLPixelFormatX32_Stencil8 + 2; // The actual last enum value is not available on iOS -static const uint32_t _mtlVertexFormatCount = MTLVertexFormatHalf + 1; - - #pragma mark - #pragma mark Metal format capabilities @@ -418,7 +411,6 @@ protected: void initVkFormatCapabilities(); void initMTLPixelFormatCapabilities(); void initMTLVertexFormatCapabilities(); - void buildMTLFormatMaps(); void buildVkFormatMaps(); void setFormatProperties(MVKVkFormatDesc& vkDesc); void modifyMTLFormatCapabilities(); @@ -446,17 +438,7 @@ protected: MVKMTLFmtCaps mtlFmtCaps); MVKPhysicalDevice* _physicalDevice; - MVKVkFormatDesc _vkFormatDescriptions[_vkFormatCount]; - MVKMTLFormatDesc _mtlPixelFormatDescriptions[_mtlPixelFormatCount]; - MVKMTLFormatDesc _mtlVertexFormatDescriptions[_mtlVertexFormatCount]; - - // Vulkan core formats have small values and are mapped by simple lookup array. - // Vulkan extension formats have larger values and are mapped by a map. - uint16_t _vkFormatDescIndicesByVkFormatsCore[_vkFormatCoreCount]; - std::unordered_map _vkFormatDescIndicesByVkFormatsExt; - - // Most Metal formats have small values and are mapped by simple lookup array. - // Outliers are mapped by a map. - uint16_t _mtlFormatDescIndicesByMTLPixelFormatsCore[_mtlPixelFormatCoreCount]; - std::unordered_map _mtlFormatDescIndicesByMTLPixelFormatsExt; + MVKInflectionMap _vkFormatDescriptions; + MVKInflectionMap _mtlPixelFormatDescriptions; // The actual last enum value is not available on iOS + MVKSmallVector _mtlVertexFormatDescriptions; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index b1c65570..877f2f2a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -762,10 +762,7 @@ MTLTextureUsage MVKPixelFormats::getMTLTextureUsage(VkImageUsageFlags vkImageUsa // Return a reference to the Vulkan format descriptor corresponding to the VkFormat. MVKVkFormatDesc& MVKPixelFormats::getVkFormatDesc(VkFormat vkFormat) { - uint16_t fmtIdx = ((vkFormat < _vkFormatCoreCount) - ? _vkFormatDescIndicesByVkFormatsCore[vkFormat] - : _vkFormatDescIndicesByVkFormatsExt[vkFormat]); - return _vkFormatDescriptions[fmtIdx]; + return _vkFormatDescriptions[vkFormat]; } // Return a reference to the Vulkan format descriptor corresponding to the MTLPixelFormat. @@ -775,15 +772,12 @@ MVKVkFormatDesc& MVKPixelFormats::getVkFormatDesc(MTLPixelFormat mtlFormat) { // Return a reference to the Metal format descriptor corresponding to the MTLPixelFormat. MVKMTLFormatDesc& MVKPixelFormats::getMTLPixelFormatDesc(MTLPixelFormat mtlFormat) { - uint16_t fmtIdx = ((mtlFormat < _mtlPixelFormatCoreCount) - ? _mtlFormatDescIndicesByMTLPixelFormatsCore[mtlFormat] - : _mtlFormatDescIndicesByMTLPixelFormatsExt[mtlFormat]); - return _mtlPixelFormatDescriptions[fmtIdx]; + return _mtlPixelFormatDescriptions[mtlFormat]; } // Return a reference to the Metal format descriptor corresponding to the MTLVertexFormat. MVKMTLFormatDesc& MVKPixelFormats::getMTLVertexFormatDesc(MTLVertexFormat mtlFormat) { - return _mtlVertexFormatDescriptions[mtlFormat < _mtlVertexFormatCount ? mtlFormat : 0]; + return _mtlVertexFormatDescriptions[mtlFormat]; } @@ -794,7 +788,6 @@ MVKPixelFormats::MVKPixelFormats(MVKPhysicalDevice* physicalDevice) : _physicalD // Build and update the Metal formats initMTLPixelFormatCapabilities(); initMTLVertexFormatCapabilities(); - buildMTLFormatMaps(); modifyMTLFormatCapabilities(); // Build the Vulkan formats and link them to the Metal formats @@ -803,11 +796,11 @@ MVKPixelFormats::MVKPixelFormats(MVKPhysicalDevice* physicalDevice) : _physicalD } #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_COMPONENT_SWIZZLE_ ##SWIZ_R, VK_COMPONENT_SWIZZLE_ ##SWIZ_G, VK_COMPONENT_SWIZZLE_ ##SWIZ_B, VK_COMPONENT_SWIZZLE_ ##SWIZ_A }, \ - "VK_FORMAT_" #VK_FMT, false } + vkFmt = VK_FORMAT_ ##VK_FMT; \ + _vkFormatDescriptions[vkFmt] = { vkFmt, 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_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, IDENTITY, IDENTITY, IDENTITY, IDENTITY) @@ -819,12 +812,7 @@ MVKPixelFormats::MVKPixelFormats(MVKPhysicalDevice* physicalDevice) : _physicalD 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() { - - mvkClear(_vkFormatDescriptions, _vkFormatCount); - - uint32_t fmtIdx = 0; - - // When adding to this list, be sure to ensure _vkFormatCount is large enough for the format count + VkFormat vkFmt; // UNDEFINED must come first. addVkFormatDesc( UNDEFINED, Invalid, Invalid, Invalid, Invalid, 1, 1, 0, None ); @@ -1115,15 +1103,14 @@ void MVKPixelFormats::initVkFormatCapabilities() { addVkFormatDescChromaSubsampling( G16_B16R16_2PLANE_422_UNORM, Invalid, 2, 16, 2, 1, 8 ); addVkFormatDescChromaSubsampling( G16_B16_R16_3PLANE_444_UNORM, Invalid, 3, 16, 1, 1, 6 ); - // When adding to this list, be sure to ensure _vkFormatCount is large enough for the format count + _vkFormatDescriptions.shrink_to_fit(); } - #define addMTLPixelFormatDescFull(MTL_FMT, VIEW_CLASS, IOS_CAPS, MACOS_CAPS, MTL_FMT_LINEAR) \ - MVKAssert(fmtIdx < _mtlPixelFormatCount, "Attempting to describe %d MTLPixelFormats, but only have space for %d. Increase the value of _mtlPixelFormatCount", fmtIdx + 1, _mtlPixelFormatCount); \ - _mtlPixelFormatDescriptions[fmtIdx++] = { .mtlPixelFormat = MTLPixelFormat ##MTL_FMT, VK_FORMAT_UNDEFINED, \ - mvkSelectPlatformValue(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS), \ - MVKMTLViewClass:: VIEW_CLASS, MTLPixelFormat ##MTL_FMT_LINEAR, "MTLPixelFormat" #MTL_FMT } + mtlPixFmt = MTLPixelFormat ##MTL_FMT; \ + _mtlPixelFormatDescriptions[mtlPixFmt] = { .mtlPixelFormat = mtlPixFmt, VK_FORMAT_UNDEFINED, \ + mvkSelectPlatformValue(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS), \ + MVKMTLViewClass:: VIEW_CLASS, MTLPixelFormat ##MTL_FMT_LINEAR, "MTLPixelFormat" #MTL_FMT } #define addMTLPixelFormatDesc(MTL_FMT, VIEW_CLASS, IOS_CAPS, MACOS_CAPS) \ addMTLPixelFormatDescFull(MTL_FMT, VIEW_CLASS, IOS_CAPS, MACOS_CAPS, MTL_FMT) @@ -1133,12 +1120,7 @@ void MVKPixelFormats::initVkFormatCapabilities() { void MVKPixelFormats::initMTLPixelFormatCapabilities() { - - mvkClear(_mtlPixelFormatDescriptions, _mtlPixelFormatCount); - - uint32_t fmtIdx = 0; - - // When adding to this list, be sure to ensure _mtlPixelFormatCount is large enough for the format count + MTLPixelFormat mtlPixFmt; // MTLPixelFormatInvalid must come first. addMTLPixelFormatDesc ( Invalid, None, None, None ); @@ -1307,26 +1289,21 @@ void MVKPixelFormats::initMTLPixelFormatCapabilities() { addMTLPixelFormatDesc ( X24_Stencil8, Depth24_Stencil8, None, DRMR ); addMTLPixelFormatDesc ( X32_Stencil8, Depth32_Stencil8, DRM, DRMR ); - // When adding to this list, be sure to ensure _mtlPixelFormatCount is large enough for the format count + _mtlPixelFormatDescriptions.shrink_to_fit(); } +// If necessary, resize vector with empty elements #define addMTLVertexFormatDesc(MTL_VTX_FMT, IOS_CAPS, MACOS_CAPS) \ mtlVtxFmt = MTLVertexFormat ##MTL_VTX_FMT; \ - if (mtlVtxFmt < _mtlVertexFormatCount) { \ - _mtlVertexFormatDescriptions[mtlVtxFmt] = { .mtlVertexFormat = mtlVtxFmt, VK_FORMAT_UNDEFINED, \ - mvkSelectPlatformValue(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS), \ - MVKMTLViewClass::None, MTLPixelFormatInvalid, "MTLVertexFormat" #MTL_VTX_FMT }; \ - } else { \ - MVKAssert(false, "Attempting to describe at least %lu MTLVertexFormats, but only have space for %d. Increase the value of _mtlVertexFormatCount", mtlVtxFmt + 1, _mtlVertexFormatCount); \ - } +if (mtlVtxFmt >= _mtlVertexFormatDescriptions.size()) { _mtlVertexFormatDescriptions.resize(mtlVtxFmt + 1, {}); } \ + _mtlVertexFormatDescriptions[mtlVtxFmt] = { .mtlVertexFormat = mtlVtxFmt, VK_FORMAT_UNDEFINED, \ + mvkSelectPlatformValue(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS), \ + MVKMTLViewClass::None, MTLPixelFormatInvalid, "MTLVertexFormat" #MTL_VTX_FMT }; void MVKPixelFormats::initMTLVertexFormatCapabilities() { + MTLVertexFormat mtlVtxFmt; - mvkClear(_mtlVertexFormatDescriptions, _mtlVertexFormatCount); - - MTLVertexFormat mtlVtxFmt = MTLVertexFormatInvalid; - - // When adding to this list, be sure to ensure _mtlVertexFormatCount is large enough for the format count + _mtlVertexFormatDescriptions.reserve(MTLVertexFormatHalf + 3); addMTLVertexFormatDesc( Invalid, None, None ); // MTLVertexFormatInvalid must come first. @@ -1395,28 +1372,7 @@ void MVKPixelFormats::initMTLVertexFormatCapabilities() { addMTLVertexFormatDesc( UChar4Normalized_BGRA, None, None ); - // When adding to this list, be sure to ensure _mtlVertexFormatCount is large enough for the format count -} - -// Populates the Metal lookup maps -void MVKPixelFormats::buildMTLFormatMaps() { - - // Set all MTLPixelFormats lookups to undefined/invalid - mvkClear(_mtlFormatDescIndicesByMTLPixelFormatsCore, _mtlPixelFormatCoreCount); - - // Build lookup table for MTLPixelFormat specs. - // For most Metal format values, which are small and consecutive, use a simple lookup array. - // For outlier format values, which can be large, use a map. - for (uint32_t fmtIdx = 0; fmtIdx < _mtlPixelFormatCount; fmtIdx++) { - MTLPixelFormat fmt = _mtlPixelFormatDescriptions[fmtIdx].mtlPixelFormat; - if (fmt) { - if (fmt < _mtlPixelFormatCoreCount) { - _mtlFormatDescIndicesByMTLPixelFormatsCore[fmt] = fmtIdx; - } else { - _mtlFormatDescIndicesByMTLPixelFormatsExt[fmt] = fmtIdx; - } - } - } + _mtlVertexFormatDescriptions.shrink_to_fit(); } // If the device supports the feature set, add additional capabilities to a MTLPixelFormat @@ -1985,69 +1941,50 @@ void MVKPixelFormats::modifyMTLFormatCapabilities(id mtlDevice) { #undef addFeatSetMTLVtxFmtCaps #undef addGPUOSMTLVtxFmtCaps -// Populates the VkFormat lookup maps and connects Vulkan and Metal pixel formats to one-another. +// Connects Vulkan and Metal pixel formats to one-another. void MVKPixelFormats::buildVkFormatMaps() { - - // Set the VkFormats to undefined/invalid - mvkClear(_vkFormatDescIndicesByVkFormatsCore, _vkFormatCoreCount); - - // Iterate through the VkFormat descriptions, populate the lookup maps and back pointers, - // and validate the Metal formats for the platform and OS. - for (uint32_t fmtIdx = 0; fmtIdx < _vkFormatCount; fmtIdx++) { - MVKVkFormatDesc& vkDesc = _vkFormatDescriptions[fmtIdx]; - VkFormat vkFmt = vkDesc.vkFormat; - if (vkFmt) { - // Create a lookup between the Vulkan format and an index to the format info. - // For core Vulkan format values, which are small and consecutive, use a simple lookup array. - // For extension format values, which can be large, use a map. - if (vkFmt < _vkFormatCoreCount) { - _vkFormatDescIndicesByVkFormatsCore[vkFmt] = fmtIdx; - } else { - _vkFormatDescIndicesByVkFormatsExt[vkFmt] = fmtIdx; - } - - if (vkDesc.needsSwizzle()) { - if (_physicalDevice) { - id mtlDev = _physicalDevice->getMTLDevice(); + for (auto& vkDesc : _vkFormatDescriptions) { + if (vkDesc.needsSwizzle()) { + if (_physicalDevice) { + id mtlDev = _physicalDevice->getMTLDevice(); #if MVK_MACCAT - bool supportsNativeTextureSwizzle = [mtlDev supportsFamily: MTLGPUFamilyMacCatalyst2]; + bool supportsNativeTextureSwizzle = [mtlDev supportsFamily: MTLGPUFamilyMacCatalyst2]; #elif MVK_MACOS - bool supportsNativeTextureSwizzle = mvkOSVersionIsAtLeast(10.15) && [mtlDev supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1]; + bool supportsNativeTextureSwizzle = mvkOSVersionIsAtLeast(10.15) && [mtlDev supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1]; #endif #if MVK_IOS || MVK_TVOS - bool supportsNativeTextureSwizzle = mtlDev && mvkOSVersionIsAtLeast(13.0); + bool supportsNativeTextureSwizzle = mtlDev && mvkOSVersionIsAtLeast(13.0); #endif - if (!supportsNativeTextureSwizzle && !getMVKConfig().fullImageViewSwizzle) { - vkDesc.mtlPixelFormat = vkDesc.mtlPixelFormatSubstitute = MTLPixelFormatInvalid; - } + if (!supportsNativeTextureSwizzle && !getMVKConfig().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. - if (vkDesc.mtlPixelFormat) { - auto& mtlDesc = getMTLPixelFormatDesc(vkDesc.mtlPixelFormat); - if ( !mtlDesc.vkFormat ) { mtlDesc.vkFormat = vkFmt; } - if ( !mtlDesc.isSupported() ) { vkDesc.mtlPixelFormat = MTLPixelFormatInvalid; } - } - if (vkDesc.mtlPixelFormatSubstitute) { - auto& mtlDesc = getMTLPixelFormatDesc(vkDesc.mtlPixelFormatSubstitute); - if ( !mtlDesc.isSupported() ) { vkDesc.mtlPixelFormatSubstitute = MTLPixelFormatInvalid; } - } - if (vkDesc.mtlVertexFormat) { - auto& mtlDesc = getMTLVertexFormatDesc(vkDesc.mtlVertexFormat); - if ( !mtlDesc.vkFormat ) { mtlDesc.vkFormat = vkFmt; } - if ( !mtlDesc.isSupported() ) { vkDesc.mtlVertexFormat = MTLVertexFormatInvalid; } - } - if (vkDesc.mtlVertexFormatSubstitute) { - auto& mtlDesc = getMTLVertexFormatDesc(vkDesc.mtlVertexFormatSubstitute); - if ( !mtlDesc.isSupported() ) { vkDesc.mtlVertexFormatSubstitute = MTLVertexFormatInvalid; } - } - - // Set Vulkan format properties - setFormatProperties(vkDesc); } + + // Populate the back reference from the Metal formats to the Vulkan format. + // Validate the corresponding Metal formats for the platform, and clear them + // if the Vulkan format if not supported. + if (vkDesc.mtlPixelFormat) { + auto& mtlDesc = getMTLPixelFormatDesc(vkDesc.mtlPixelFormat); + if ( !mtlDesc.vkFormat ) { mtlDesc.vkFormat = vkDesc.vkFormat; } + if ( !mtlDesc.isSupported() ) { vkDesc.mtlPixelFormat = MTLPixelFormatInvalid; } + } + if (vkDesc.mtlPixelFormatSubstitute) { + auto& mtlDesc = getMTLPixelFormatDesc(vkDesc.mtlPixelFormatSubstitute); + if ( !mtlDesc.isSupported() ) { vkDesc.mtlPixelFormatSubstitute = MTLPixelFormatInvalid; } + } + if (vkDesc.mtlVertexFormat) { + auto& mtlDesc = getMTLVertexFormatDesc(vkDesc.mtlVertexFormat); + if ( !mtlDesc.vkFormat ) { mtlDesc.vkFormat = vkDesc.vkFormat; } + if ( !mtlDesc.isSupported() ) { vkDesc.mtlVertexFormat = MTLVertexFormatInvalid; } + } + if (vkDesc.mtlVertexFormatSubstitute) { + auto& mtlDesc = getMTLVertexFormatDesc(vkDesc.mtlVertexFormatSubstitute); + if ( !mtlDesc.isSupported() ) { vkDesc.mtlVertexFormatSubstitute = MTLVertexFormatInvalid; } + } + + // Set Vulkan format properties + setFormatProperties(vkDesc); } } diff --git a/MoltenVK/MoltenVK/Utility/MVKInflectionMap.h b/MoltenVK/MoltenVK/Utility/MVKInflectionMap.h new file mode 100755 index 00000000..b536451f --- /dev/null +++ b/MoltenVK/MoltenVK/Utility/MVKInflectionMap.h @@ -0,0 +1,105 @@ +/* + * MVKInflectionMap.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. + */ + +#pragma once + +#include "MVKSmallVector.h" +#include + +/** + * An unordered map that splits elements between a fast-access vector of LinearCount consecutively + * indexed elements, and a slower-access map holding sparse indexes larger than LinearCount. + * + * This design can be useful for a collection that is indexed by an enum that has a large + * set of consecutive elements, plus additional enum values that are more sparsely assigned. + * Examples of these enums are VkFormat and MTLPixelFormat. + * + * KeyType is used to lookup values, and must be a type that is convertable to an unsigned integer. + * ValueType must have an empty constructor (default or otherwise). + * IndexType must be a type that is convertable to an unsigned integer (eg. uint8_t...uint64_t), + * and which is large enough to represent the number of values in this map. + * Iteration can be accomplished as + */ +template +class MVKInflectionMap { + +public: + using value_type = ValueType; + class iterator { + MVKInflectionMap* map; + IndexType index; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = ValueType; + using pointer = value_type*; + using reference = value_type&; + + iterator() : map(nullptr), index(0) {} + iterator(MVKInflectionMap& m, const IndexType i) : map(&m), index(i) {} + + iterator &operator=( const iterator &it ) { + map = it.map; + index = it.index; + return *this; + } + + ValueType* operator->() { return &map->_values[index]; } + ValueType& operator*() { return map->_values[index]; } + operator ValueType*() { return &map->_values[index]; } + + bool operator==(const iterator& it) const { return map == it.map && index == it.index; } + bool operator!=(const iterator& it) const { return map != it.map || index != it.index; } + + iterator& operator++() { index++; return *this; } + iterator operator++( int ) { auto t = *this; index++; return t; } + + bool is_valid() const { return index < map->_values.size(); } + }; + using reverse_iterator = std::reverse_iterator; + + const ValueType& operator[](const KeyType idx) const { return getValue(idx); } + ValueType& operator[](const KeyType idx) { return getValue(idx); } + + iterator begin() { return iterator(*this, 0); } + iterator end() { return iterator(*this, _values.size()); } + + bool empty() { return _values.size() == 0; } + size_t size() { return _values.size(); } + void shrink_to_fit() { _values.shrink_to_fit(); } + +protected: + static constexpr IndexType kMVKInflectionMapValueMissing = std::numeric_limits::max(); + typedef struct IndexValue { IndexType value = kMVKInflectionMapValueMissing; } IndexValue; + + // Returns a refrence to the value at the index. + // If the index has not been initialized, add an empty element at + // the end of the values array, and set the index to its position. + ValueType& getValue(KeyType idx) { + IndexValue& valIdx = idx < LinearCount ? _linearIndexes[idx] : _inflectionIndexes[idx]; + if (valIdx.value == kMVKInflectionMapValueMissing) { + _values.push_back({}); + valIdx.value = _values.size() - 1; + } + return _values[valIdx.value]; + } + + MVKSmallVector _values; + std::unordered_map _inflectionIndexes; + IndexValue _linearIndexes[LinearCount]; +}; diff --git a/Scripts/runcts b/Scripts/runcts index 735e84ef..86ddcc40 100755 --- a/Scripts/runcts +++ b/Scripts/runcts @@ -131,4 +131,4 @@ start_time=${SECONDS} --deqp-caselist-file="${caselist_file}" \ &> "${results_file}" -echo Testing complete in $(($SECONDS - $start_time)) seconds +echo Testing complete in $(($SECONDS - $start_time)) seconds at `date +%r`