Skip to content

Commit

Permalink
Vulkan: support instanced draws. (reland)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
fjhenigman authored and Commit Bot committed Feb 14, 2019
1 parent 0c01e36 commit 52047de
Show file tree
Hide file tree
Showing 12 changed files with 204 additions and 89 deletions.
45 changes: 33 additions & 12 deletions src/libANGLE/renderer/vulkan/ContextVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
gl::PrimitiveMode mode,
GLint firstVertex,
GLsizei vertexOrIndexCount,
GLsizei instanceCount,
gl::DrawElementsType indexTypeOrNone,
const void *indices,
DirtyBits dirtyBitMask,
Expand All @@ -216,7 +217,7 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
if (context->getStateCache().hasAnyActiveClientAttrib())
{
ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount,
indexTypeOrNone, indices));
instanceCount, indexTypeOrNone, indices));
mDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
}

Expand Down Expand Up @@ -266,6 +267,7 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
gl::PrimitiveMode mode,
GLsizei indexCount,
GLsizei instanceCount,
gl::DrawElementsType indexType,
const void *indices,
vk::CommandBuffer **commandBufferOut)
Expand Down Expand Up @@ -297,8 +299,8 @@ angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
}
}

return setupDraw(context, mode, 0, indexCount, indexType, indices, mIndexedDirtyBitsMask,
commandBufferOut);
return setupDraw(context, mode, 0, indexCount, instanceCount, indexType, indices,
mIndexedDirtyBitsMask, commandBufferOut);
}

angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
Expand All @@ -315,7 +317,7 @@ angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
? indexTypeOrInvalid
: gl::DrawElementsType::UnsignedInt;
return setupDraw(context, mode, firstVertex, vertexOrIndexCount, indexTypeOrInvalid, indices,
return setupDraw(context, mode, firstVertex, vertexOrIndexCount, 1, indexTypeOrInvalid, indices,
mIndexedDirtyBitsMask, commandBufferOut);
}

Expand Down Expand Up @@ -455,8 +457,8 @@ angle::Result ContextVk::drawArrays(const gl::Context *context,
}
else
{
ANGLE_TRY(setupDraw(context, mode, first, count, gl::DrawElementsType::InvalidEnum, nullptr,
mNonIndexedDirtyBitsMask, &commandBuffer));
ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum,
nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
commandBuffer->draw(clampedVertexCount, 1, first, 0);
}

Expand All @@ -467,10 +469,20 @@ angle::Result ContextVk::drawArraysInstanced(const gl::Context *context,
gl::PrimitiveMode mode,
GLint first,
GLsizei count,
GLsizei instanceCount)
GLsizei instances)
{
ANGLE_VK_UNREACHABLE(this);
return angle::Result::Stop;
if (mode == gl::PrimitiveMode::LineLoop)
{
// TODO - http://anglebug.com/2672
ANGLE_VK_UNREACHABLE(this);
return angle::Result::Stop;
}

vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
commandBuffer->draw(gl::GetClampedVertexCount<uint32_t>(count), instances, first, 0);
return angle::Result::Continue;
}

angle::Result ContextVk::drawElements(const gl::Context *context,
Expand All @@ -487,7 +499,7 @@ angle::Result ContextVk::drawElements(const gl::Context *context,
}
else
{
ANGLE_TRY(setupIndexedDraw(context, mode, count, type, indices, &commandBuffer));
ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices, &commandBuffer));
commandBuffer->drawIndexed(count, 1, 0, 0, 0);
}

Expand All @@ -501,8 +513,17 @@ angle::Result ContextVk::drawElementsInstanced(const gl::Context *context,
const void *indices,
GLsizei instances)
{
ANGLE_VK_UNREACHABLE(this);
return angle::Result::Stop;
if (mode == gl::PrimitiveMode::LineLoop)
{
// TODO - http://anglebug.com/2672
ANGLE_VK_UNREACHABLE(this);
return angle::Result::Stop;
}

vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer));
commandBuffer->drawIndexed(count, instances, 0, 0, 0);
return angle::Result::Continue;
}

angle::Result ContextVk::drawRangeElements(const gl::Context *context,
Expand Down
4 changes: 3 additions & 1 deletion src/libANGLE/renderer/vulkan/ContextVk.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
GLsizei count,
gl::DrawElementsType type,
const void *indices,
GLsizei instances) override;
GLsizei instanceCount) override;
angle::Result drawRangeElements(const gl::Context *context,
gl::PrimitiveMode mode,
GLuint start,
Expand Down Expand Up @@ -232,13 +232,15 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
gl::PrimitiveMode mode,
GLint firstVertex,
GLsizei vertexOrIndexCount,
GLsizei instanceCount,
gl::DrawElementsType indexTypeOrInvalid,
const void *indices,
DirtyBits dirtyBitMask,
vk::CommandBuffer **commandBufferOut);
angle::Result setupIndexedDraw(const gl::Context *context,
gl::PrimitiveMode mode,
GLsizei indexCount,
GLsizei instanceCount,
gl::DrawElementsType indexType,
const void *indices,
vk::CommandBuffer **commandBufferOut);
Expand Down
138 changes: 95 additions & 43 deletions src/libANGLE/renderer/vulkan/RendererVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,38 +74,24 @@ bool ShouldEnableMockICD(const egl::AttributeMap &attribs)
#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 strcmp(a, b) < 0;
}

return VK_SUCCESS;
VkResult VerifyExtensionsPresent(const RendererVk::ExtensionNameList &haystack,
const RendererVk::ExtensionNameList &needles)
{
// 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 *extensionName,
const std::vector<VkExtensionProperties> &extensionProps)
bool ExtensionFound(const char *needle, const RendererVk::ExtensionNameList &haystack)
{
for (const auto &extensionProp : extensionProps)
{
if (strcmp(extensionProp.extensionName, extensionName) == 0)
{
return true;
}
}
return false;
// 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
Expand Down Expand Up @@ -513,6 +499,7 @@ RendererVk::RendererVk()
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()),
Expand Down Expand Up @@ -664,16 +651,26 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
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)
{
Expand All @@ -685,8 +682,16 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
}

// 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;
Expand Down Expand Up @@ -767,6 +772,14 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
&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);
Expand Down Expand Up @@ -882,10 +895,21 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
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.
Expand All @@ -899,17 +923,21 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
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;
Expand All @@ -925,10 +953,34 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
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));

Expand Down Expand Up @@ -1073,7 +1125,7 @@ gl::Version RendererVk::getMaxSupportedESVersion() const
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
Expand All @@ -1084,7 +1136,7 @@ void RendererVk::initFeatures(const std::vector<VkExtensionProperties> &deviceEx
#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
Expand Down Expand Up @@ -1124,7 +1176,7 @@ void RendererVk::initFeatures(const std::vector<VkExtensionProperties> &deviceEx
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;
}
Expand Down
6 changes: 5 additions & 1 deletion src/libANGLE/renderer/vulkan/RendererVk.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ class RendererVk : angle::NonCopyable
bool hasTextureFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);

static constexpr size_t kMaxExtensionNames = 200;
using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>;

private:
// Number of semaphores for external entities to renderer to issue a wait, such as surface's
// image acquire.
Expand All @@ -224,7 +227,7 @@ class RendererVk : angle::NonCopyable
vk::CommandBuffer &&commandBuffer);
void freeAllInFlightResources();
angle::Result flushCommandGraph(vk::Context *context, vk::CommandBuffer *commandBatch);
void initFeatures(const std::vector<VkExtensionProperties> &deviceExtensionProps);
void initFeatures(const ExtensionNameList &extensions);
void initPipelineCacheVkKey();
angle::Result initPipelineCache(DisplayVk *display);

Expand Down Expand Up @@ -262,6 +265,7 @@ class RendererVk : angle::NonCopyable
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
VkQueue mQueue;
uint32_t mCurrentQueueFamilyIndex;
uint32_t mMaxVertexAttribDivisor;
VkDevice mDevice;
vk::CommandPool mCommandPool;
SerialFactory mQueueSerialFactory;
Expand Down
Loading

0 comments on commit 52047de

Please sign in to comment.