Vulkan: support instanced draws. (reland)
Enable instanced draws with the Vulkan backend.
So far it only works when Vulkan has VK_EXT_vertex_attribute_divisor.
BUG=angleproject:2672
Change-Id: Ib6655625776344305911a1a742c85f17638cee8f
Reviewed-on: https://chromium-review.googlesource.com/c/1469263
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Frank Henigman <fjhenigman@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index eab2c6d..d84b13e 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -74,38 +74,24 @@
#endif // !defined(ANGLE_PLATFORM_ANDROID)
}
-VkResult VerifyExtensionsPresent(const std::vector<VkExtensionProperties> &extensionProps,
- const std::vector<const char *> &enabledExtensionNames)
+bool StrLess(const char *a, const char *b)
{
- // Compile the extensions names into a set.
- std::set<std::string> extensionNames;
- for (const auto &extensionProp : extensionProps)
- {
- extensionNames.insert(extensionProp.extensionName);
- }
-
- for (const char *extensionName : enabledExtensionNames)
- {
- if (extensionNames.count(extensionName) == 0)
- {
- return VK_ERROR_EXTENSION_NOT_PRESENT;
- }
- }
-
- return VK_SUCCESS;
+ return strcmp(a, b) < 0;
}
-bool ExtensionFound(const char *extensionName,
- const std::vector<VkExtensionProperties> &extensionProps)
+VkResult VerifyExtensionsPresent(const RendererVk::ExtensionNameList &haystack,
+ const RendererVk::ExtensionNameList &needles)
{
- for (const auto &extensionProp : extensionProps)
- {
- if (strcmp(extensionProp.extensionName, extensionName) == 0)
- {
- return true;
- }
- }
- return false;
+ // NOTE: The lists must be sorted.
+ return std::includes(haystack.begin(), haystack.end(), needles.begin(), needles.end(), StrLess)
+ ? VK_SUCCESS
+ : VK_ERROR_EXTENSION_NOT_PRESENT;
+}
+
+bool ExtensionFound(const char *needle, const RendererVk::ExtensionNameList &haystack)
+{
+ // NOTE: The list must be sorted.
+ return std::binary_search(haystack.begin(), haystack.end(), needle, StrLess);
}
// Array of Validation error/warning messages that will be ignored, should include bugID
@@ -513,6 +499,7 @@
mPhysicalDevice(VK_NULL_HANDLE),
mQueue(VK_NULL_HANDLE),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
+ mMaxVertexAttribDivisor(1),
mDevice(VK_NULL_HANDLE),
mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate()),
@@ -664,16 +651,26 @@
instanceExtensionProps.data() + previousExtensionCount));
}
- std::vector<const char *> enabledInstanceExtensions;
+ ExtensionNameList instanceExtensionNames;
+ if (!instanceExtensionProps.empty())
+ {
+ for (const VkExtensionProperties &i : instanceExtensionProps)
+ {
+ instanceExtensionNames.push_back(i.extensionName);
+ }
+ std::sort(instanceExtensionNames.begin(), instanceExtensionNames.end(), StrLess);
+ }
+
+ ExtensionNameList enabledInstanceExtensions;
enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
enabledInstanceExtensions.push_back(wsiExtension);
bool enableDebugUtils =
mEnableValidationLayers &&
- ExtensionFound(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instanceExtensionProps);
+ ExtensionFound(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instanceExtensionNames);
bool enableDebugReport =
mEnableValidationLayers && !enableDebugUtils &&
- ExtensionFound(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instanceExtensionProps);
+ ExtensionFound(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instanceExtensionNames);
if (enableDebugUtils)
{
@@ -685,8 +682,16 @@
}
// Verify the required extensions are in the extension names set. Fail if not.
+ std::sort(enabledInstanceExtensions.begin(), enabledInstanceExtensions.end(), StrLess);
ANGLE_VK_TRY(displayVk,
- VerifyExtensionsPresent(instanceExtensionProps, enabledInstanceExtensions));
+ VerifyExtensionsPresent(instanceExtensionNames, enabledInstanceExtensions));
+
+ // Enable VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME if available.
+ if (ExtensionFound(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+ instanceExtensionNames))
+ {
+ enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+ }
VkApplicationInfo applicationInfo = {};
applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
@@ -767,6 +772,14 @@
&mDebugReportCallback));
}
+ if (std::find(enabledInstanceExtensions.begin(), enabledInstanceExtensions.end(),
+ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) !=
+ enabledInstanceExtensions.end())
+ {
+ InitGetPhysicalDeviceProperties2KHRFunctions(mInstance);
+ ASSERT(vkGetPhysicalDeviceProperties2KHR);
+ }
+
uint32_t physicalDeviceCount = 0;
ANGLE_VK_TRY(displayVk, vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
ANGLE_VK_CHECK(displayVk, physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED);
@@ -882,10 +895,21 @@
deviceExtensionProps.data() + previousExtensionCount));
}
- std::vector<const char *> enabledDeviceExtensions;
+ ExtensionNameList deviceExtensionNames;
+ if (!deviceExtensionProps.empty())
+ {
+ ASSERT(deviceExtensionNames.size() <= deviceExtensionProps.size());
+ for (const VkExtensionProperties &prop : deviceExtensionProps)
+ {
+ deviceExtensionNames.push_back(prop.extensionName);
+ }
+ std::sort(deviceExtensionNames.begin(), deviceExtensionNames.end(), StrLess);
+ }
+
+ ExtensionNameList enabledDeviceExtensions;
enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
- initFeatures(deviceExtensionProps);
+ initFeatures(deviceExtensionNames);
mFeaturesInitialized = true;
// Selectively enable KHR_MAINTENANCE1 to support viewport flipping.
@@ -899,17 +923,21 @@
enabledDeviceExtensions.push_back(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
}
- ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionProps, enabledDeviceExtensions));
+ std::sort(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), StrLess);
+ ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionNames, enabledDeviceExtensions));
// Select additional features to be enabled
- VkPhysicalDeviceFeatures enabledFeatures = {};
- enabledFeatures.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
- enabledFeatures.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess;
+ VkPhysicalDeviceFeatures2KHR enabledFeatures = {};
+ enabledFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
+ enabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess;
- VkDeviceQueueCreateInfo queueCreateInfo = {};
+ VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT divisorFeatures = {};
+ divisorFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
+ divisorFeatures.vertexAttributeInstanceRateDivisor = true;
float zeroPriority = 0.0f;
-
+ VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.flags = 0;
queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
@@ -925,10 +953,34 @@
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.enabledLayerCount = enabledDeviceLayerNames.size();
createInfo.ppEnabledLayerNames = enabledDeviceLayerNames.data();
+
+ if (vkGetPhysicalDeviceProperties2KHR &&
+ ExtensionFound(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, deviceExtensionNames))
+ {
+ enabledDeviceExtensions.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
+ enabledFeatures.pNext = &divisorFeatures;
+
+ 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;
+ deviceProperties.pNext = &divisorProperties;
+
+ vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
+ mMaxVertexAttribDivisor = divisorProperties.maxVertexAttribDivisor;
+
+ createInfo.pNext = &enabledFeatures;
+ }
+ else
+ {
+ createInfo.pEnabledFeatures = &enabledFeatures.features;
+ }
+
createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
createInfo.ppEnabledExtensionNames =
enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
- createInfo.pEnabledFeatures = &enabledFeatures;
ANGLE_VK_TRY(displayVk, vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice));
@@ -1073,7 +1125,7 @@
return maxVersion;
}
-void RendererVk::initFeatures(const std::vector<VkExtensionProperties> &deviceExtensionProps)
+void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
{
// Use OpenGL line rasterization rules by default.
// TODO(jmadill): Fix Android support. http://anglebug.com/2830
@@ -1084,7 +1136,7 @@
#endif // defined(ANGLE_PLATFORM_ANDROID)
if ((mPhysicalDeviceProperties.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) ||
- ExtensionFound(VK_KHR_MAINTENANCE1_EXTENSION_NAME, deviceExtensionProps))
+ ExtensionFound(VK_KHR_MAINTENANCE1_EXTENSION_NAME, deviceExtensionNames))
{
// TODO(lucferron): Currently disabled on Intel only since many tests are failing and need
// investigation. http://anglebug.com/2728
@@ -1124,7 +1176,7 @@
IsNexus5X(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID);
#endif
- if (ExtensionFound(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, deviceExtensionProps))
+ if (ExtensionFound(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, deviceExtensionNames))
{
mFeatures.supportsIncrementalPresent = true;
}