Commit 71c1138d by Tobin Ehlis Committed by Commit Bot

Vulkan: Emulate instanced attrib divisor

This sets instancedArrays[ANGLE|EXT] extenstions as always supported regardless of underlying Vulkan HW's max vertex attrib divisor. Then detect instances where app sets a divisor that isn't supported by hardware and emulate those cases. Emulations is accomplished by copying the instanced attribs to a new buffer where each attrib is present once per instance, using the attrib divisor value as a factor to replicate the attribs, and then setting the actual divisor value for the draw to "1". Also, we only store 8 bits for the divisor used in the PSO, so this code also handles emulation of the case where divisor is > 255. This is passing all of the drawInstanced/Elements dEQP tests where divisor has to be emulated. Also enabled end2end InstancingTestES3 for Vulkan backend. Bug: angleproject:2672 Change-Id: I9932f9eab49b16a19e8bbd35dacaf3b5a27a213f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1758689Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com> Commit-Queue: Tobin Ehlis <tobine@google.com>
parent cb16fb5f
...@@ -477,12 +477,14 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, ...@@ -477,12 +477,14 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
} }
// Must be called before the command buffer is started. Can call finish. // Must be called before the command buffer is started. Can call finish.
if (context->getStateCache().hasAnyActiveClientAttrib()) if (mVertexArray->getStreamingVertexAttribsMask().any())
{ {
ASSERT(firstVertexOrInvalid != -1); ASSERT(firstVertexOrInvalid != -1);
ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertexOrInvalid, // All client attribs & any emulated buffered attribs will be updated
vertexOrIndexCount, instanceCount, ANGLE_TRY(mVertexArray->updateStreamedAttribs(context, firstVertexOrInvalid,
indexTypeOrInvalid, indices)); vertexOrIndexCount, instanceCount,
indexTypeOrInvalid, indices));
mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS); mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
} }
......
...@@ -213,9 +213,10 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -213,9 +213,10 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
GLuint relativeOffset) GLuint relativeOffset)
{ {
invalidateVertexAndIndexBuffers(); invalidateVertexAndIndexBuffers();
mGraphicsPipelineDesc->updateVertexInput(&mGraphicsPipelineTransition, // Set divisor to 1 for attribs with emulated divisor
static_cast<uint32_t>(attribIndex), stride, mGraphicsPipelineDesc->updateVertexInput(
divisor, format, relativeOffset); &mGraphicsPipelineTransition, static_cast<uint32_t>(attribIndex), stride,
divisor > mRenderer->getMaxVertexAttribDivisor() ? 1 : divisor, format, relativeOffset);
} }
void invalidateDefaultAttribute(size_t attribIndex); void invalidateDefaultAttribute(size_t attribIndex);
......
...@@ -1056,7 +1056,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1056,7 +1056,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
deviceProperties.pNext = &divisorProperties; deviceProperties.pNext = &divisorProperties;
vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties); vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
mMaxVertexAttribDivisor = divisorProperties.maxVertexAttribDivisor; // We only store 8 bit divisor in GraphicsPipelineDesc so capping value & we emulate if
// exceeded
mMaxVertexAttribDivisor =
std::min(divisorProperties.maxVertexAttribDivisor,
static_cast<uint32_t>(std::numeric_limits<uint8_t>::max()));
createInfo.pNext = &enabledFeatures; createInfo.pNext = &enabledFeatures;
} }
......
...@@ -125,6 +125,7 @@ class RendererVk : angle::NonCopyable ...@@ -125,6 +125,7 @@ class RendererVk : angle::NonCopyable
ASSERT(mFeaturesInitialized); ASSERT(mFeaturesInitialized);
return mFeatures; return mFeatures;
} }
uint32_t getMaxVertexAttribDivisor() const { return mMaxVertexAttribDivisor; }
bool isMockICDEnabled() const { return mEnabledICD == vk::ICD::Mock; } bool isMockICDEnabled() const { return mEnabledICD == vk::ICD::Mock; }
......
...@@ -37,12 +37,12 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -37,12 +37,12 @@ class VertexArrayVk : public VertexArrayImpl
VkBuffer bufferHandle, VkBuffer bufferHandle,
uint32_t offset); uint32_t offset);
angle::Result updateClientAttribs(const gl::Context *context, angle::Result updateStreamedAttribs(const gl::Context *context,
GLint firstVertex, GLint firstVertex,
GLsizei vertexOrIndexCount, GLsizei vertexOrIndexCount,
GLsizei instanceCount, GLsizei instanceCount,
gl::DrawElementsType indexTypeOrInvalid, gl::DrawElementsType indexTypeOrInvalid,
const void *indices); const void *indices);
angle::Result handleLineLoop(ContextVk *contextVk, angle::Result handleLineLoop(ContextVk *contextVk,
GLint firstVertex, GLint firstVertex,
...@@ -92,6 +92,11 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -92,6 +92,11 @@ class VertexArrayVk : public VertexArrayImpl
size_t indexCount, size_t indexCount,
const void *sourcePointer); const void *sourcePointer);
const gl::AttributesMask &getStreamingVertexAttribsMask() const
{
return mStreamingVertexAttribsMask;
}
private: private:
void setDefaultPackedInput(ContextVk *contextVk, size_t attribIndex); void setDefaultPackedInput(ContextVk *contextVk, size_t attribIndex);
...@@ -133,6 +138,9 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -133,6 +138,9 @@ class VertexArrayVk : public VertexArrayImpl
// Vulkan does not allow binding a null vertex buffer. We use a dummy as a placeholder. // Vulkan does not allow binding a null vertex buffer. We use a dummy as a placeholder.
vk::BufferHelper mTheNullBuffer; vk::BufferHelper mTheNullBuffer;
// Track client and/or emulated attribs that we have to stream their buffer contents
gl::AttributesMask mStreamingVertexAttribsMask;
}; };
} // namespace rx } // namespace rx
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/ProgramVk.h" #include "libANGLE/renderer/vulkan/ProgramVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/VertexArrayVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h" #include "libANGLE/renderer/vulkan/vk_helpers.h"
...@@ -673,7 +674,6 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -673,7 +674,6 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
VkPipelineVertexInputDivisorStateCreateInfoEXT divisorState = {}; VkPipelineVertexInputDivisorStateCreateInfoEXT divisorState = {};
divisorState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; divisorState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
divisorState.pVertexBindingDivisors = divisorDesc.data(); divisorState.pVertexBindingDivisors = divisorDesc.data();
for (size_t attribIndexSizeT : activeAttribLocationsMask) for (size_t attribIndexSizeT : activeAttribLocationsMask)
{ {
const uint32_t attribIndex = static_cast<uint32_t>(attribIndexSizeT); const uint32_t attribIndex = static_cast<uint32_t>(attribIndexSizeT);
...@@ -885,10 +885,6 @@ void GraphicsPipelineDesc::updateVertexInput(GraphicsPipelineTransitionBits *tra ...@@ -885,10 +885,6 @@ void GraphicsPipelineDesc::updateVertexInput(GraphicsPipelineTransitionBits *tra
{ {
vk::PackedAttribDesc &packedAttrib = mVertexInputAttribs.attribs[attribIndex]; vk::PackedAttribDesc &packedAttrib = mVertexInputAttribs.attribs[attribIndex];
// TODO: Handle the case where the divisor overflows the field that holds it.
// http://anglebug.com/2672
ASSERT(divisor <= std::numeric_limits<decltype(packedAttrib.divisor)>::max());
SetBitField(packedAttrib.stride, stride); SetBitField(packedAttrib.stride, stride);
SetBitField(packedAttrib.divisor, divisor); SetBitField(packedAttrib.divisor, divisor);
......
...@@ -38,7 +38,7 @@ using RefCountedPipelineLayout = RefCounted<PipelineLayout>; ...@@ -38,7 +38,7 @@ using RefCountedPipelineLayout = RefCounted<PipelineLayout>;
// fewer bits. For example, boolean values could be represented by a single bit instead // fewer bits. For example, boolean values could be represented by a single bit instead
// of a uint8_t. However at the current time there are concerns about the portability // of a uint8_t. However at the current time there are concerns about the portability
// of bitfield operators, and complexity issues with using bit mask operations. This is // of bitfield operators, and complexity issues with using bit mask operations. This is
// something likely we will want to investigate as the Vulkan implementation progresses. // something we will likely want to investigate as the Vulkan implementation progresses.
// //
// Second implementation note: the struct packing is also a bit fragile, and some of the // Second implementation note: the struct packing is also a bit fragile, and some of the
// packing requirements depend on using alignas and field ordering to get the result of // packing requirements depend on using alignas and field ordering to get the result of
...@@ -164,8 +164,6 @@ static_assert(sizeof(AttachmentOpsArray) == 20, "Size check failed"); ...@@ -164,8 +164,6 @@ static_assert(sizeof(AttachmentOpsArray) == 20, "Size check failed");
struct PackedAttribDesc final struct PackedAttribDesc final
{ {
uint8_t format; uint8_t format;
// TODO(http://anglebug.com/2672): Emulate divisors greater than UBYTE_MAX.
uint8_t divisor; uint8_t divisor;
// Can only take 11 bits on NV. // Can only take 11 bits on NV.
...@@ -315,9 +313,9 @@ constexpr size_t kPackedInputAssemblyAndColorBlendStateSize = ...@@ -315,9 +313,9 @@ constexpr size_t kPackedInputAssemblyAndColorBlendStateSize =
static_assert(kPackedInputAssemblyAndColorBlendStateSize == 56, "Size check failed"); static_assert(kPackedInputAssemblyAndColorBlendStateSize == 56, "Size check failed");
constexpr size_t kGraphicsPipelineDescSumOfSizes = constexpr size_t kGraphicsPipelineDescSumOfSizes =
kVertexInputAttributesSize + kPackedInputAssemblyAndColorBlendStateSize + kVertexInputAttributesSize + kRenderPassDescSize + kPackedRasterizationAndMultisampleStateSize +
kPackedRasterizationAndMultisampleStateSize + kPackedDepthStencilStateSize + kPackedDepthStencilStateSize + kPackedInputAssemblyAndColorBlendStateSize + sizeof(VkViewport) +
kRenderPassDescSize + sizeof(VkViewport) + sizeof(VkRect2D); sizeof(VkRect2D);
// Number of dirty bits in the dirty bit set. // Number of dirty bits in the dirty bit set.
constexpr size_t kGraphicsPipelineDirtyBitBytes = 4; constexpr size_t kGraphicsPipelineDirtyBitBytes = 4;
......
...@@ -82,10 +82,9 @@ void RendererVk::ensureCapsInitialized() const ...@@ -82,10 +82,9 @@ void RendererVk::ensureCapsInitialized() const
mNativeExtensions.vertexHalfFloat = true; mNativeExtensions.vertexHalfFloat = true;
// TODO: Enable this always and emulate instanced draws if any divisor exceeds the maximum // Enabled in HW if VK_EXT_vertex_attribute_divisor available, otherwise emulated
// supported. http://anglebug.com/2672 mNativeExtensions.instancedArraysANGLE = true;
mNativeExtensions.instancedArraysANGLE = mMaxVertexAttribDivisor > 1; mNativeExtensions.instancedArraysEXT = true;
mNativeExtensions.instancedArraysEXT = mMaxVertexAttribDivisor > 1;
// Only expose robust buffer access if the physical device supports it. // Only expose robust buffer access if the physical device supports it.
mNativeExtensions.robustBufferAccessBehavior = mNativeExtensions.robustBufferAccessBehavior =
......
...@@ -555,16 +555,6 @@ ...@@ -555,16 +555,6 @@
3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.link_program = FAIL 3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.link_program = FAIL
3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.use_program = FAIL 3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.use_program = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.draw_elements_instanced.attribute_divisor.2*_instances = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.draw_elements_instanced.attribute_divisor.4_instances = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.draw_elements_instanced.mixed.2*_instances = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.draw_elements_instanced.mixed.4_instances = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.draw_arrays_instanced.attribute_divisor.2*_instances = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.draw_arrays_instanced.attribute_divisor.4_instances = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.draw_arrays_instanced.mixed.2*_instances = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.draw_arrays_instanced.mixed.4_instances = FAIL
2672 VULKAN : dEQP-GLES3.functional.instanced.types* = FAIL
// Polygon offset: // Polygon offset:
3678 VULKAN : dEQP-GLES3.functional.polygon_offset.float32_result_depth_clamp = FAIL 3678 VULKAN : dEQP-GLES3.functional.polygon_offset.float32_result_depth_clamp = FAIL
3678 VULKAN : dEQP-GLES3.functional.polygon_offset.float32_factor_1_slope = FAIL 3678 VULKAN : dEQP-GLES3.functional.polygon_offset.float32_factor_1_slope = FAIL
......
...@@ -588,7 +588,7 @@ TEST_P(InstancingTestES3, LargestDivisor) ...@@ -588,7 +588,7 @@ TEST_P(InstancingTestES3, LargestDivisor)
<< "Vertex attrib divisor read was not the same that was passed in."; << "Vertex attrib divisor read was not the same that was passed in.";
} }
ANGLE_INSTANTIATE_TEST(InstancingTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11()); ANGLE_INSTANTIATE_TEST(InstancingTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11(), ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(InstancingTestES31, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11()); ANGLE_INSTANTIATE_TEST(InstancingTestES31, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment