Merge pull request #1395 from billhollings/apple-silicon-clear-color-adjustment

Fix incorrect translation of clear color values on Apple Silicon.
This commit is contained in:
Bill Hollings 2021-07-05 14:04:53 -04:00 committed by GitHub
commit 9534c3b9ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 133 additions and 94 deletions

View File

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

View File

@ -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. */

View File

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

View File

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