Support the VK_EXT_4444_formats
extension.
This turned out to be a little bit more involved than I had hoped. But, with this, we can now use the `VK_FORMAT_A4R4G4B4_UNORM_PACK16` and `VK_FORMAT_A4B4G4R4_UNORM_PACK16` formats from shaders, use them as blit sources, and even clear them. Storage images and render targets of these formats aren't supported, however. To support the latter would require the insertion of a swizzle into the fragment shader before returning. The former cannot be reasonably supported.
This commit is contained in:
parent
9356c89bd5
commit
5d173d0e09
@ -350,6 +350,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
|
||||
- `VK_KHR_timeline_semaphore`
|
||||
- `VK_KHR_uniform_buffer_standard_layout`
|
||||
- `VK_KHR_variable_pointers`
|
||||
- `VK_EXT_4444_formats` *(requires 16-bit formats and either native texture swizzling or manual swizzling to be enabled)*
|
||||
- `VK_EXT_buffer_device_address` *(requires GPU Tier 2 argument buffers support)*
|
||||
- `VK_EXT_debug_marker`
|
||||
- `VK_EXT_debug_report`
|
||||
|
@ -19,6 +19,7 @@ MoltenVK 1.2.5
|
||||
Released TBD
|
||||
|
||||
- Add support for extensions:
|
||||
- `VK_EXT_4444_formats`
|
||||
- `VK_EXT_shader_demote_to_helper_invocation`
|
||||
- Ensure non-dispatch compute commands don't interfere with compute encoding state used by dispatch commands.
|
||||
- Support `VK_PRESENT_MODE_IMMEDIATE_KHR` if `VkPresentTimeGOOGLE::desiredPresentTime` is zero.
|
||||
|
@ -227,6 +227,15 @@ MTLTextureSwizzle mvkMTLTextureSwizzleFromVkComponentSwizzle(VkComponentSwizzle
|
||||
/** Returns all four Metal texture swizzles from the Vulkan component mapping. */
|
||||
MTLTextureSwizzleChannels mvkMTLTextureSwizzleChannelsFromVkComponentMapping(VkComponentMapping vkMapping);
|
||||
|
||||
/** Maps a clear color according to the specified VkComponentSwizzle. */
|
||||
float mvkVkClearColorFloatValueFromVkComponentSwizzle(float *colors, uint32_t index, VkComponentSwizzle vkSwizzle);
|
||||
|
||||
/** Maps a clear color according to the specified VkComponentSwizzle. */
|
||||
uint32_t mvkVkClearColorUIntValueFromVkComponentSwizzle(uint32_t *colors, uint32_t index, VkComponentSwizzle vkSwizzle);
|
||||
|
||||
/** Maps a clear color according to the specified VkComponentSwizzle. */
|
||||
int32_t mvkVkClearColorIntValueFromVkComponentSwizzle(int32_t *colors, uint32_t index, VkComponentSwizzle vkSwizzle);
|
||||
|
||||
|
||||
#pragma mark Mipmaps
|
||||
|
||||
|
@ -374,6 +374,7 @@ bool MVKCmdBlitImage<N>::canCopyFormats(const VkImageBlit2& region) {
|
||||
uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(region.srcSubresource.aspectMask);
|
||||
uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(region.dstSubresource.aspectMask);
|
||||
return ((_srcImage->getMTLPixelFormat(srcPlaneIndex) == _dstImage->getMTLPixelFormat(dstPlaneIndex)) &&
|
||||
!_srcImage->needsSwizzle() &&
|
||||
(_dstImage->getSampleCount() == _srcImage->getSampleCount()));
|
||||
}
|
||||
|
||||
@ -456,7 +457,7 @@ void MVKCmdBlitImage<N>::encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse com
|
||||
uint32_t copyCnt = 0;
|
||||
uint32_t blitCnt = 0;
|
||||
|
||||
// Separate BLITs into those that are really just simple texure region copies,
|
||||
// Separate BLITs into those that are really just simple texture region copies,
|
||||
// and those that require rendering
|
||||
for (auto& vkIB : _vkImageBlits) {
|
||||
if (canCopyFormats(vkIB) && canCopy(vkIB)) {
|
||||
@ -500,6 +501,15 @@ void MVKCmdBlitImage<N>::encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse com
|
||||
id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture(srcPlaneIndex);
|
||||
id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture(dstPlaneIndex);
|
||||
if (blitCnt && srcMTLTex && dstMTLTex) {
|
||||
if (cmdEncoder->getDevice()->_pMetalFeatures->nativeTextureSwizzle &&
|
||||
_srcImage->needsSwizzle()) {
|
||||
// Use a view that has a swizzle on it.
|
||||
srcMTLTex = [[srcMTLTex newTextureViewWithPixelFormat:srcMTLTex.pixelFormat
|
||||
textureType:srcMTLTex.textureType
|
||||
levels:NSMakeRange(0, srcMTLTex.mipmapLevelCount)
|
||||
slices:NSMakeRange(0, srcMTLTex.arrayLength)
|
||||
swizzle:_srcImage->getPixelFormats()->getMTLTextureSwizzleChannels(_srcImage->getVkFormat())] autorelease];
|
||||
}
|
||||
cmdEncoder->endCurrentMetalEncoding();
|
||||
|
||||
MTLRenderPassDescriptor* mtlRPD = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
@ -549,6 +559,14 @@ void MVKCmdBlitImage<N>::encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse com
|
||||
blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(_filter);
|
||||
blitKey.srcAspect = mvkIBR.region.srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
blitKey.dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_dstImage->getSampleCount());
|
||||
if (!cmdEncoder->getDevice()->_pMetalFeatures->nativeTextureSwizzle &&
|
||||
_srcImage->needsSwizzle()) {
|
||||
VkComponentMapping vkMapping = _srcImage->getPixelFormats()->getVkComponentMapping(_srcImage->getVkFormat());
|
||||
blitKey.srcSwizzleR = vkMapping.r;
|
||||
blitKey.srcSwizzleG = vkMapping.g;
|
||||
blitKey.srcSwizzleB = vkMapping.b;
|
||||
blitKey.srcSwizzleA = vkMapping.a;
|
||||
}
|
||||
id<MTLRenderPipelineState> mtlRPS = cmdEncoder->getCommandEncodingPool()->getCmdBlitImageMTLRenderPipelineState(blitKey);
|
||||
bool isBlittingDepth = mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_DEPTH_BIT));
|
||||
bool isBlittingStencil = mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_STENCIL_BIT));
|
||||
|
@ -37,20 +37,31 @@ class MVKQueryPool;
|
||||
* This structure can be used as a key in a std::map and std::unordered_map.
|
||||
*/
|
||||
typedef struct MVKRPSKeyBlitImg {
|
||||
uint16_t srcMTLPixelFormat = 0; /**< as MTLPixelFormat */
|
||||
uint16_t dstMTLPixelFormat = 0; /**< as MTLPixelFormat */
|
||||
uint8_t srcMTLTextureType = 0; /**< as MTLTextureType */
|
||||
uint16_t srcMTLPixelFormat : 12; /**< as MTLPixelFormat */
|
||||
uint16_t dstMTLPixelFormat : 12; /**< as MTLPixelFormat */
|
||||
uint8_t srcMTLTextureType : 4; /**< as MTLTextureType */
|
||||
uint8_t srcFilter : 4; /**< as MTLSamplerMinMagFilter */
|
||||
uint8_t srcAspect = 0; /**< as VkImageAspectFlags */
|
||||
uint8_t srcFilter = 0; /**< as MTLSamplerMinMagFilter */
|
||||
uint8_t dstSampleCount = 0;
|
||||
uint8_t srcSwizzleR : 4; /**< as VkComponentSwizzle */
|
||||
uint8_t srcSwizzleG : 4; /**< as VkComponentSwizzle */
|
||||
uint8_t srcSwizzleB : 4; /**< as VkComponentSwizzle */
|
||||
uint8_t srcSwizzleA : 4; /**< as VkComponentSwizzle */
|
||||
|
||||
MVKRPSKeyBlitImg() : srcMTLPixelFormat(0), dstMTLPixelFormat(0), srcMTLTextureType(0), srcFilter(0),
|
||||
srcSwizzleR(0), srcSwizzleG(0), srcSwizzleB(0), srcSwizzleA(0) {}
|
||||
|
||||
bool operator==(const MVKRPSKeyBlitImg& rhs) const {
|
||||
if (srcMTLPixelFormat != rhs.srcMTLPixelFormat) { return false; }
|
||||
if (dstMTLPixelFormat != rhs.dstMTLPixelFormat) { return false; }
|
||||
if (srcMTLTextureType != rhs.srcMTLTextureType) { return false; }
|
||||
if (srcAspect != rhs.srcAspect) { return false; }
|
||||
if (srcFilter != rhs.srcFilter) { return false; }
|
||||
if (srcAspect != rhs.srcAspect) { return false; }
|
||||
if (dstSampleCount != rhs.dstSampleCount) { return false; }
|
||||
if (srcSwizzleR != rhs.srcSwizzleR) { return false; }
|
||||
if (srcSwizzleG != rhs.srcSwizzleG) { return false; }
|
||||
if (srcSwizzleB != rhs.srcSwizzleB) { return false; }
|
||||
if (srcSwizzleA != rhs.srcSwizzleA) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -70,23 +81,40 @@ typedef struct MVKRPSKeyBlitImg {
|
||||
srcMTLTextureType == MTLTextureType1DArray);
|
||||
}
|
||||
|
||||
VkComponentMapping getSrcSwizzle() {
|
||||
return { (VkComponentSwizzle)srcSwizzleR, (VkComponentSwizzle)srcSwizzleG,
|
||||
(VkComponentSwizzle)srcSwizzleB, (VkComponentSwizzle)srcSwizzleA };
|
||||
}
|
||||
|
||||
std::size_t hash() const {
|
||||
std::size_t hash = srcMTLPixelFormat;
|
||||
|
||||
hash <<= 16;
|
||||
hash <<= 12;
|
||||
hash |= dstMTLPixelFormat;
|
||||
|
||||
hash <<= 8;
|
||||
hash <<= 4;
|
||||
hash |= srcMTLTextureType;
|
||||
|
||||
hash <<= 4;
|
||||
hash |= srcFilter;
|
||||
|
||||
hash <<= 8;
|
||||
hash |= srcAspect;
|
||||
|
||||
hash <<= 8;
|
||||
hash |= srcFilter;
|
||||
|
||||
hash <<= 8;
|
||||
hash |= dstSampleCount;
|
||||
|
||||
hash <<= 4;
|
||||
hash |= srcSwizzleR;
|
||||
|
||||
hash <<= 4;
|
||||
hash |= srcSwizzleG;
|
||||
|
||||
hash <<= 4;
|
||||
hash |= srcSwizzleB;
|
||||
|
||||
hash <<= 4;
|
||||
hash |= srcSwizzleA;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
@ -167,6 +167,25 @@ id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdClearMTLRenderPipeli
|
||||
return rps;
|
||||
}
|
||||
|
||||
static char getSwizzleChar(char defaultChar, VkComponentSwizzle vkSwizzle) {
|
||||
switch (vkSwizzle) {
|
||||
case VK_COMPONENT_SWIZZLE_IDENTITY: return defaultChar;
|
||||
// FIXME: 0 and 1 (currently not used in any default swizzles)
|
||||
case VK_COMPONENT_SWIZZLE_R: return 'x';
|
||||
case VK_COMPONENT_SWIZZLE_G: return 'y';
|
||||
case VK_COMPONENT_SWIZZLE_B: return 'z';
|
||||
case VK_COMPONENT_SWIZZLE_A: return 'w';
|
||||
default: return defaultChar;
|
||||
}
|
||||
}
|
||||
|
||||
static void getSwizzleString(char swizzleStr[4], VkComponentMapping vkMapping) {
|
||||
swizzleStr[0] = getSwizzleChar('x', vkMapping.r);
|
||||
swizzleStr[1] = getSwizzleChar('y', vkMapping.g);
|
||||
swizzleStr[2] = getSwizzleChar('z', vkMapping.b);
|
||||
swizzleStr[3] = getSwizzleChar('w', vkMapping.a);
|
||||
}
|
||||
|
||||
id<MTLFunction> MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg& blitKey) {
|
||||
@autoreleasepool {
|
||||
bool isLayeredBlit = blitKey.dstSampleCount > 1 ? _device->_pMetalFeatures->multisampleLayeredRendering : _device->_pMetalFeatures->layeredRendering;
|
||||
@ -177,6 +196,7 @@ id<MTLFunction> MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg&
|
||||
NSString* typePrefix = @"texture";
|
||||
NSString* typeSuffix;
|
||||
NSString* coordArg;
|
||||
char swizzleArg[4] = { 'x', 'y', 'z', 'w' };
|
||||
if (mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_DEPTH_BIT))) {
|
||||
typePrefix = @"depth";
|
||||
}
|
||||
@ -208,6 +228,9 @@ id<MTLFunction> MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg&
|
||||
}
|
||||
NSString* sliceArg = isArrayType ? (isLayeredBlit ? @", subRez.slice + varyings.v_layer" : @", subRez.slice") : @"";
|
||||
NSString* srcFilter = isLinearFilter ? @"linear" : @"nearest";
|
||||
if (!getDevice()->_pMetalFeatures->nativeTextureSwizzle) {
|
||||
getSwizzleString(swizzleArg, blitKey.getSrcSwizzle());
|
||||
}
|
||||
|
||||
NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ];
|
||||
[msl appendLineMVK: @"#include <metal_stdlib>"];
|
||||
@ -263,15 +286,15 @@ id<MTLFunction> MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg&
|
||||
[msl appendLineMVK: @" constant TexSubrez& subRez [[buffer(0)]]) {"];
|
||||
[msl appendLineMVK: @" FragmentOutputs out;"];
|
||||
if (mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_DEPTH_BIT))) {
|
||||
[msl appendFormat: @" out.depth = tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod));", coordArg, sliceArg];
|
||||
[msl appendFormat: @" out.depth = tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod)).%c;", coordArg, sliceArg, swizzleArg[0]];
|
||||
[msl appendLineMVK];
|
||||
}
|
||||
if (mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_STENCIL_BIT))) {
|
||||
[msl appendFormat: @" out.stencil = stencilTex.sample(ce_stencil_sampler, varyings.v_texCoord%@%@, level(subRez.lod)).x;", coordArg, sliceArg];
|
||||
[msl appendFormat: @" out.stencil = stencilTex.sample(ce_stencil_sampler, varyings.v_texCoord%@%@, level(subRez.lod)).%c;", coordArg, sliceArg, swizzleArg[0]];
|
||||
[msl appendLineMVK];
|
||||
}
|
||||
if (!mvkIsAnyFlagEnabled(blitKey.srcAspect, (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
|
||||
[msl appendFormat: @" out.color = tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod));", coordArg, sliceArg];
|
||||
[msl appendFormat: @" out.color = tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod)).%.4s;", coordArg, sliceArg, swizzleArg];
|
||||
[msl appendLineMVK];
|
||||
}
|
||||
[msl appendLineMVK: @" return out;"];
|
||||
|
@ -371,6 +371,15 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
|
||||
portabilityFeatures->vertexAttributeAccessBeyondStride = true; // Costs additional buffers. Should make configuration switch.
|
||||
break;
|
||||
}
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: {
|
||||
auto* formatFeatures = (VkPhysicalDevice4444FormatsFeaturesEXT*)next;
|
||||
bool canSupport4444 = _metalFeatures.tileBasedDeferredRendering &&
|
||||
(_metalFeatures.nativeTextureSwizzle ||
|
||||
mvkConfig().fullImageViewSwizzle);
|
||||
formatFeatures->formatA4R4G4B4 = canSupport4444;
|
||||
formatFeatures->formatA4B4G4R4 = canSupport4444;
|
||||
break;
|
||||
}
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: {
|
||||
auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next;
|
||||
interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups;
|
||||
|
@ -62,6 +62,7 @@ MVK_DEVICE_FEATURE(VariablePointer, VARIABLE_POINTER,
|
||||
MVK_DEVICE_FEATURE(VulkanMemoryModel, VULKAN_MEMORY_MODEL, 3)
|
||||
MVK_DEVICE_FEATURE_EXTN(FragmentShaderBarycentric, FRAGMENT_SHADER_BARYCENTRIC, KHR, 1)
|
||||
MVK_DEVICE_FEATURE_EXTN(PortabilitySubset, PORTABILITY_SUBSET, KHR, 15)
|
||||
MVK_DEVICE_FEATURE_EXTN(4444Formats, 4444_FORMATS, EXT, 2)
|
||||
MVK_DEVICE_FEATURE_EXTN(FragmentShaderInterlock, FRAGMENT_SHADER_INTERLOCK, EXT, 3)
|
||||
MVK_DEVICE_FEATURE_EXTN(PipelineCreationCacheControl, PIPELINE_CREATION_CACHE_CONTROL, EXT, 1)
|
||||
MVK_DEVICE_FEATURE_EXTN(Robustness2, ROBUSTNESS_2, EXT, 3)
|
||||
|
@ -224,6 +224,9 @@ public:
|
||||
/** Returns the number of planes of this image view. */
|
||||
uint8_t getPlaneCount() { return _planes.size(); }
|
||||
|
||||
/** Returns whether or not the image format requires swizzling. */
|
||||
bool needsSwizzle() { return getPixelFormats()->needsSwizzle(_vkFormat); }
|
||||
|
||||
/** Populates the specified layout for the specified sub-resource. */
|
||||
VkResult getSubresourceLayout(const VkImageSubresource* pSubresource,
|
||||
VkSubresourceLayout* pLayout);
|
||||
|
@ -1575,6 +1575,26 @@ VkResult MVKImageViewPlane::initSwizzledMTLPixelFormat(const VkImageViewCreateIn
|
||||
VkImageAspectFlags aspectMask = pCreateInfo->subresourceRange.aspectMask;
|
||||
|
||||
#define adjustComponentSwizzleValue(comp, currVal, newVal) if (_componentSwizzle.comp == VK_COMPONENT_SWIZZLE_ ##currVal) { _componentSwizzle.comp = VK_COMPONENT_SWIZZLE_ ##newVal; }
|
||||
#define adjustAnyComponentSwizzleValue(comp, I, R, G, B, A) \
|
||||
switch (_componentSwizzle.comp) { \
|
||||
case VK_COMPONENT_SWIZZLE_IDENTITY: \
|
||||
_componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##I; \
|
||||
break; \
|
||||
case VK_COMPONENT_SWIZZLE_R: \
|
||||
_componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##R; \
|
||||
break; \
|
||||
case VK_COMPONENT_SWIZZLE_G: \
|
||||
_componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##G; \
|
||||
break; \
|
||||
case VK_COMPONENT_SWIZZLE_B: \
|
||||
_componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##B; \
|
||||
break; \
|
||||
case VK_COMPONENT_SWIZZLE_A: \
|
||||
_componentSwizzle.comp = VK_COMPONENT_SWIZZLE_##A; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
}
|
||||
|
||||
// Use swizzle adjustment to bridge some differences between Vulkan and Metal pixel formats.
|
||||
// Do this ahead of other tests and adjustments so that swizzling will be enabled by tests below.
|
||||
@ -1589,6 +1609,24 @@ VkResult MVKImageViewPlane::initSwizzledMTLPixelFormat(const VkImageViewCreateIn
|
||||
adjustComponentSwizzleValue(a, IDENTITY, ONE);
|
||||
break;
|
||||
|
||||
case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
|
||||
// Metal doesn't (publicly) support this directly, so use a swizzle to get the ordering right.
|
||||
// n.b. **Do NOT use adjustComponentSwizzleValue if multiple values need substitution,
|
||||
// and some of the substitutes are keys for other substitutions!**
|
||||
adjustAnyComponentSwizzleValue(r, G, G, B, A, R);
|
||||
adjustAnyComponentSwizzleValue(g, B, G, B, A, R);
|
||||
adjustAnyComponentSwizzleValue(b, A, G, B, A, R);
|
||||
adjustAnyComponentSwizzleValue(a, R, G, B, A, R);
|
||||
break;
|
||||
|
||||
case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
|
||||
// Metal doesn't support this directly, so use a swizzle to get the ordering right.
|
||||
adjustAnyComponentSwizzleValue(r, A, A, B, G, R);
|
||||
adjustAnyComponentSwizzleValue(g, B, A, B, G, R);
|
||||
adjustAnyComponentSwizzleValue(b, G, A, B, G, R);
|
||||
adjustAnyComponentSwizzleValue(a, R, A, B, G, R);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ typedef struct MVKVkFormatDesc {
|
||||
uint32_t bytesPerBlock;
|
||||
MVKFormatType formatType;
|
||||
VkFormatProperties properties;
|
||||
VkComponentMapping componentMapping;
|
||||
const char* name;
|
||||
bool hasReportedSubstitution;
|
||||
|
||||
@ -158,6 +159,13 @@ typedef struct MVKVkFormatDesc {
|
||||
|
||||
inline bool vertexIsSupported() const { return (mtlVertexFormat != MTLVertexFormatInvalid); };
|
||||
inline bool vertexIsSupportedOrSubstitutable() const { return vertexIsSupported() || (mtlVertexFormatSubstitute != MTLVertexFormatInvalid); };
|
||||
|
||||
bool needsSwizzle() const {
|
||||
return componentMapping.r != VK_COMPONENT_SWIZZLE_IDENTITY ||
|
||||
componentMapping.g != VK_COMPONENT_SWIZZLE_IDENTITY ||
|
||||
componentMapping.b != VK_COMPONENT_SWIZZLE_IDENTITY ||
|
||||
componentMapping.a != VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
}
|
||||
} MVKVkFormatDesc;
|
||||
|
||||
/** Describes the properties of a MTLPixelFormat or MTLVertexFormat. */
|
||||
@ -320,6 +328,21 @@ public:
|
||||
*/
|
||||
size_t getBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer);
|
||||
|
||||
/** Returns whether or not the specified Vulkan format requires swizzling to use with Metal. */
|
||||
bool needsSwizzle(VkFormat vkFormat);
|
||||
|
||||
/** Returns any VkComponentMapping needed to use the specified Vulkan format. */
|
||||
VkComponentMapping getVkComponentMapping(VkFormat vkFormat);
|
||||
|
||||
/**
|
||||
* Returns the inverse of the VkComponentMapping needed to use the specified Vulkan format.
|
||||
* If the original mapping is not a one-to-one function, the behaviour is undefined.
|
||||
*/
|
||||
VkComponentMapping getInverseComponentMapping(VkFormat vkFormat);
|
||||
|
||||
/** Returns any MTLTextureSwizzleChannels needed to use the specified Vulkan format. */
|
||||
MTLTextureSwizzleChannels getMTLTextureSwizzleChannels(VkFormat vkFormat);
|
||||
|
||||
/** Returns the default properties for the specified Vulkan format. */
|
||||
VkFormatProperties& getVkFormatProperties(VkFormat vkFormat);
|
||||
|
||||
|
@ -377,6 +377,44 @@ size_t MVKPixelFormats::getBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesP
|
||||
return mvkCeilingDivide(texelRowsPerLayer, getVkFormatDesc(mtlFormat).blockTexelSize.height) * bytesPerRow;
|
||||
}
|
||||
|
||||
bool MVKPixelFormats::needsSwizzle(VkFormat vkFormat) {
|
||||
return getVkFormatDesc(vkFormat).needsSwizzle();
|
||||
}
|
||||
|
||||
VkComponentMapping MVKPixelFormats::getVkComponentMapping(VkFormat vkFormat) {
|
||||
return getVkFormatDesc(vkFormat).componentMapping;
|
||||
}
|
||||
|
||||
VkComponentMapping MVKPixelFormats::getInverseComponentMapping(VkFormat vkFormat) {
|
||||
#define INVERT_SWIZZLE(x, X, Y) \
|
||||
case VK_COMPONENT_SWIZZLE_##X: \
|
||||
inverse.x = VK_COMPONENT_SWIZZLE_##Y; \
|
||||
break
|
||||
#define INVERT_MAPPING(y, Y) \
|
||||
switch (mapping.y) { \
|
||||
case VK_COMPONENT_SWIZZLE_IDENTITY: \
|
||||
inverse.y = VK_COMPONENT_SWIZZLE_IDENTITY; \
|
||||
break; \
|
||||
INVERT_SWIZZLE(r, R, Y); \
|
||||
INVERT_SWIZZLE(g, G, Y); \
|
||||
INVERT_SWIZZLE(b, B, Y); \
|
||||
INVERT_SWIZZLE(a, A, Y); \
|
||||
default: break; \
|
||||
}
|
||||
VkComponentMapping mapping = getVkComponentMapping(vkFormat), inverse;
|
||||
INVERT_MAPPING(r, R)
|
||||
INVERT_MAPPING(g, G)
|
||||
INVERT_MAPPING(b, B)
|
||||
INVERT_MAPPING(a, A)
|
||||
return inverse;
|
||||
#undef INVERT_MAPPING
|
||||
#undef INVERT_SWIZZLE
|
||||
}
|
||||
|
||||
MTLTextureSwizzleChannels MVKPixelFormats::getMTLTextureSwizzleChannels(VkFormat vkFormat) {
|
||||
return mvkMTLTextureSwizzleChannelsFromVkComponentMapping(getVkComponentMapping(vkFormat));
|
||||
}
|
||||
|
||||
VkFormatProperties& MVKPixelFormats::getVkFormatProperties(VkFormat vkFormat) {
|
||||
return getVkFormatDesc(vkFormat).properties;
|
||||
}
|
||||
@ -464,13 +502,18 @@ MTLVertexFormat MVKPixelFormats::getMTLVertexFormat(VkFormat vkFormat) {
|
||||
|
||||
MTLClearColor MVKPixelFormats::getMTLClearColor(VkClearValue vkClearValue, VkFormat vkFormat) {
|
||||
MTLClearColor mtlClr;
|
||||
// The VkComponentMapping (and its MTLTextureSwizzleChannels equivalent) define the *sources*
|
||||
// for the texture color components for reading. Since we're *writing* to the texture,
|
||||
// we need to *invert* the mapping.
|
||||
// n.b. Bad things might happen if the original swizzle isn't one-to-one!
|
||||
VkComponentMapping inverseMap = getInverseComponentMapping(vkFormat);
|
||||
switch (getFormatType(vkFormat)) {
|
||||
case kMVKFormatColorHalf:
|
||||
case kMVKFormatColorFloat:
|
||||
mtlClr.red = vkClearValue.color.float32[0];
|
||||
mtlClr.green = vkClearValue.color.float32[1];
|
||||
mtlClr.blue = vkClearValue.color.float32[2];
|
||||
mtlClr.alpha = vkClearValue.color.float32[3];
|
||||
case kMVKFormatColorFloat: {
|
||||
mtlClr.red = mvkVkClearColorFloatValueFromVkComponentSwizzle(vkClearValue.color.float32, 0, inverseMap.r);
|
||||
mtlClr.green = mvkVkClearColorFloatValueFromVkComponentSwizzle(vkClearValue.color.float32, 1, inverseMap.g);
|
||||
mtlClr.blue = mvkVkClearColorFloatValueFromVkComponentSwizzle(vkClearValue.color.float32, 2, inverseMap.b);
|
||||
mtlClr.alpha = mvkVkClearColorFloatValueFromVkComponentSwizzle(vkClearValue.color.float32, 3, inverseMap.a);
|
||||
|
||||
if (_physicalDevice && _physicalDevice->getMetalFeatures()->clearColorFloatRounding == MVK_FLOAT_ROUNDING_DOWN) {
|
||||
// For normalized formats, increment the clear value by half the ULP
|
||||
@ -486,6 +529,8 @@ MTLClearColor MVKPixelFormats::getMTLClearColor(VkClearValue vkClearValue, VkFor
|
||||
#define OFFSET_SNORM(COLOR, BIT_WIDTH) OFFSET_NORM(-1.0, COLOR, BIT_WIDTH - 1)
|
||||
switch (vkFormat) {
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
|
||||
case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
|
||||
case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
|
||||
OFFSET_UNORM(red, 4)
|
||||
OFFSET_UNORM(green, 4)
|
||||
OFFSET_UNORM(blue, 4)
|
||||
@ -571,21 +616,22 @@ MTLClearColor MVKPixelFormats::getMTLClearColor(VkClearValue vkClearValue, VkFor
|
||||
#undef OFFSET_NORM
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kMVKFormatColorUInt8:
|
||||
case kMVKFormatColorUInt16:
|
||||
case kMVKFormatColorUInt32:
|
||||
mtlClr.red = vkClearValue.color.uint32[0];
|
||||
mtlClr.green = vkClearValue.color.uint32[1];
|
||||
mtlClr.blue = vkClearValue.color.uint32[2];
|
||||
mtlClr.alpha = vkClearValue.color.uint32[3];
|
||||
mtlClr.red = mvkVkClearColorUIntValueFromVkComponentSwizzle(vkClearValue.color.uint32, 0, inverseMap.r);
|
||||
mtlClr.green = mvkVkClearColorUIntValueFromVkComponentSwizzle(vkClearValue.color.uint32, 1, inverseMap.g);
|
||||
mtlClr.blue = mvkVkClearColorUIntValueFromVkComponentSwizzle(vkClearValue.color.uint32, 2, inverseMap.b);
|
||||
mtlClr.alpha = mvkVkClearColorUIntValueFromVkComponentSwizzle(vkClearValue.color.uint32, 3, inverseMap.a);
|
||||
break;
|
||||
case kMVKFormatColorInt8:
|
||||
case kMVKFormatColorInt16:
|
||||
case kMVKFormatColorInt32:
|
||||
mtlClr.red = vkClearValue.color.int32[0];
|
||||
mtlClr.green = vkClearValue.color.int32[1];
|
||||
mtlClr.blue = vkClearValue.color.int32[2];
|
||||
mtlClr.alpha = vkClearValue.color.int32[3];
|
||||
mtlClr.red = mvkVkClearColorIntValueFromVkComponentSwizzle(vkClearValue.color.int32, 0, inverseMap.r);
|
||||
mtlClr.green = mvkVkClearColorIntValueFromVkComponentSwizzle(vkClearValue.color.int32, 1, inverseMap.g);
|
||||
mtlClr.blue = mvkVkClearColorIntValueFromVkComponentSwizzle(vkClearValue.color.int32, 2, inverseMap.b);
|
||||
mtlClr.alpha = mvkVkClearColorIntValueFromVkComponentSwizzle(vkClearValue.color.int32, 3, inverseMap.a);
|
||||
break;
|
||||
default:
|
||||
mtlClr.red = 0.0;
|
||||
@ -756,16 +802,21 @@ MVKPixelFormats::MVKPixelFormats(MVKPhysicalDevice* physicalDevice) : _physicalD
|
||||
buildVkFormatMaps();
|
||||
}
|
||||
|
||||
#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) \
|
||||
#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_FORMAT_" #VK_FMT, false }
|
||||
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)
|
||||
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)
|
||||
|
||||
#define addVkFormatDescSwizzled(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE, SWIZ_R, SWIZ_G, SWIZ_B, SWIZ_A) \
|
||||
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, SWIZ_R, SWIZ_G, SWIZ_B, SWIZ_A)
|
||||
|
||||
#define addVkFormatDescChromaSubsampling(VK_FMT, MTL_FMT, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT) \
|
||||
addVkFormatDescFull(VK_FMT, MTL_FMT, Invalid, Invalid, Invalid, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT, ColorFloat)
|
||||
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() {
|
||||
|
||||
@ -781,6 +832,8 @@ void MVKPixelFormats::initVkFormatCapabilities() {
|
||||
addVkFormatDesc( R4G4_UNORM_PACK8, Invalid, Invalid, Invalid, Invalid, 1, 1, 1, ColorFloat );
|
||||
addVkFormatDesc( R4G4B4A4_UNORM_PACK16, ABGR4Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
|
||||
addVkFormatDesc( B4G4R4A4_UNORM_PACK16, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
|
||||
addVkFormatDescSwizzled( A4R4G4B4_UNORM_PACK16, ABGR4Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat, G, B, A, R );
|
||||
addVkFormatDescSwizzled( A4B4G4R4_UNORM_PACK16, ABGR4Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat, A, B, G, R );
|
||||
|
||||
addVkFormatDesc( R5G6B5_UNORM_PACK16, B5G6R5Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
|
||||
addVkFormatDesc( B5G6R5_UNORM_PACK16, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
|
||||
@ -1962,6 +2015,23 @@ void MVKPixelFormats::buildVkFormatMaps() {
|
||||
_vkFormatDescIndicesByVkFormatsExt[vkFmt] = fmtIdx;
|
||||
}
|
||||
|
||||
if (vkDesc.needsSwizzle()) {
|
||||
if (_physicalDevice) {
|
||||
id<MTLDevice> mtlDev = _physicalDevice->getMTLDevice();
|
||||
#if MVK_MACCAT
|
||||
bool supportsNativeTextureSwizzle = [mtlDev supportsFamily: MTLGPUFamilyMacCatalyst2];
|
||||
#elif MVK_MACOS
|
||||
bool supportsNativeTextureSwizzle = mvkOSVersionIsAtLeast(10.15) && [mtlDev supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1];
|
||||
#endif
|
||||
#if MVK_IOS || MVK_TVOS
|
||||
bool supportsNativeTextureSwizzle = mtlDev && mvkOSVersionIsAtLeast(13.0);
|
||||
#endif
|
||||
if (!supportsNativeTextureSwizzle && !mvkConfig().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.
|
||||
@ -2078,6 +2148,13 @@ void MVKPixelFormats::setFormatProperties(MVKVkFormatDesc& vkDesc) {
|
||||
mvkDisableFlags(vkProps.optimalTilingFeatures, (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT));
|
||||
}
|
||||
|
||||
// These formats require swizzling. In order to support rendering, we'll have to swizzle
|
||||
// in the fragment shader, but that hasn't been implemented yet.
|
||||
if (vkDesc.needsSwizzle()) {
|
||||
mvkDisableFlags(vkProps.optimalTilingFeatures, (kMVKVkFormatFeatureFlagsTexColorAtt |
|
||||
kMVKVkFormatFeatureFlagsTexBlend));
|
||||
}
|
||||
|
||||
// Linear tiling is not available to depth/stencil or compressed formats.
|
||||
// GBGR and BGRG formats also do not support linear tiling in Metal.
|
||||
if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed ||
|
||||
|
@ -92,6 +92,7 @@ MVK_EXTENSION(KHR_timeline_semaphore, KHR_TIMELINE_SEMAPHORE,
|
||||
MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT, DEVICE, 10.11, 8.0)
|
||||
MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, DEVICE, 10.11, 8.0)
|
||||
MVK_EXTENSION(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA)
|
||||
MVK_EXTENSION(EXT_4444_formats, EXT_4444_FORMATS, DEVICE, 11.0, 13.0)
|
||||
MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0)
|
||||
MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE, 10.11, 8.0)
|
||||
MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0)
|
||||
|
@ -228,6 +228,45 @@ MVK_PUBLIC_SYMBOL MTLTextureSwizzleChannels mvkMTLTextureSwizzleChannelsFromVkCo
|
||||
#undef convert
|
||||
}
|
||||
|
||||
MVK_PUBLIC_SYMBOL float mvkVkClearColorFloatValueFromVkComponentSwizzle(float *colors, uint32_t index, VkComponentSwizzle vkSwizzle) {
|
||||
switch (vkSwizzle) {
|
||||
case VK_COMPONENT_SWIZZLE_IDENTITY: return colors[index];
|
||||
case VK_COMPONENT_SWIZZLE_ZERO: return 0.f;
|
||||
case VK_COMPONENT_SWIZZLE_ONE: return 1.f;
|
||||
case VK_COMPONENT_SWIZZLE_R: return colors[0];
|
||||
case VK_COMPONENT_SWIZZLE_G: return colors[1];
|
||||
case VK_COMPONENT_SWIZZLE_B: return colors[2];
|
||||
case VK_COMPONENT_SWIZZLE_A: return colors[3];
|
||||
default: return colors[index];
|
||||
}
|
||||
}
|
||||
|
||||
MVK_PUBLIC_SYMBOL uint32_t mvkVkClearColorUIntValueFromVkComponentSwizzle(uint32_t *colors, uint32_t index, VkComponentSwizzle vkSwizzle) {
|
||||
switch (vkSwizzle) {
|
||||
case VK_COMPONENT_SWIZZLE_IDENTITY: return colors[index];
|
||||
case VK_COMPONENT_SWIZZLE_ZERO: return 0U;
|
||||
case VK_COMPONENT_SWIZZLE_ONE: return 1U;
|
||||
case VK_COMPONENT_SWIZZLE_R: return colors[0];
|
||||
case VK_COMPONENT_SWIZZLE_G: return colors[1];
|
||||
case VK_COMPONENT_SWIZZLE_B: return colors[2];
|
||||
case VK_COMPONENT_SWIZZLE_A: return colors[3];
|
||||
default: return colors[index];
|
||||
}
|
||||
}
|
||||
|
||||
MVK_PUBLIC_SYMBOL int32_t mvkVkClearColorIntValueFromVkComponentSwizzle(int32_t *colors, uint32_t index, VkComponentSwizzle vkSwizzle) {
|
||||
switch (vkSwizzle) {
|
||||
case VK_COMPONENT_SWIZZLE_IDENTITY: return colors[index];
|
||||
case VK_COMPONENT_SWIZZLE_ZERO: return 0;
|
||||
case VK_COMPONENT_SWIZZLE_ONE: return 1;
|
||||
case VK_COMPONENT_SWIZZLE_R: return colors[0];
|
||||
case VK_COMPONENT_SWIZZLE_G: return colors[1];
|
||||
case VK_COMPONENT_SWIZZLE_B: return colors[2];
|
||||
case VK_COMPONENT_SWIZZLE_A: return colors[3];
|
||||
default: return colors[index];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Mipmaps
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user