Advertise the VK_EXT_shader_stencil_export extension.

This is supported by Mac GPU Family 2 starting on macOS 10.14, and Apple
GPU Family 5 starting on iOS 12.

Supporting this is a bit tricky. Because only some devices support this
extension, we now have to keep track of supported device extensions per
device.
This commit is contained in:
Chip Davis 2019-06-29 19:16:16 -05:00
parent 53b6ced8b3
commit fc13aec2af
9 changed files with 82 additions and 27 deletions

View File

@ -240,7 +240,7 @@ In addition to the core *Vulkan* API, **MoltenVK** also supports the following
- `VK_KHR_maintenance3` - `VK_KHR_maintenance3`
- `VK_KHR_push_descriptor` - `VK_KHR_push_descriptor`
- `VK_KHR_relaxed_block_layout` - `VK_KHR_relaxed_block_layout`
- `VK_KHR_sampler_mirror_clamp_to_edge` - `VK_KHR_sampler_mirror_clamp_to_edge` *(macOS)*
- `VK_KHR_shader_draw_parameters` - `VK_KHR_shader_draw_parameters`
- `VK_KHR_shader_float16_int8` - `VK_KHR_shader_float16_int8`
- `VK_KHR_storage_buffer_storage_class` - `VK_KHR_storage_buffer_storage_class`
@ -254,6 +254,7 @@ In addition to the core *Vulkan* API, **MoltenVK** also supports the following
- `VK_EXT_host_query_reset` - `VK_EXT_host_query_reset`
- `VK_EXT_memory_budget` - `VK_EXT_memory_budget`
- `VK_EXT_metal_surface` - `VK_EXT_metal_surface`
- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)*
- `VK_EXT_shader_viewport_index_layer` - `VK_EXT_shader_viewport_index_layer`
- `VK_EXT_vertex_attribute_divisor` - `VK_EXT_vertex_attribute_divisor`
- `VK_EXTX_portability_subset` - `VK_EXTX_portability_subset`

View File

@ -537,6 +537,7 @@ typedef struct {
VkBool32 events; /**< If true, Metal synchronization events are supported. */ VkBool32 events; /**< If true, Metal synchronization events are supported. */
VkBool32 memoryBarriers; /**< If true, full memory barriers within Metal render passes are supported. */ VkBool32 memoryBarriers; /**< If true, full memory barriers within Metal render passes are supported. */
VkBool32 multisampleLayeredRendering; /**< If true, layered rendering to multiple multi-sampled cube or texture array layers is supported. */ VkBool32 multisampleLayeredRendering; /**< If true, layered rendering to multiple multi-sampled cube or texture array layers is supported. */
VkBool32 stencilFeedback; /**< If true, fragment shaders that write to [[stencil]] outputs are supported. */
} MVKPhysicalDeviceMetalFeatures; } MVKPhysicalDeviceMetalFeatures;
/** /**

View File

@ -88,6 +88,9 @@ public:
/** Returns a pointer to the Vulkan instance. */ /** Returns a pointer to the Vulkan instance. */
MVKInstance* getInstance() override { return _mvkInstance; } MVKInstance* getInstance() override { return _mvkInstance; }
/** Populates the specified array with the supported extensions of this device. */
VkResult getExtensionProperties(const char* pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties);
/** Populates the specified structure with the features of this device. */ /** Populates the specified structure with the features of this device. */
void getFeatures(VkPhysicalDeviceFeatures* features); void getFeatures(VkPhysicalDeviceFeatures* features);
@ -318,6 +321,8 @@ protected:
void initFeatures(); void initFeatures();
void initProperties(); void initProperties();
void initMemoryProperties(); void initMemoryProperties();
void initExtensions();
MVKExtensionList* getSupportedExtensions(const char* pLayerName = nullptr);
std::vector<MVKQueueFamily*>& getQueueFamilies(); std::vector<MVKQueueFamily*>& getQueueFamilies();
void initPipelineCacheUUID(); void initPipelineCacheUUID();
MTLFeatureSet getHighestMTLFeatureSet(); MTLFeatureSet getHighestMTLFeatureSet();
@ -327,6 +332,7 @@ protected:
id<MTLDevice> _mtlDevice; id<MTLDevice> _mtlDevice;
MVKInstance* _mvkInstance; MVKInstance* _mvkInstance;
MVKExtensionList _supportedExtensions;
VkPhysicalDeviceFeatures _features; VkPhysicalDeviceFeatures _features;
MVKPhysicalDeviceMetalFeatures _metalFeatures; MVKPhysicalDeviceMetalFeatures _metalFeatures;
VkPhysicalDeviceProperties _properties; VkPhysicalDeviceProperties _properties;

View File

@ -56,6 +56,11 @@ using namespace std;
#pragma mark - #pragma mark -
#pragma mark MVKPhysicalDevice #pragma mark MVKPhysicalDevice
VkResult MVKPhysicalDevice::getExtensionProperties(const char* pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties) {
MVKExtensionList* extensions = getSupportedExtensions(pLayerName);
return extensions->getProperties(pCount, pProperties);
}
void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures* features) { void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures* features) {
if (features) { *features = _features; } if (features) { *features = _features; }
} }
@ -676,7 +681,7 @@ VkResult MVKPhysicalDevice::getPhysicalDeviceMemoryProperties(VkPhysicalDeviceMe
#pragma mark Construction #pragma mark Construction
MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtlDevice) { MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtlDevice) : _supportedExtensions(this, true) {
_mvkInstance = mvkInstance; _mvkInstance = mvkInstance;
_mtlDevice = [mtlDevice retain]; _mtlDevice = [mtlDevice retain];
@ -684,6 +689,7 @@ MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtl
initFeatures(); // Call second. initFeatures(); // Call second.
initProperties(); // Call third. initProperties(); // Call third.
initMemoryProperties(); initMemoryProperties();
initExtensions();
logGPUInfo(); logGPUInfo();
} }
@ -751,6 +757,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily5_v1] ) { if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily5_v1] ) {
_metalFeatures.layeredRendering = true; _metalFeatures.layeredRendering = true;
_metalFeatures.stencilFeedback = true;
} }
#endif #endif
@ -793,6 +800,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1] ) { if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1] ) {
_metalFeatures.multisampleLayeredRendering = _metalFeatures.layeredRendering; _metalFeatures.multisampleLayeredRendering = _metalFeatures.layeredRendering;
_metalFeatures.stencilFeedback = true;
} }
#endif #endif
@ -1499,6 +1507,18 @@ void MVKPhysicalDevice::initMemoryProperties() {
#endif #endif
} }
void MVKPhysicalDevice::initExtensions() {
if (!_metalFeatures.stencilFeedback) {
_supportedExtensions.vk_EXT_shader_stencil_export.enabled = false;
}
}
// Return all extensions supported by this physical device.
MVKExtensionList* MVKPhysicalDevice::getSupportedExtensions(const char* pLayerName) {
if (!pLayerName || strcmp(pLayerName, "MoltenVK") == 0) { return &_supportedExtensions; }
return getInstance()->getLayerManager()->getLayerNamed(pLayerName)->getSupportedExtensions();
}
void MVKPhysicalDevice::logGPUInfo() { void MVKPhysicalDevice::logGPUInfo() {
string devTypeStr; string devTypeStr;
switch (_properties.deviceType) { switch (_properties.deviceType) {
@ -2280,7 +2300,7 @@ void MVKDevice::enableExtensions(const VkDeviceCreateInfo* pCreateInfo) {
MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_enabledExtensions; MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_enabledExtensions;
setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount, setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount,
pCreateInfo->ppEnabledExtensionNames, pCreateInfo->ppEnabledExtensionNames,
getInstance()->getDriverLayer()->getSupportedExtensions())); getPhysicalDevice()->getSupportedExtensions()));
} }
// Create the command queues // Create the command queues

View File

@ -58,6 +58,7 @@ MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS)
MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET) MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET)
MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET) MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET)
MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE) MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE)
MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT)
MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER) MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER)
MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR) MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR)
MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET) MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET)

View File

@ -85,6 +85,20 @@ public:
*/ */
std::string enabledNamesString(const char* separator = " ", bool prefixFirstWithSeparator = false) const; std::string enabledNamesString(const char* separator = " ", bool prefixFirstWithSeparator = false) const;
/**
* If pProperties is null, the value of pCount is updated with the number of extensions
* enabled in this list.
*
* If pProperties is not null, then pCount extension properties are copied into the array.
* If the number of available extensions is less than pCount, the value of pCount is updated
* to indicate the number of extension properties actually returned in the array.
*
* Returns VK_SUCCESS if successful. Returns VK_INCOMPLETE if the number of extensions
* enabled in this list is larger than the specified pCount. Returns other values
* if an error occurs.
*/
VkResult getProperties(uint32_t* pCount, VkExtensionProperties* pProperties);
MVKExtensionList(MVKVulkanAPIObject* apiObject, bool enableForPlatform = false); MVKExtensionList(MVKVulkanAPIObject* apiObject, bool enableForPlatform = false);
protected: protected:

View File

@ -50,6 +50,9 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) {
if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) { if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
return mvkOSVersion() >= 10.13; return mvkOSVersion() >= 10.13;
} }
if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
return mvkOSVersion() >= 10.14;
}
if (pProperties == &kVkExtProps_MVK_IOS_SURFACE) { return false; } if (pProperties == &kVkExtProps_MVK_IOS_SURFACE) { return false; }
if (pProperties == &kVkExtProps_IMG_FORMAT_PVRTC) { return false; } if (pProperties == &kVkExtProps_IMG_FORMAT_PVRTC) { return false; }
#endif #endif
@ -58,6 +61,9 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) {
if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) { if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
return mvkOSVersion() >= 11.0; return mvkOSVersion() >= 11.0;
} }
if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
return mvkOSVersion() >= 12.0;
}
if (pProperties == &kVkExtProps_MVK_MACOS_SURFACE) { return false; } if (pProperties == &kVkExtProps_MVK_MACOS_SURFACE) { return false; }
#endif #endif
@ -157,3 +163,31 @@ string MVKExtensionList::enabledNamesString(const char* separator, bool prefixFi
} }
return logMsg; return logMsg;
} }
VkResult MVKExtensionList::getProperties(uint32_t* pCount, VkExtensionProperties* pProperties) {
uint32_t enabledCnt = 0;
// Iterate extensions and handle those that are enabled. Count them,
// and if they are to be returned, and there is room, do so.
uint32_t extnCnt = getCount();
MVKExtension* extnAry = &extensionArray;
for (uint32_t extnIdx = 0; extnIdx < extnCnt; extnIdx++) {
if (extnAry[extnIdx].enabled) {
if (pProperties) {
if (enabledCnt < *pCount) {
pProperties[enabledCnt] = *(extnAry[extnIdx].pProperties);
} else {
return VK_INCOMPLETE;
}
}
enabledCnt++;
}
}
// Return the count of enabled extensions. This will either be a
// count of all enabled extensions, or a count of those returned.
*pCount = enabledCnt;
return VK_SUCCESS;
}

View File

@ -32,29 +32,7 @@ VkLayerProperties* const MVKLayer::getLayerProperties() { return &_layerProperti
VkResult MVKLayer::getExtensionProperties(uint32_t* pCount, VkExtensionProperties* pProperties) { VkResult MVKLayer::getExtensionProperties(uint32_t* pCount, VkExtensionProperties* pProperties) {
uint32_t enabledCnt = 0; return _supportedExtensions.getProperties(pCount, pProperties);
// Iterate extensions and handle those that are enabled. Count them,
// and if they are to be returned, and there is room, do so.
uint32_t extnCnt = _supportedExtensions.getCount();
MVKExtension* extnAry = &_supportedExtensions.extensionArray;
for (uint32_t extnIdx = 0; extnIdx < extnCnt; extnIdx++) {
if (extnAry[extnIdx].enabled) {
if (pProperties) {
if (enabledCnt < *pCount) {
pProperties[enabledCnt] = *(extnAry[extnIdx].pProperties);
} else {
return VK_INCOMPLETE;
}
}
enabledCnt++;
}
}
// Return the count of enabled extensions. This will either be a
// count of all enabled extensions, or a count of those returned.
*pCount = enabledCnt;
return VK_SUCCESS;
} }

View File

@ -282,7 +282,7 @@ MVK_PUBLIC_SYMBOL VkResult vkEnumerateDeviceExtensionProperties(
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice); MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
VkResult rslt = mvkPD->getInstance()->getLayerManager()->getLayerNamed(pLayerName)->getExtensionProperties(pCount, pProperties); VkResult rslt = mvkPD->getExtensionProperties(pLayerName, pCount, pProperties);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
return rslt; return rslt;
} }