Vulkan: Cleanup device feature query and enabling

All device extension features and properties queries are now performed
in a single call for each (i.e. one for features, one for properties),
with all the extension structs chained.  Then based on which feature is
present (not just whether the extension is supported), the extensions
and features are enabled.

In the process, it fixes the following issues:

- If VK_EXT_vertex_attribute_divisor is present, but the necessary
vertexAttributeInstanceRateDivisor feature is not supported, that
feature is not enabled and the emulation path is taken.  Incidentally,
this also fixes an issue with renderdoc that refuses to replay captures
on such devices.
- If VK_EXT_transform_feedback is present, but the necessary
transformFeedback feature is not supported, similarly that feature is
not enabled and the emulation path is taken.

Bug: angleproject:4306
Bug: angleproject:4027
Change-Id: I0969064cba811d215c37dfe551b0ceedb334051c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2005111
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Tobin Ehlis <tobine@google.com>
This commit is contained in:
Shahbaz Youssefi 2020-01-16 14:48:12 -05:00 коммит произвёл Commit Bot
Родитель 3b2780e621
Коммит 13205b935d
3 изменённых файлов: 126 добавлений и 96 удалений

Просмотреть файл

@ -545,7 +545,6 @@ RendererVk::RendererVk()
mDebugUtilsMessenger(VK_NULL_HANDLE),
mDebugReportCallback(VK_NULL_HANDLE),
mPhysicalDevice(VK_NULL_HANDLE),
mPhysicalDeviceSubgroupProperties{},
mQueue(VK_NULL_HANDLE),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mMaxVertexAttribDivisor(1),
@ -558,8 +557,6 @@ RendererVk::RendererVk()
mPipelineCacheDirty(false),
mPipelineCacheInitialized(false)
{
mPhysicalDeviceSubgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
VkFormatProperties invalid = {0, 0, kInvalidFormatFeatureFlags};
mFormatProperties.fill(invalid);
}
@ -891,6 +888,84 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
return angle::Result::Continue;
}
void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExtensionNames)
{
// Default initialize all extension features to false.
mLineRasterizationFeatures = {};
mLineRasterizationFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT;
mProvokingVertexFeatures = {};
mProvokingVertexFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT;
mVertexAttributeDivisorFeatures = {};
mVertexAttributeDivisorFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
mVertexAttributeDivisorProperties = {};
mVertexAttributeDivisorProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
mTransformFeedbackFeatures = {};
mTransformFeedbackFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
mPhysicalDeviceSubgroupProperties = {};
mPhysicalDeviceSubgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
if (!vkGetPhysicalDeviceProperties2KHR || !vkGetPhysicalDeviceFeatures2KHR)
{
return;
}
// Query features and properties.
VkPhysicalDeviceFeatures2KHR deviceFeatures = {};
deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
VkPhysicalDeviceProperties2 deviceProperties = {};
deviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
// Query line rasterization features
if (ExtensionFound(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceFeatures, &mLineRasterizationFeatures);
}
// Query provoking vertex features
if (ExtensionFound(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceFeatures, &mProvokingVertexFeatures);
}
// Query attribute divisor features and properties
if (ExtensionFound(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceFeatures, &mVertexAttributeDivisorFeatures);
vk::AddToPNextChain(&deviceProperties, &mVertexAttributeDivisorProperties);
}
// Query transform feedback features
if (ExtensionFound(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceFeatures, &mTransformFeedbackFeatures);
}
// Query subgroup properties
vk::AddToPNextChain(&deviceProperties, &mPhysicalDeviceSubgroupProperties);
vkGetPhysicalDeviceFeatures2KHR(mPhysicalDevice, &deviceFeatures);
vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
// Clean up pNext chains
mLineRasterizationFeatures.pNext = nullptr;
mProvokingVertexFeatures.pNext = nullptr;
mVertexAttributeDivisorFeatures.pNext = nullptr;
mVertexAttributeDivisorProperties.pNext = nullptr;
mTransformFeedbackFeatures.pNext = nullptr;
mPhysicalDeviceSubgroupProperties.pNext = nullptr;
}
angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex)
{
uint32_t deviceLayerCount = 0;
@ -967,50 +1042,10 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &zeroPriority;
// Setup device initialization struct
VkDeviceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.flags = 0;
createInfo.queueCreateInfoCount = 1;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.enabledLayerCount = static_cast<uint32_t>(enabledDeviceLayerNames.size());
createInfo.ppEnabledLayerNames = enabledDeviceLayerNames.data();
mLineRasterizationFeatures = {};
mLineRasterizationFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT;
ASSERT(mLineRasterizationFeatures.bresenhamLines == VK_FALSE);
if (vkGetPhysicalDeviceFeatures2KHR &&
ExtensionFound(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, deviceExtensionNames))
{
enabledDeviceExtensions.push_back(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
// Query line rasterization capabilities
VkPhysicalDeviceFeatures2KHR availableFeatures = {};
availableFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
vk::AppendToPNextChain(&availableFeatures, &mLineRasterizationFeatures);
vkGetPhysicalDeviceFeatures2KHR(mPhysicalDevice, &availableFeatures);
vk::AppendToPNextChain(&createInfo, &mLineRasterizationFeatures);
}
mProvokingVertexFeatures = {};
mProvokingVertexFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT;
ASSERT(mProvokingVertexFeatures.provokingVertexLast == VK_FALSE);
if (vkGetPhysicalDeviceFeatures2KHR &&
ExtensionFound(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, deviceExtensionNames))
{
enabledDeviceExtensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
// Query line rasterization capabilities
VkPhysicalDeviceFeatures2KHR availableFeatures = {};
availableFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
vk::AppendToPNextChain(&availableFeatures, &mProvokingVertexFeatures);
vkGetPhysicalDeviceFeatures2KHR(mPhysicalDevice, &availableFeatures);
vk::AppendToPNextChain(&createInfo, &mProvokingVertexFeatures);
}
// Query extensions and their features.
queryDeviceExtensionFeatures(deviceExtensionNames);
// Initialize features and workarounds.
if (!displayVk->getState().featuresAllDisabled)
{
initFeatures(deviceExtensionNames);
@ -1088,61 +1123,53 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
}
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT divisorFeatures = {};
divisorFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
if (vkGetPhysicalDeviceProperties2KHR &&
ExtensionFound(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, deviceExtensionNames))
// Setup device initialization struct
VkDeviceCreateInfo createInfo = {};
// Based on available extension features, decide on which extensions and features to enable.
if (mLineRasterizationFeatures.bresenhamLines)
{
enabledDeviceExtensions.push_back(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
vk::AddToPNextChain(&createInfo, &mLineRasterizationFeatures);
}
if (mProvokingVertexFeatures.provokingVertexLast)
{
enabledDeviceExtensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
vk::AddToPNextChain(&createInfo, &mProvokingVertexFeatures);
}
if (mVertexAttributeDivisorFeatures.vertexAttributeInstanceRateDivisor)
{
enabledDeviceExtensions.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
divisorFeatures.vertexAttributeInstanceRateDivisor = true;
vk::AppendToPNextChain(&enabledFeatures, &divisorFeatures);
vk::AddToPNextChain(&createInfo, &mVertexAttributeDivisorFeatures);
VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT divisorProperties = {};
divisorProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
VkPhysicalDeviceProperties2 deviceProperties = {};
deviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
vk::AppendToPNextChain(&deviceProperties, &divisorProperties);
vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
// We only store 8 bit divisor in GraphicsPipelineDesc so capping value & we emulate if
// exceeded
mMaxVertexAttribDivisor =
std::min(divisorProperties.maxVertexAttribDivisor,
std::min(mVertexAttributeDivisorProperties.maxVertexAttribDivisor,
static_cast<uint32_t>(std::numeric_limits<uint8_t>::max()));
vk::AppendToPNextChain(&createInfo, &enabledFeatures);
}
else
{
// Enable all available features
createInfo.pEnabledFeatures = &enabledFeatures.features;
}
if (vkGetPhysicalDeviceProperties2KHR)
{
VkPhysicalDeviceProperties2 deviceProperties = {};
deviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
vk::AppendToPNextChain(&deviceProperties, &mPhysicalDeviceSubgroupProperties);
vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
}
bool supportsTransformFeedbackExt = getFeatures().supportsTransformFeedbackExtension.enabled;
if (supportsTransformFeedbackExt)
if (getFeatures().supportsTransformFeedbackExtension.enabled)
{
enabledDeviceExtensions.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
VkPhysicalDeviceTransformFeedbackFeaturesEXT xfbFeature = {};
xfbFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
xfbFeature.transformFeedback = true;
xfbFeature.geometryStreams = true;
vk::AppendToPNextChain(&enabledFeatures, &xfbFeature);
vk::AddToPNextChain(&createInfo, &mTransformFeedbackFeatures);
}
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.flags = 0;
createInfo.queueCreateInfoCount = 1;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.enabledLayerCount = static_cast<uint32_t>(enabledDeviceLayerNames.size());
createInfo.ppEnabledLayerNames = enabledDeviceLayerNames.data();
createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
createInfo.ppEnabledExtensionNames =
enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
// Enable core features without assuming VkPhysicalDeviceFeatures2KHR is accepted in the pNext
// chain of VkDeviceCreateInfo.
createInfo.pEnabledFeatures = &enabledFeatures.features;
ANGLE_VK_TRY(displayVk, vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice));
volkLoadDevice(mDevice);
@ -1437,9 +1464,8 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
(&mFeatures), supportsShaderStencilExport,
ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames));
ANGLE_FEATURE_CONDITION(
(&mFeatures), supportsTransformFeedbackExtension,
ExtensionFound(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, deviceExtensionNames));
ANGLE_FEATURE_CONDITION((&mFeatures), supportsTransformFeedbackExtension,
mTransformFeedbackFeatures.transformFeedback == VK_TRUE);
ANGLE_FEATURE_CONDITION((&mFeatures), emulateTransformFeedback,
(mFeatures.supportsTransformFeedbackExtension.enabled == VK_FALSE &&

Просмотреть файл

@ -220,6 +220,8 @@ class RendererVk : angle::NonCopyable
angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
void ensureCapsInitialized() const;
void queryDeviceExtensionFeatures(const ExtensionNameList &deviceExtensionNames);
void initFeatures(const ExtensionNameList &extensions);
void initPipelineCacheVkKey();
angle::Result initPipelineCache(DisplayVk *display,
@ -252,10 +254,13 @@ class RendererVk : angle::NonCopyable
VkDebugReportCallbackEXT mDebugReportCallback;
VkPhysicalDevice mPhysicalDevice;
VkPhysicalDeviceProperties mPhysicalDeviceProperties;
VkPhysicalDeviceSubgroupProperties mPhysicalDeviceSubgroupProperties;
VkPhysicalDeviceFeatures mPhysicalDeviceFeatures;
VkPhysicalDeviceLineRasterizationFeaturesEXT mLineRasterizationFeatures;
VkPhysicalDeviceProvokingVertexFeaturesEXT mProvokingVertexFeatures;
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT mVertexAttributeDivisorFeatures;
VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT mVertexAttributeDivisorProperties;
VkPhysicalDeviceTransformFeedbackFeaturesEXT mTransformFeedbackFeatures;
VkPhysicalDeviceSubgroupProperties mPhysicalDeviceSubgroupProperties;
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
std::mutex mQueueMutex;
VkQueue mQueue;

Просмотреть файл

@ -103,16 +103,15 @@ namespace vk
{
struct Format;
// Append ptr to end of pNext chain beginning at chainStart
// Prepend ptr to the pNext chain at chainStart
template <typename VulkanStruct1, typename VulkanStruct2>
void AppendToPNextChain(VulkanStruct1 *chainStart, VulkanStruct2 *ptr)
void AddToPNextChain(VulkanStruct1 *chainStart, VulkanStruct2 *ptr)
{
ASSERT(ptr->pNext == nullptr);
VkBaseOutStructure *localPtr = reinterpret_cast<VkBaseOutStructure *>(chainStart);
while (localPtr->pNext)
{
localPtr = localPtr->pNext;
}
localPtr->pNext = reinterpret_cast<VkBaseOutStructure *>(ptr);
ptr->pNext = localPtr->pNext;
localPtr->pNext = reinterpret_cast<VkBaseOutStructure *>(ptr);
}
extern const char *gLoaderLayersPathEnv;