diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 374bd2dd..e7daeb84 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -13,6 +13,15 @@ Copyright (c) 2015-2021 [The Brenwill Workshop Ltd.](http://www.brenwill.com) +MoltenVK 1.1.5 +-------------- + +Released TBD + +- Fix incorrect translation of clear color values on Apple Silicon. + + + MoltenVK 1.1.4 -------------- diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index c77d52d9..149dd217 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -50,12 +50,12 @@ typedef unsigned long MTLLanguageVersion; */ #define MVK_VERSION_MAJOR 1 #define MVK_VERSION_MINOR 1 -#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) -#define VK_MVK_MOLTENVK_SPEC_VERSION 31 +#define VK_MVK_MOLTENVK_SPEC_VERSION 32 #define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk" /** Identifies the level of logging MoltenVK should be limited to outputting. */ @@ -827,6 +827,14 @@ typedef struct { } 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; + /** * Features provided by the current implementation of Metal on the current device. You can * retrieve a copy of this structure using the vkGetPhysicalDeviceMetalFeaturesMVK() function. @@ -906,6 +914,7 @@ typedef struct { 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. */ } MVKPhysicalDeviceMetalFeatures; /** MoltenVK performance of a particular type of activity. */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index ac1dbfd4..1e8146ba 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1192,6 +1192,19 @@ void MVKPhysicalDevice::initMetalFeatures() { _metalFeatures.maxPerStageStorageTextureCount = 8; + // GPU-specific features + switch (_properties.vendorID) { + case kAMDVendorId: + _metalFeatures.clearColorFloatRounding = MVK_FLOAT_ROUNDING_DOWN; + break; + case kAppleVendorId: + case kIntelVendorId: + case kNVVendorId: + default: + _metalFeatures.clearColorFloatRounding = MVK_FLOAT_ROUNDING_NEAREST; + break; + } + #if MVK_TVOS _metalFeatures.mslVersionEnum = MTLLanguageVersion1_1; _metalFeatures.mtlBufferAlignment = 64; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index 22117dcc..c40a156a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -467,100 +467,108 @@ MTLClearColor MVKPixelFormats::getMTLClearColor(VkClearValue vkClearValue, VkFor mtlClr.green = vkClearValue.color.float32[1]; mtlClr.blue = vkClearValue.color.float32[2]; mtlClr.alpha = vkClearValue.color.float32[3]; - // For normalized formats, increment the clear value by half the minimum delta - // (i.e. 1/(2*(2**component_size - 1))), to force Metal to round up. This should - // fix some problems with clear values being off by one. -#define OFFSET_UNORM(COLOR, DENOM) if (mtlClr.COLOR > 0.0 && mtlClr.COLOR < 1.0) { mtlClr.COLOR += 1.0/DENOM; } -#define OFFSET_SNORM(COLOR, DENOM) if (mtlClr.COLOR > -1.0 && mtlClr.COLOR < 1.0) { mtlClr.COLOR += 1.0/DENOM; } - switch (vkFormat) { - case VK_FORMAT_R4G4B4A4_UNORM_PACK16: - OFFSET_UNORM(red, 30.0) - OFFSET_UNORM(green, 30.0) - OFFSET_UNORM(blue, 30.0) - OFFSET_UNORM(alpha, 30.0); - break; - case VK_FORMAT_R5G6B5_UNORM_PACK16: - OFFSET_UNORM(red, 62.0) - OFFSET_UNORM(green, 126.0) - OFFSET_UNORM(blue, 62.0) - break; - case VK_FORMAT_R5G5B5A1_UNORM_PACK16: - case VK_FORMAT_A1R5G5B5_UNORM_PACK16: - OFFSET_UNORM(red, 62.0) - OFFSET_UNORM(green, 62.0) - OFFSET_UNORM(blue, 62.0) - break; - case VK_FORMAT_R8_UNORM: - case VK_FORMAT_R8_SRGB: - OFFSET_UNORM(red, 510.0) - break; - case VK_FORMAT_R8_SNORM: - OFFSET_SNORM(red, 254.0) - break; - case VK_FORMAT_R8G8_UNORM: - case VK_FORMAT_R8G8_SRGB: - OFFSET_UNORM(red, 510.0) - OFFSET_UNORM(green, 510.0) - break; - case VK_FORMAT_R8G8_SNORM: - OFFSET_SNORM(red, 254.0) - OFFSET_SNORM(green, 254.0) - break; - case VK_FORMAT_R8G8B8A8_UNORM: - case VK_FORMAT_R8G8B8A8_SRGB: - case VK_FORMAT_B8G8R8A8_UNORM: - case VK_FORMAT_B8G8R8A8_SRGB: - case VK_FORMAT_A8B8G8R8_UNORM_PACK32: - case VK_FORMAT_A8B8G8R8_SRGB_PACK32: - OFFSET_UNORM(red, 510.0) - OFFSET_UNORM(green, 510.0) - OFFSET_UNORM(blue, 510.0) - OFFSET_UNORM(alpha, 510.0) - break; - case VK_FORMAT_R8G8B8A8_SNORM: - OFFSET_SNORM(red, 254.0) - OFFSET_SNORM(green, 254.0) - OFFSET_SNORM(blue, 254.0) - OFFSET_SNORM(alpha, 254.0) - break; - case VK_FORMAT_A2R10G10B10_UNORM_PACK32: - case VK_FORMAT_A2B10G10R10_UNORM_PACK32: - OFFSET_UNORM(red, 2046.0) - OFFSET_UNORM(green, 2046.0) - OFFSET_UNORM(blue, 2046.0) - OFFSET_UNORM(alpha, 6.0) - break; - case VK_FORMAT_R16_UNORM: - OFFSET_UNORM(red, 131070.0) - break; - case VK_FORMAT_R16_SNORM: - OFFSET_SNORM(red, 65534.0) - break; - case VK_FORMAT_R16G16_UNORM: - OFFSET_UNORM(red, 131070.0) - OFFSET_UNORM(green, 131070.0) - break; - case VK_FORMAT_R16G16_SNORM: - OFFSET_SNORM(red, 65534.0) - OFFSET_SNORM(green, 65534.0) - break; - case VK_FORMAT_R16G16B16A16_UNORM: - OFFSET_UNORM(red, 131070.0) - OFFSET_UNORM(green, 131070.0) - OFFSET_UNORM(blue, 131070.0) - OFFSET_UNORM(alpha, 131070.0) - break; - case VK_FORMAT_R16G16B16A16_SNORM: - OFFSET_SNORM(red, 65534.0) - OFFSET_SNORM(green, 65534.0) - OFFSET_SNORM(blue, 65534.0) - OFFSET_SNORM(alpha, 65534.0) - break; - default: - break; - } + + if (_physicalDevice && _physicalDevice->getMetalFeatures()->clearColorFloatRounding == MVK_FLOAT_ROUNDING_DOWN) { + // For normalized formats, increment the clear value by half the ULP + // (i.e. 1/(2*(2**component_size - 1))), to force Metal to round up. + // This should fix some problems with clear values being off by one ULP on some platforms. +#define OFFSET_NORM(MIN_VAL, COLOR, BIT_WIDTH) \ + if (mtlClr.COLOR > (MIN_VAL) && mtlClr.COLOR < 1.0) { \ + mtlClr.COLOR += 1.0 / (2.0 * ((1U << (BIT_WIDTH)) - 1)); \ + } +#define OFFSET_UNORM(COLOR, BIT_WIDTH) OFFSET_NORM(0.0, COLOR, BIT_WIDTH) +#define OFFSET_SNORM(COLOR, BIT_WIDTH) OFFSET_NORM(-1.0, COLOR, BIT_WIDTH - 1) + switch (vkFormat) { + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + OFFSET_UNORM(red, 4) + OFFSET_UNORM(green, 4) + OFFSET_UNORM(blue, 4) + OFFSET_UNORM(alpha, 4) + break; + case VK_FORMAT_R5G6B5_UNORM_PACK16: + OFFSET_UNORM(red, 5) + OFFSET_UNORM(green, 6) + OFFSET_UNORM(blue, 5) + break; + case VK_FORMAT_R5G5B5A1_UNORM_PACK16: + case VK_FORMAT_A1R5G5B5_UNORM_PACK16: + OFFSET_UNORM(red, 5) + OFFSET_UNORM(green, 5) + OFFSET_UNORM(blue, 5) + break; + case VK_FORMAT_R8_UNORM: + case VK_FORMAT_R8_SRGB: + OFFSET_UNORM(red, 8) + break; + case VK_FORMAT_R8_SNORM: + OFFSET_SNORM(red, 8) + break; + case VK_FORMAT_R8G8_UNORM: + case VK_FORMAT_R8G8_SRGB: + OFFSET_UNORM(red, 8) + OFFSET_UNORM(green, 8) + break; + case VK_FORMAT_R8G8_SNORM: + OFFSET_SNORM(red, 8) + OFFSET_SNORM(green, 8) + break; + case VK_FORMAT_R8G8B8A8_UNORM: + case VK_FORMAT_R8G8B8A8_SRGB: + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_B8G8R8A8_SRGB: + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + OFFSET_UNORM(red, 8) + OFFSET_UNORM(green, 8) + OFFSET_UNORM(blue, 8) + OFFSET_UNORM(alpha, 8) + break; + case VK_FORMAT_R8G8B8A8_SNORM: + OFFSET_SNORM(red, 8) + OFFSET_SNORM(green, 8) + OFFSET_SNORM(blue, 8) + OFFSET_SNORM(alpha, 8) + break; + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + OFFSET_UNORM(red, 10) + OFFSET_UNORM(green, 10) + OFFSET_UNORM(blue, 10) + OFFSET_UNORM(alpha, 2) + break; + case VK_FORMAT_R16_UNORM: + OFFSET_UNORM(red, 16) + break; + case VK_FORMAT_R16_SNORM: + OFFSET_SNORM(red, 16) + break; + case VK_FORMAT_R16G16_UNORM: + OFFSET_UNORM(red, 16) + OFFSET_UNORM(green, 16) + break; + case VK_FORMAT_R16G16_SNORM: + OFFSET_SNORM(red, 16) + OFFSET_SNORM(green, 16) + break; + case VK_FORMAT_R16G16B16A16_UNORM: + OFFSET_UNORM(red, 16) + OFFSET_UNORM(green, 16) + OFFSET_UNORM(blue, 16) + OFFSET_UNORM(alpha, 16) + break; + case VK_FORMAT_R16G16B16A16_SNORM: + OFFSET_SNORM(red, 16) + OFFSET_SNORM(green, 16) + OFFSET_SNORM(blue, 16) + OFFSET_SNORM(alpha, 16) + break; + default: + break; + } #undef OFFSET_UNORM #undef OFFSET_SNORM +#undef OFFSET_NORM + } break; case kMVKFormatColorUInt8: case kMVKFormatColorUInt16: