Return error for requested unsupported features
Per the Vulkan spec:
If any requested feature is not supported, vkCreateDevice
must return VK_ERROR_FEATURE_NOT_PRESENT.
I've added a templated function to vk::PhysicalDevice that compares
requested features against the results of a call to getFeatures2. This
keeps the places that reference support for a feature localized to
VkPhysicalDevice.cpp.
Bug: b/198667115
Tests: dEQP-VK.api.device_init.create_device_unsupported_features
Change-Id: I7a49b607ea1513ba568a82c0655a63e17f12f2b1
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/56969
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Sean Risser <srisser@google.com>
Commit-Queue: Sean Risser <srisser@google.com>
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 7cbe047..3eaff75 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -1060,6 +1060,42 @@
return true;
}
+template<typename T>
+bool PhysicalDevice::hasExtendedFeatures(const T *requestedFeature) const
+{
+ VkPhysicalDeviceFeatures2 features;
+ features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ T supportedFeature;
+ supportedFeature.sType = requestedFeature->sType;
+ supportedFeature.pNext = nullptr;
+ features.pNext = &supportedFeature;
+
+ getFeatures2(&features);
+ size_t offsetToFirstBool32 = sizeof(VkBaseOutStructure);
+ size_t numFeatures = (sizeof(T) - offsetToFirstBool32) / sizeof(VkBool32);
+ const VkBool32 *requestedFeatureBools = reinterpret_cast<const VkBool32 *>(
+ reinterpret_cast<const uint8_t *>(requestedFeature) + offsetToFirstBool32);
+ const VkBool32 *supportedFeatureBools = reinterpret_cast<const VkBool32 *>(
+ reinterpret_cast<const uint8_t *>(&supportedFeature) + offsetToFirstBool32);
+
+ for(size_t i = 0; i < numFeatures; i++)
+ {
+ if((requestedFeatureBools[i] != VK_FALSE) && (supportedFeatureBools[i] == VK_FALSE))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+#define InstantiateHasExtendedFeatures(Type) template bool PhysicalDevice::hasExtendedFeatures<Type>(const Type *requestedFeature) const
+InstantiateHasExtendedFeatures(VkPhysicalDeviceLineRasterizationFeaturesEXT);
+InstantiateHasExtendedFeatures(VkPhysicalDeviceProvokingVertexFeaturesEXT);
+InstantiateHasExtendedFeatures(VkPhysicalDeviceVulkan11Features);
+InstantiateHasExtendedFeatures(VkPhysicalDeviceVulkan12Features);
+InstantiateHasExtendedFeatures(VkPhysicalDeviceDepthClipEnableFeaturesEXT);
+#undef InstantiateHasExtendedFeatures
+
void PhysicalDevice::GetFormatProperties(Format format, VkFormatProperties *pFormatProperties)
{
pFormatProperties->linearTilingFeatures = 0; // Unsupported format
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp
index 31647f5..068011a 100644
--- a/src/Vulkan/VkPhysicalDevice.hpp
+++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -37,6 +37,8 @@
const VkPhysicalDeviceFeatures &getFeatures() const;
void getFeatures2(VkPhysicalDeviceFeatures2 *features) const;
bool hasFeatures(const VkPhysicalDeviceFeatures &requestedFeatures) const;
+ template<typename T>
+ bool hasExtendedFeatures(const T *requestedFeature) const;
const VkPhysicalDeviceProperties &getProperties() const;
void getProperties(VkPhysicalDeviceIDProperties *properties) const;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 1dcb45e..4efba76 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -791,11 +791,9 @@
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT:
{
- const VkPhysicalDeviceLineRasterizationFeaturesEXT *lineRasterizationFeatures = reinterpret_cast<const VkPhysicalDeviceLineRasterizationFeaturesEXT *>(extensionCreateInfo);
- if((lineRasterizationFeatures->smoothLines != VK_FALSE) ||
- (lineRasterizationFeatures->stippledBresenhamLines != VK_FALSE) ||
- (lineRasterizationFeatures->stippledRectangularLines != VK_FALSE) ||
- (lineRasterizationFeatures->stippledSmoothLines != VK_FALSE))
+ const auto *lineRasterizationFeatures = reinterpret_cast<const VkPhysicalDeviceLineRasterizationFeaturesEXT *>(extensionCreateInfo);
+ bool hasFeatures = vk::Cast(physicalDevice)->hasExtendedFeatures(lineRasterizationFeatures);
+ if(!hasFeatures)
{
return VK_ERROR_FEATURE_NOT_PRESENT;
}
@@ -804,12 +802,11 @@
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT:
{
const VkPhysicalDeviceProvokingVertexFeaturesEXT *provokingVertexFeatures = reinterpret_cast<const VkPhysicalDeviceProvokingVertexFeaturesEXT *>(extensionCreateInfo);
-
- // Provoking vertex is supported.
- // provokingVertexFeatures->provokingVertexLast can be VK_TRUE or VK_FALSE.
- // No action needs to be taken on our end in either case; it's the apps responsibility to check
- // that the provokingVertexLast feature is enabled before using the provoking vertex convention.
- (void)provokingVertexFeatures->provokingVertexLast;
+ bool hasFeatures = vk::Cast(physicalDevice)->hasExtendedFeatures(provokingVertexFeatures);
+ if(!hasFeatures)
+ {
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+ }
}
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT:
@@ -874,6 +871,36 @@
(void)customBorderColorFeatures->customBorderColorWithoutFormat;
}
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES:
+ {
+ const auto *vk11Features = reinterpret_cast<const VkPhysicalDeviceVulkan11Features *>(extensionCreateInfo);
+ bool hasFeatures = vk::Cast(physicalDevice)->hasExtendedFeatures(vk11Features);
+ if(!hasFeatures)
+ {
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+ }
+ }
+ break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES:
+ {
+ const auto *vk12Features = reinterpret_cast<const VkPhysicalDeviceVulkan12Features *>(extensionCreateInfo);
+ bool hasFeatures = vk::Cast(physicalDevice)->hasExtendedFeatures(vk12Features);
+ if(!hasFeatures)
+ {
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+ }
+ }
+ break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT:
+ {
+ const auto *depthClipFeatures = reinterpret_cast<const VkPhysicalDeviceDepthClipEnableFeaturesEXT *>(extensionCreateInfo);
+ bool hasFeatures = vk::Cast(physicalDevice)->hasExtendedFeatures(depthClipFeatures);
+ if(!hasFeatures)
+ {
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+ }
+ }
+ break;
default:
// "the [driver] must skip over, without processing (other than reading the sType and pNext members) any structures in the chain with sType values not defined by [supported extenions]"
LOG_TRAP("pCreateInfo->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str());