Merge pull request #1395 from billhollings/apple-silicon-clear-color-adjustment
Fix incorrect translation of clear color values on Apple Silicon.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 374bd2d..e7daeb8 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -13,6 +13,15 @@
+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 c77d52d..149dd21 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -50,12 +50,12 @@
*/
#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 @@
} 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 @@
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 ac1dbfd..1e8146b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -1192,6 +1192,19 @@
_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 22117dc..c40a156 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
@@ -467,100 +467,108 @@
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: