Add support for VK_EXTX_portability_subset extension.

Add KhronosGroup/Vulkan-Portability as external dependency repo.
Add ExternalRevisions/Vulkan-Portability_repo_revision.
Add vk_extx_portability_subset.h header file to mvk_vulkan.h.
MVKImageView allow constructor with no image or device.
Add mvkVkComponentMappingsMatch() & mvkVkComponentSwizzlesMatch() functions.
Cleanup some local var init warnings.
This commit is contained in:
Bill Hollings 2019-01-27 19:52:59 -05:00
parent 100848304d
commit e5a890775b
20 changed files with 300 additions and 152 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ External/cereal
External/glslang
External/SPIRV-Cross
External/Vulkan-Headers
External/Vulkan-Portability
External/Vulkan-Tools
External/VulkanSamples

View File

@ -750,7 +750,7 @@
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
HEADER_SEARCH_PATHS = (
"\"$(SRCROOT)/../../../External/Vulkan-Headers/include\"",
"\"$(SRCROOT)/../../../MoltenVK/include\"",
"\"$(SRCROOT)/../VulkanSamples/API-Samples/utils\"",
);
ONLY_ACTIVE_ARCH = YES;
@ -777,7 +777,7 @@
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
HEADER_SEARCH_PATHS = (
"\"$(SRCROOT)/../../../External/Vulkan-Headers/include\"",
"\"$(SRCROOT)/../../../MoltenVK/include\"",
"\"$(SRCROOT)/../VulkanSamples/API-Samples/utils\"",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.moltenvk.${PRODUCT_NAME:identifier}";

View File

@ -410,8 +410,7 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES;
HEADER_SEARCH_PATHS = (
"\"$(SRCROOT)/include\"",
"\"$(SRCROOT)/../../../MoltenVK/include/MoltenVK\"",
"\"$(SRCROOT)/../../../External/Vulkan-Headers/include\"",
"\"$(SRCROOT)/../../../MoltenVK/include\"",
);
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC";
@ -435,8 +434,7 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES;
HEADER_SEARCH_PATHS = (
"\"$(SRCROOT)/include\"",
"\"$(SRCROOT)/../../../MoltenVK/include/MoltenVK\"",
"\"$(SRCROOT)/../../../External/Vulkan-Headers/include\"",
"\"$(SRCROOT)/../../../MoltenVK/include\"",
);
OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = "com.moltenvk.${PRODUCT_NAME:identifier}";

View File

@ -18,7 +18,7 @@
#import "DemoViewController.h"
#include "mvk_vulkan.h"
#include <MoltenVK/mvk_vulkan.h>
#include "../../Vulkan-Tools/cube/cube.c"

View File

@ -19,7 +19,7 @@
#import "DemoViewController.h"
#import <QuartzCore/CAMetalLayer.h>
#include "mvk_vulkan.h"
#include <MoltenVK/mvk_vulkan.h>
#include "../../Vulkan-Tools/cube/cube.c"

View File

@ -245,8 +245,9 @@ In addition to the core *Vulkan* API, **MoltenVK** also supports the following
- `VK_KHR_variable_pointers`
- `VK_EXT_shader_viewport_index_layer`
- `VK_EXT_vertex_attribute_divisor`
- `VK_MVK_macos_surface` (macOS)
- `VK_EXTX_portability_subset`
- `VK_MVK_ios_surface` (iOS)
- `VK_MVK_macos_surface` (macOS)
- `VK_MVK_moltenvk`
- `VK_AMD_gpu_shader_half_float`
- `VK_AMD_negative_viewport_height`

View File

@ -0,0 +1 @@
53be040f04ce55463d0e5b25fd132f45f003e903

View File

@ -378,6 +378,7 @@
A9E53DFE21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLRenderPipelineDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCommonEnvironment.h; sourceTree = "<group>"; };
A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKLogging.h; sourceTree = "<group>"; };
A9F2559121F96814008C7785 /* vulkan-portability */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "vulkan-portability"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
@ -539,6 +540,7 @@
isa = PBXGroup;
children = (
A9AD67C72054DD6C00ED3C08 /* vulkan */,
A9F2559121F96814008C7785 /* vulkan-portability */,
);
path = include;
sourceTree = "<group>";
@ -1123,7 +1125,7 @@
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
GENERATE_MASTER_OBJECT_FILE = YES;
@ -1179,7 +1181,7 @@
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
GENERATE_MASTER_OBJECT_FILE = YES;

View File

@ -40,5 +40,6 @@
#endif
#include <vulkan/vulkan.h>
#include <vulkan-portability/vk_extx_portability_subset.h>
#endif

View File

@ -375,26 +375,38 @@ typedef struct {
VkBool32 switchSystemGPU;
/**
* If enabled, arbitrary ImageView component swizzles are supported, as defined
* If enabled, arbitrary VkImageView component swizzles are supported, as defined
* in VkImageViewCreateInfo::components when creating a VkImageView.
*
* If disabled, a very limited set of ImageView component swizzles are supported
* If disabled, a very limited set of VkImageView component swizzles are supported
* via format substitutions.
*
* Metal does not natively support per-texture swizzling. If this parameter is enabled
* when a pipeline is compiled, ImageView swizzling is automatically performed in the
* converted Metal shader code during all texture sampling and reading operations,
* regardless of whether a swizzle has been specified for the ImageView associated
* with the Metal texture. This may result in reduced performance.
* both when a VkImageView is created, and when any pipeline that uses that VkImageView
* is compiled, VkImageView swizzling is automatically performed in the converted Metal
* shader code during all texture sampling and reading operations, regardless of whether
* a swizzle is required for the VkImageView associated with the Metal texture.
* This may result in reduced performance.
*
* The value of this parameter may be changed at any time during application runtime,
* and the changed value will immediately effect subsequent MoltenVK behaviour.
* Specifically, this parameter can be enabled when compiling some pipelines,
* and disabled when compiling others. Existing pipelines are not automatically
* re-compiled when this parameter is changed.
* Specifically, this parameter can be enabled when creating VkImageViews that need it,
* and compiling pipelines that use those VkImageViews, and can be disabled when creating
* VkImageViews that don't need it, and compiling pipelines that use those VkImageViews.
*
* If this parameter is disabled, the following limited set of ImageView swizzles
* are supported by MoltenVK, via automatic format substitution:
* Existing pipelines are not automatically re-compiled when this parameter is changed.
*
* An error is logged and returned during VkImageView creation if that VkImageView
* requires full image view swizzling and this feature is not enabled. An error is
* also logged when a pipeline that was not compiled with full image view swizzling
* is presented with a VkImageView that is expecting it.
*
* An error is also retuned and logged when a VkPhysicalDeviceImageFormatInfo2KHR is passed
* in a call to vkGetPhysicalDeviceImageFormatProperties2KHR() to query for an VkImageView
* format that will require full swizzling to be enabled, and this feature is not enabled.
*
* If this parameter is disabled, the following limited set of VkImageView swizzles are
* supported by MoltenVK, via automatic format substitution:
*
* Texture format Swizzle
* -------------- -------

View File

@ -287,6 +287,7 @@ protected:
std::vector<MVKQueueFamily*>& getQueueFamilies();
void initPipelineCacheUUID();
MTLFeatureSet getHighestMTLFeatureSet();
bool getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo);
void logGPUInfo();
id<MTLDevice> _mtlDevice;

View File

@ -65,7 +65,7 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
features->features = _features;
auto* next = (MVKVkAPIStructHeader*)features->pNext;
while (next) {
switch (next->sType) {
switch ((uint32_t)next->sType) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: {
auto* storageFeatures = (VkPhysicalDevice16BitStorageFeatures*)next;
storageFeatures->storageBuffer16BitAccess = true;
@ -104,6 +104,16 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
next = (MVKVkAPIStructHeader*)divisorFeatures->pNext;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX: {
auto* portabilityFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesEXTX*)next;
portabilityFeatures->triangleFans = false;
portabilityFeatures->separateStencilMaskRef = false;
portabilityFeatures->events = false;
portabilityFeatures->standardImageViews = false;
portabilityFeatures->samplerMipLodBias = false;
next = (MVKVkAPIStructHeader*)portabilityFeatures->pNext;
break;
}
default:
next = (MVKVkAPIStructHeader*)next->pNext;
break;
@ -120,36 +130,42 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
if (properties) {
properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties->properties = _properties;
auto* next = (VkStructureType*)properties->pNext;
while (next) {
switch (*next) {
auto* next = (MVKVkAPIStructHeader*)properties->pNext;
while (next) {
switch ((uint32_t)next->sType) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next;
pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
next = (VkStructureType*)pointClipProps->pNext;
next = (MVKVkAPIStructHeader*)pointClipProps->pNext;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {
auto* maint3Props = (VkPhysicalDeviceMaintenance3Properties*)next;
maint3Props->maxPerSetDescriptors = (_metalFeatures.maxPerStageBufferCount + _metalFeatures.maxPerStageTextureCount + _metalFeatures.maxPerStageSamplerCount) * 2;
maint3Props->maxMemoryAllocationSize = _metalFeatures.maxMTLBufferSize;
next = (VkStructureType*)maint3Props->pNext;
next = (MVKVkAPIStructHeader*)maint3Props->pNext;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next;
pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources;
next = (VkStructureType*)pushDescProps->pNext;
next = (MVKVkAPIStructHeader*)pushDescProps->pNext;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next;
divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
next = (VkStructureType*)divisorProps->pNext;
next = (MVKVkAPIStructHeader*)divisorProps->pNext;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: {
auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next;
portabilityProps->minVertexInputBindingStrideAlignment = 4;
next = (MVKVkAPIStructHeader*)portabilityProps->pNext;
break;
}
default:
next = (VkStructureType*)((VkPhysicalDeviceProperties2*)next)->pNext;
next = (MVKVkAPIStructHeader*)((VkPhysicalDeviceProperties2*)next)->pNext;
break;
}
}
@ -334,17 +350,56 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(const VkPhysicalDeviceImage
if ( !pImageFormatInfo || pImageFormatInfo->sType != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR ) {
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
if ( !getFormatIsSupported(pImageFormatInfo->format) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
if ( !pImageFormatProperties ) {
return VK_SUCCESS;
}
if ( !getImageViewIsSupported(pImageFormatInfo) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
pImageFormatProperties->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
return getImageFormatProperties(pImageFormatInfo->format, pImageFormatInfo->type,
pImageFormatInfo->tiling, pImageFormatInfo->usage,
pImageFormatInfo->flags,
&pImageFormatProperties->imageFormatProperties);
if (pImageFormatProperties) {
pImageFormatProperties->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
return getImageFormatProperties(pImageFormatInfo->format, pImageFormatInfo->type,
pImageFormatInfo->tiling, pImageFormatInfo->usage,
pImageFormatInfo->flags,
&pImageFormatProperties->imageFormatProperties);
}
return VK_SUCCESS;
}
// If the image format info links portability image view info, test if an image view of that configuration is supported
bool MVKPhysicalDevice::getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo) {
auto* next = (VkStructureType*)pImageFormatInfo->pNext;
while (next) {
switch ((int32_t)*next) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_SUPPORT_EXTX: {
auto* portImgViewInfo = (VkPhysicalDeviceImageViewSupportEXTX*)next;
// Create an image view and test whether it could be configured
VkImageViewCreateInfo viewInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = (VkStructureType*)portImgViewInfo->pNext,
.flags = portImgViewInfo->flags,
.image = VK_NULL_HANDLE,
.viewType = portImgViewInfo->viewType,
.format = portImgViewInfo->format,
.components = portImgViewInfo->components,
.subresourceRange = {
.aspectMask = portImgViewInfo->aspectMask,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1},
};
MVKImageView imgView(VK_NULL_HANDLE, &viewInfo, _mvkInstance->getMoltenVKConfiguration());
return imgView.getConfigurationResult() == VK_SUCCESS;
}
default:
next = (VkStructureType*)((VkPhysicalDeviceFeatures2*)next)->pNext;
break;
}
}
return true;
}

View File

@ -280,15 +280,19 @@ public:
#pragma mark Construction
MVKImageView(MVKDevice* device, const VkImageViewCreateInfo* pCreateInfo);
MVKImageView(MVKDevice* device,
const VkImageViewCreateInfo* pCreateInfo,
const MVKConfiguration* pAltMVKConfig = nullptr);
~MVKImageView() override;
protected:
id<MTLTexture> newMTLTexture();
void initMTLTextureViewSupport();
MTLPixelFormat getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components, bool& useSwizzle);
bool matchesSwizzle(VkComponentMapping components, VkComponentMapping pattern);
MTLPixelFormat getSwizzledMTLPixelFormat(VkFormat format,
VkComponentMapping components,
bool& useSwizzle,
const MVKConfiguration* pMVKConfig);
void validateImageViewConfig(const VkImageViewCreateInfo* pCreateInfo);
MVKImage* _image;

View File

@ -761,10 +761,13 @@ id<MTLTexture> MVKImageView::newMTLTexture() {
#pragma mark Construction
MVKImageView::MVKImageView(MVKDevice* device, const VkImageViewCreateInfo* pCreateInfo) : MVKRefCountedDeviceObject(device) {
// device and _image may be nil when a temporary instance
// is constructed to validate image view capabilities
MVKImageView::MVKImageView(MVKDevice* device,
const VkImageViewCreateInfo* pCreateInfo,
const MVKConfiguration* pAltMVKConfig) : MVKRefCountedDeviceObject(device) {
_image = (MVKImage*)pCreateInfo->image;
_usage = _image->_usage;
_usage = _image ? _image->_usage : 0;
auto* next = (VkStructureType*)pCreateInfo->pNext;
while (next) {
@ -787,23 +790,30 @@ MVKImageView::MVKImageView(MVKDevice* device, const VkImageViewCreateInfo* pCrea
// Remember the subresource range, and determine the actual number of mip levels and texture slices
_subresourceRange = pCreateInfo->subresourceRange;
if (_subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS) {
_subresourceRange.levelCount = _image->getMipLevelCount() - _subresourceRange.baseMipLevel;
_subresourceRange.levelCount = _image ? (_image->getMipLevelCount() - _subresourceRange.baseMipLevel) : 1;
}
if (_subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS) {
_subresourceRange.layerCount = _image->getLayerCount() - _subresourceRange.baseArrayLayer;
_subresourceRange.layerCount = _image ? (_image->getLayerCount() - _subresourceRange.baseArrayLayer) : 1;
}
bool useSwizzle;
bool useShaderSwizzle;
bool isMultisample = _image ? _image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT : false;
_mtlTexture = nil;
_mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components, useSwizzle);
_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, (_image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT));
_mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components, useShaderSwizzle,
(_device ? _device->_pMVKConfig : pAltMVKConfig));
_packedSwizzle = useShaderSwizzle ? mvkPackSwizzle(pCreateInfo->components) : 0;
_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, isMultisample);
initMTLTextureViewSupport();
_packedSwizzle = useSwizzle ? mvkPackSwizzle(pCreateInfo->components) : 0;
}
// Validate whether the image view configuration can be supported
void MVKImageView::validateImageViewConfig(const VkImageViewCreateInfo* pCreateInfo) {
// No image if we are just validating view config
MVKImage* image = (MVKImage*)pCreateInfo->image;
if ( !image ) { return; }
VkImageType imgType = image->getImageType();
VkImageViewType viewType = pCreateInfo->viewType;
@ -820,102 +830,117 @@ void MVKImageView::validateImageViewConfig(const VkImageViewCreateInfo* pCreateI
}
}
// Returns a MTLPixelFormat, based on the original MTLPixelFormat, as converted from the VkFormat,
// but possibly modified by the swizzles defined in the VkComponentMapping of the VkImageViewCreateInfo.
// Metal does not support general per-texture swizzles, and so this function relies on a few coincidental
// alignments of existing MTLPixelFormats of the same structure. If swizzling is not possible for a
// particular combination of format and swizzle spec, the original MTLPixelFormat is returned.
MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components, bool& useSwizzle) {
MTLPixelFormat mtlPF = getMTLPixelFormatFromVkFormat(format);
// Returns a MTLPixelFormat, based on the MTLPixelFormat converted from the VkFormat, but possibly
// modified by the swizzles defined in the VkComponentMapping of the VkImageViewCreateInfo.
// Metal does not support general per-texture swizzles, so if the swizzle is not an identity swizzle, this
// function attempts to find an alternate MTLPixelFormat that coincidentally matches the swizzled format.
// If a replacement MTLFormat was found, it is returned and useShaderSwizzle is set to false.
// If a replacement MTLFormat could not be found, the original MTLPixelFormat is returned, and the
// useShaderSwizzle is set to true, indicating that shader swizzling should be used for this image view.
// The config is used to test whether full shader swizzle support is available, and to report an error if not.
MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format,
VkComponentMapping components,
bool& useShaderSwizzle,
const MVKConfiguration* pMVKConfig) {
useSwizzle = false;
switch (mtlPF) {
case MTLPixelFormatR8Unorm:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_R} ) ) {
return MTLPixelFormatA8Unorm;
}
break;
// Attempt to find a valid format transformation swizzle first.
MTLPixelFormat mtlPF = getMTLPixelFormatFromVkFormat(format);
useShaderSwizzle = false;
case MTLPixelFormatA8Unorm:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_ZERO} ) ) {
return MTLPixelFormatR8Unorm;
}
break;
#define SWIZZLE_MATCHES(R, G, B, A) mvkVkComponentMappingsMatch(components, {VK_COMPONENT_SWIZZLE_ ##R, VK_COMPONENT_SWIZZLE_ ##G, VK_COMPONENT_SWIZZLE_ ##B, VK_COMPONENT_SWIZZLE_ ##A} )
#define VK_COMPONENT_SWIZZLE_ANY VK_COMPONENT_SWIZZLE_MAX_ENUM
case MTLPixelFormatRGBA8Unorm:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A} ) ) {
return MTLPixelFormatBGRA8Unorm;
}
break;
switch (mtlPF) {
case MTLPixelFormatR8Unorm:
if (SWIZZLE_MATCHES(ZERO, ANY, ANY, R)) {
return MTLPixelFormatA8Unorm;
}
break;
case MTLPixelFormatRGBA8Unorm_sRGB:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A} ) ) {
return MTLPixelFormatBGRA8Unorm_sRGB;
}
break;
case MTLPixelFormatA8Unorm:
if (SWIZZLE_MATCHES(A, ANY, ANY, ZERO)) {
return MTLPixelFormatR8Unorm;
}
break;
case MTLPixelFormatBGRA8Unorm:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A} ) ) {
return MTLPixelFormatRGBA8Unorm;
}
break;
case MTLPixelFormatRGBA8Unorm:
if (SWIZZLE_MATCHES(B, G, R, A)) {
return MTLPixelFormatBGRA8Unorm;
}
break;
case MTLPixelFormatBGRA8Unorm_sRGB:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A} ) ) {
return MTLPixelFormatRGBA8Unorm_sRGB;
}
break;
case MTLPixelFormatRGBA8Unorm_sRGB:
if (SWIZZLE_MATCHES(B, G, R, A)) {
return MTLPixelFormatBGRA8Unorm_sRGB;
}
break;
case MTLPixelFormatDepth32Float_Stencil8:
if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
if (!matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM} ) ) {
useSwizzle = true;
}
return MTLPixelFormatX32_Stencil8;
}
break;
case MTLPixelFormatBGRA8Unorm:
if (SWIZZLE_MATCHES(B, G, R, A)) {
return MTLPixelFormatRGBA8Unorm;
}
break;
case MTLPixelFormatBGRA8Unorm_sRGB:
if (SWIZZLE_MATCHES(B, G, R, A)) {
return MTLPixelFormatRGBA8Unorm_sRGB;
}
break;
case MTLPixelFormatDepth32Float_Stencil8:
// If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed
if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
mtlPF = MTLPixelFormatX32_Stencil8;
if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) {
return mtlPF;
}
}
break;
#if MVK_MACOS
case MTLPixelFormatDepth24Unorm_Stencil8:
if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
if (!matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM} ) ) {
useSwizzle = true;
}
return MTLPixelFormatX24_Stencil8;
}
break;
case MTLPixelFormatDepth24Unorm_Stencil8:
// If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed
if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
mtlPF = MTLPixelFormatX24_Stencil8;
if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) {
return mtlPF;
}
}
break;
#endif
default:
break;
}
default:
break;
}
if ( !matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A} ) ) {
useSwizzle = true;
}
return mtlPF;
}
// No format transformation swizzles were found, so unless we have an identity swizzle, we'll need to use shader swizzling.
if ( !SWIZZLE_MATCHES(R, G, B, A)) {
useShaderSwizzle = true;
// Returns whether the swizzle components of the internal VkComponentMapping matches the
// swizzle pattern, by comparing corresponding elements of the two structures. The pattern
// supports wildcards, in that any element of pattern can be set to VK_COMPONENT_SWIZZLE_MAX_ENUM
// to indicate that any value in the corresponding element of components.
bool MVKImageView::matchesSwizzle(VkComponentMapping components, VkComponentMapping pattern) {
if ( !((pattern.r == VK_COMPONENT_SWIZZLE_MAX_ENUM) || (pattern.r == components.r) ||
((pattern.r == VK_COMPONENT_SWIZZLE_R) && (components.r == VK_COMPONENT_SWIZZLE_IDENTITY))) ) { return false; }
if ( !((pattern.g == VK_COMPONENT_SWIZZLE_MAX_ENUM) || (pattern.g == components.g) ||
((pattern.g == VK_COMPONENT_SWIZZLE_G) && (components.g == VK_COMPONENT_SWIZZLE_IDENTITY))) ) { return false; }
if ( !((pattern.b == VK_COMPONENT_SWIZZLE_MAX_ENUM) || (pattern.b == components.b) ||
((pattern.b == VK_COMPONENT_SWIZZLE_B) && (components.b == VK_COMPONENT_SWIZZLE_IDENTITY))) ) { return false; }
if ( !((pattern.a == VK_COMPONENT_SWIZZLE_MAX_ENUM) || (pattern.a == components.a) ||
((pattern.a == VK_COMPONENT_SWIZZLE_A) && (components.a == VK_COMPONENT_SWIZZLE_IDENTITY))) ) { return false; }
if ( !pMVKConfig->fullImageViewSwizzle ) {
const char* vkCmd = _image ? "vkCreateImageView(VkImageViewCreateInfo" : "vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDeviceImageViewSupportEXTX";
const char* errMsg = ("The value of %s::components) (%s, %s, %s, %s), when applied to a VkImageView, requires full component swizzling to be enabled both at the"
" time when the VkImageView is created and at the time any pipeline that uses that VkImageView is compiled. Full component swizzling can"
" be enabled via the MVKConfiguration::fullImageViewSwizzle config parameter or MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE environment variable.");
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, errMsg, vkCmd,
mvkVkComponentSwizzleName(components.r), mvkVkComponentSwizzleName(components.g),
mvkVkComponentSwizzleName(components.b), mvkVkComponentSwizzleName(components.a)));
}
}
return true;
return mtlPF;
}
// Determine whether this image view should use a Metal texture view,
// and set the _useMTLTextureView variable appropriately.
void MVKImageView::initMTLTextureViewSupport() {
// If no image we're just validating image iview config
if ( !_image ) {
_useMTLTextureView = false;
return;
}
_useMTLTextureView = _image->_canSupportMTLTextureView;
bool is3D = _image->_mtlTextureType == MTLTextureType3D;

View File

@ -53,6 +53,7 @@ MVK_EXTENSION(KHR_swapchain_mutable_format, KHR_SWAPCHAIN_MUTABLE_FORMAT)
MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS)
MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER)
MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR)
MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET)
MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE)
MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE)
MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK)

View File

@ -297,6 +297,40 @@ static inline VkComponentMapping mvkUnpackSwizzle(uint32_t packed) {
return components;
}
/**
* Returns whether the two component swizzles, cs1 and cs2 match. Positional identity matches
* and wildcard matches are allowed. The two values match under any of the following conditions:
* 1) cs1 and cs2 are equal to each other.
* 2) Either cs1 or cs2 is equal to VK_COMPONENT_SWIZZLE_IDENTITY and the other value
* is equal to the positional value csPos, which is one of VK_COMPONENT_SWIZZLE_R,
* VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, or VK_COMPONENT_SWIZZLE_A.
* 3) Either cs1 or cs2 is VK_COMPONENT_SWIZZLE_MAX_ENUM, which is considered a wildcard,
* and matches any value.
*/
static inline bool mvkVKComponentSwizzlesMatch(VkComponentSwizzle cs1,
VkComponentSwizzle cs2,
VkComponentSwizzle csPos) {
return ((cs1 == cs2) ||
((cs1 == VK_COMPONENT_SWIZZLE_IDENTITY) && (cs2 == csPos)) ||
((cs2 == VK_COMPONENT_SWIZZLE_IDENTITY) && (cs1 == csPos)) ||
(cs1 == VK_COMPONENT_SWIZZLE_MAX_ENUM) || (cs2 == VK_COMPONENT_SWIZZLE_MAX_ENUM));
}
/**
* Returns whether the two swizzle component mappings match each other, by comparing the
* corresponding elements of the two mappings. A component value of VK_COMPONENT_SWIZZLE_IDENTITY
* on either mapping matches the VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
* or VK_COMPONENT_SWIZZLE_A value in the other mapping if it is the correct position.
* A component value of VK_COMPONENT_SWIZZLE_MAX_ENUM is considered a wildcard and matches
* any value in the corresponding component in the other mapping.
*/
static inline bool mvkVkComponentMappingsMatch(VkComponentMapping cm1, VkComponentMapping cm2) {
return (mvkVKComponentSwizzlesMatch(cm1.r, cm2.r, VK_COMPONENT_SWIZZLE_R) &&
mvkVKComponentSwizzlesMatch(cm1.g, cm2.g, VK_COMPONENT_SWIZZLE_G) &&
mvkVKComponentSwizzlesMatch(cm1.b, cm2.b, VK_COMPONENT_SWIZZLE_B) &&
mvkVKComponentSwizzlesMatch(cm1.a, cm2.a, VK_COMPONENT_SWIZZLE_A));
}
#pragma mark -
#pragma mark Template functions

View File

@ -1480,33 +1480,31 @@ MVK_PUBLIC_SYMBOL void vkCmdExecuteCommands(
#pragma mark VK_KHR_bind_memory2 extension
MVK_PUBLIC_SYMBOL VkResult vkBindBufferMemory2KHR(
VkDevice device,
uint32_t bindInfoCount,
const VkBindBufferMemoryInfoKHR* pBindInfos) {
VkResult res;
for (uint32_t i = 0; i < bindInfoCount; ++i) {
MVKBuffer* mvkBuff = (MVKBuffer*)pBindInfos[i].buffer;
res = mvkBuff->bindDeviceMemory2(&pBindInfos[i]);
if (res != VK_SUCCESS) {
break;
}
}
return res;
VkDevice device,
uint32_t bindInfoCount,
const VkBindBufferMemoryInfoKHR* pBindInfos) {
VkResult rslt = VK_SUCCESS;
for (uint32_t i = 0; i < bindInfoCount; ++i) {
MVKBuffer* mvkBuff = (MVKBuffer*)pBindInfos[i].buffer;
VkResult r = mvkBuff->bindDeviceMemory2(&pBindInfos[i]);
if (rslt == VK_SUCCESS) { rslt = r; }
}
return rslt;
}
MVK_PUBLIC_SYMBOL VkResult vkBindImageMemory2KHR(
VkDevice device,
uint32_t bindInfoCount,
const VkBindImageMemoryInfoKHR* pBindInfos) {
VkResult res;
for (uint32_t i = 0; i < bindInfoCount; ++i) {
MVKImage* mvkImg = (MVKImage*)pBindInfos[i].image;
res = mvkImg->bindDeviceMemory2(&pBindInfos[i]);
if (res != VK_SUCCESS) {
break;
}
}
return res;
VkDevice device,
uint32_t bindInfoCount,
const VkBindImageMemoryInfoKHR* pBindInfos) {
VkResult rslt = VK_SUCCESS;
for (uint32_t i = 0; i < bindInfoCount; ++i) {
MVKImage* mvkImg = (MVKImage*)pBindInfos[i].image;
VkResult r = mvkImg->bindDeviceMemory2(&pBindInfos[i]);
if (rslt == VK_SUCCESS) { rslt = r; }
}
return rslt;
}

View File

@ -0,0 +1 @@
../../External/Vulkan-Portability/include/vulkan

1
MoltenVK/vulkan-portability Symbolic link
View File

@ -0,0 +1 @@
../../External/Vulkan-Portability/include/vulkan

View File

@ -144,6 +144,18 @@ else
update_repo ${REPO_NAME} ${REPO_URL} ${REPO_REV}
fi
# ----------------- Vulkan-Portability -------------------
echo
echo ========== Vulkan-Portability ==========
echo
REPO_NAME=Vulkan-Portability
REPO_URL="https://github.com/KhronosGroup/${REPO_NAME}.git"
REPO_REV=$(cat "../${EXT_REV_DIR}/${REPO_NAME}_repo_revision")
update_repo ${REPO_NAME} ${REPO_URL} ${REPO_REV}
# ----------------- SPIRV-Cross -------------------