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).
This commit is contained in:
Bill Hollings 2023-12-27 19:34:23 -05:00
parent fe65485bfb
commit 88799cf255
5 changed files with 180 additions and 146 deletions

View File

@ -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 = "<group>"; };
A99C91012295FAC500A061DA /* MVKVulkanAPIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKVulkanAPIObject.h; sourceTree = "<group>"; };
A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MVKEnvironment.cpp; sourceTree = "<group>"; };
A9AB95292B3EDFCC00C4E967 /* MVKInflectionMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKInflectionMap.h; sourceTree = "<group>"; };
A9AD67C72054DD6C00ED3C08 /* vulkan */ = {isa = PBXFileReference; lastKnownFileType = folder; path = vulkan; sourceTree = "<group>"; };
A9B3D73829F9B3B100745CD4 /* mvk_deprecated_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mvk_deprecated_api.h; sourceTree = "<group>"; };
A9B3D73A29F9B3B100745CD4 /* mvk_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mvk_config.h; sourceTree = "<group>"; };
@ -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 */,

View File

@ -20,6 +20,7 @@
#include "MVKBaseObject.h"
#include "MVKOSExtensions.h"
#include "MVKInflectionMap.h"
#include "mvk_datatypes.hpp"
#include <spirv_msl.hpp>
#include <unordered_map>
@ -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<uint32_t, uint32_t> _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<NSUInteger, uint32_t> _mtlFormatDescIndicesByMTLPixelFormatsExt;
MVKInflectionMap<VkFormat, MVKVkFormatDesc, VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1> _vkFormatDescriptions;
MVKInflectionMap<uint16_t, MVKMTLFormatDesc, MTLPixelFormatX32_Stencil8 + 2> _mtlPixelFormatDescriptions; // The actual last enum value is not available on iOS
MVKSmallVector<MVKMTLFormatDesc> _mtlVertexFormatDescriptions;
};

View File

@ -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<MVKMTLFmtCaps>(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<MVKMTLFmtCaps>(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<MVKMTLFmtCaps>(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<MVKMTLFmtCaps>(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> 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<MTLDevice> mtlDev = _physicalDevice->getMTLDevice();
for (auto& vkDesc : _vkFormatDescriptions) {
if (vkDesc.needsSwizzle()) {
if (_physicalDevice) {
id<MTLDevice> 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);
}
}

View File

@ -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 <unordered_map>
/**
* 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<typename KeyType, typename ValueType, size_t LinearCount, typename IndexType = uint16_t>
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<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<IndexType>::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<ValueType> _values;
std::unordered_map<KeyType, IndexValue> _inflectionIndexes;
IndexValue _linearIndexes[LinearCount];
};

View File

@ -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`