mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
Vulkan: Implement GL_EXT_multi_draw_indirect
* Optimized the implementations of multiDrawArraysIndirect() and multiDrawElementsIndirect() for Vulkan * Added helper functions to support drawArraysIndirect() and drawElementsIndirect() as special cases of multiDraw*Indirect functions. * Added the flag to enable the multiDrawIndirect feature (drawCount > 1). The generic implementation is used if the flag is disabled. Bug: angleproject:6439 Change-Id: Ibc653d93d355657f828de9c33da22428629e450f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3276044 Commit-Queue: Amirali Abdolrashidi <abdolrashidi@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
committed by
Angle LUCI CQ
parent
6233dc7e8f
commit
79f9d163b4
@@ -193,6 +193,12 @@ struct FeaturesVk : FeatureSetBase
|
||||
"VkDevice supports the VK_EXT_custom_border_color extension", &members,
|
||||
"http://anglebug.com/3577"};
|
||||
|
||||
// Whether the VkDevice supports multiDrawIndirect (drawIndirect with drawCount > 1)
|
||||
// http://anglebug.com/6439
|
||||
Feature supportsMultiDrawIndirect = {
|
||||
"supportsMultiDrawIndirect", FeatureCategory::VulkanFeatures,
|
||||
"VkDevice supports the multiDrawIndirect extension", &members, "http://anglebug.com/6439"};
|
||||
|
||||
// Whether the VkDevice supports the VK_KHR_depth_stencil_resolve extension with the
|
||||
// independentResolveNone feature.
|
||||
// http://anglebug.com/4836
|
||||
|
||||
@@ -140,6 +140,30 @@ constexpr size_t kDefaultValueSize = sizeof(gl::VertexAttribCurrent
|
||||
constexpr size_t kDefaultBufferSize = kDefaultValueSize * 16;
|
||||
constexpr size_t kDriverUniformsAllocatorPageSize = 4 * 1024;
|
||||
|
||||
bool CanMultiDrawIndirectUseCmd(ContextVk *contextVk,
|
||||
VertexArrayVk *vertexArray,
|
||||
gl::PrimitiveMode mode,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride)
|
||||
{
|
||||
// Use the generic implementation if multiDrawIndirect is disabled, if line loop is being used
|
||||
// for multiDraw, if drawcount is greater than maxDrawIndirectCount, or if there are streaming
|
||||
// vertex attributes.
|
||||
const bool supportsMultiDrawIndirect =
|
||||
contextVk->getFeatures().supportsMultiDrawIndirect.enabled;
|
||||
const bool isMultiDrawLineLoop = (mode == gl::PrimitiveMode::LineLoop && drawcount > 1);
|
||||
const bool isDrawCountBeyondLimit =
|
||||
(static_cast<uint32_t>(drawcount) >
|
||||
contextVk->getRenderer()->getPhysicalDeviceProperties().limits.maxDrawIndirectCount);
|
||||
const bool isMultiDrawWithStreamingAttribs =
|
||||
(vertexArray->getStreamingVertexAttribsMask().any() && drawcount > 1);
|
||||
|
||||
const bool canMultiDrawIndirectUseCmd = supportsMultiDrawIndirect && !isMultiDrawLineLoop &&
|
||||
!isDrawCountBeyondLimit &&
|
||||
!isMultiDrawWithStreamingAttribs;
|
||||
return canMultiDrawIndirectUseCmd;
|
||||
}
|
||||
|
||||
uint32_t GetCoverageSampleCount(const gl::State &glState, FramebufferVk *drawFramebuffer)
|
||||
{
|
||||
if (!glState.isSampleCoverageEnabled())
|
||||
@@ -2832,6 +2856,61 @@ angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const void *indirect)
|
||||
{
|
||||
return multiDrawArraysIndirectHelper(context, mode, indirect, 1, 0);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
gl::DrawElementsType type,
|
||||
const void *indirect)
|
||||
{
|
||||
return multiDrawElementsIndirectHelper(context, mode, type, indirect, 1, 0);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawArrays(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLint *firsts,
|
||||
const GLsizei *counts,
|
||||
GLsizei drawcount)
|
||||
{
|
||||
return rx::MultiDrawArraysGeneral(this, context, mode, firsts, counts, drawcount);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawArraysInstanced(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLint *firsts,
|
||||
const GLsizei *counts,
|
||||
const GLsizei *instanceCounts,
|
||||
GLsizei drawcount)
|
||||
{
|
||||
return rx::MultiDrawArraysInstancedGeneral(this, context, mode, firsts, counts, instanceCounts,
|
||||
drawcount);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawArraysIndirect(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const void *indirect,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride)
|
||||
{
|
||||
return multiDrawArraysIndirectHelper(context, mode, indirect, drawcount, stride);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawArraysIndirectHelper(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const void *indirect,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride)
|
||||
{
|
||||
if (!rx::CanMultiDrawIndirectUseCmd(this, mVertexArray, mode, drawcount, stride))
|
||||
{
|
||||
return rx::MultiDrawArraysIndirectGeneral(this, context, mode, indirect, drawcount, stride);
|
||||
}
|
||||
|
||||
// Stride must be a multiple of the size of VkDrawIndirectCommand (stride = 0 is invalid when
|
||||
// drawcount > 1).
|
||||
uint32_t vkStride = (stride == 0 && drawcount > 1) ? sizeof(VkDrawIndirectCommand) : stride;
|
||||
|
||||
gl::Buffer *indirectBuffer = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
|
||||
VkDeviceSize indirectBufferOffset = 0;
|
||||
vk::BufferHelper *currentIndirectBuf =
|
||||
@@ -2841,6 +2920,9 @@ angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
|
||||
|
||||
if (mVertexArray->getStreamingVertexAttribsMask().any())
|
||||
{
|
||||
// Handling instanced vertex attributes is not covered for drawcount > 1.
|
||||
ASSERT(drawcount <= 1);
|
||||
|
||||
// We have instanced vertex attributes that need to be emulated for Vulkan.
|
||||
// invalidate any cache and map the buffer so that we can read the indirect data.
|
||||
// Mapping the buffer will cause a flush.
|
||||
@@ -2859,6 +2941,9 @@ angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
|
||||
|
||||
if (mode == gl::PrimitiveMode::LineLoop)
|
||||
{
|
||||
// Line loop only supports handling at most one indirect parameter.
|
||||
ASSERT(drawcount <= 1);
|
||||
|
||||
ASSERT(indirectBuffer);
|
||||
vk::BufferHelper *dstIndirectBuf = nullptr;
|
||||
VkDeviceSize dstIndirectBufOffset = 0;
|
||||
@@ -2868,7 +2953,7 @@ angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
|
||||
&dstIndirectBufOffset));
|
||||
|
||||
mRenderPassCommandBuffer->drawIndexedIndirect(dstIndirectBuf->getBuffer(),
|
||||
dstIndirectBufOffset, 1, 0);
|
||||
dstIndirectBufOffset, drawcount, vkStride);
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
@@ -2876,15 +2961,60 @@ angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
|
||||
currentIndirectBufOffset));
|
||||
|
||||
mRenderPassCommandBuffer->drawIndirect(currentIndirectBuf->getBuffer(),
|
||||
currentIndirectBufOffset, 1, 0);
|
||||
currentIndirectBufOffset, drawcount, vkStride);
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
gl::DrawElementsType type,
|
||||
const void *indirect)
|
||||
angle::Result ContextVk::multiDrawElements(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLsizei *counts,
|
||||
gl::DrawElementsType type,
|
||||
const GLvoid *const *indices,
|
||||
GLsizei drawcount)
|
||||
{
|
||||
return rx::MultiDrawElementsGeneral(this, context, mode, counts, type, indices, drawcount);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawElementsInstanced(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLsizei *counts,
|
||||
gl::DrawElementsType type,
|
||||
const GLvoid *const *indices,
|
||||
const GLsizei *instanceCounts,
|
||||
GLsizei drawcount)
|
||||
{
|
||||
return rx::MultiDrawElementsInstancedGeneral(this, context, mode, counts, type, indices,
|
||||
instanceCounts, drawcount);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawElementsIndirect(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
gl::DrawElementsType type,
|
||||
const void *indirect,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride)
|
||||
{
|
||||
return multiDrawElementsIndirectHelper(context, mode, type, indirect, drawcount, stride);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawElementsIndirectHelper(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
gl::DrawElementsType type,
|
||||
const void *indirect,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride)
|
||||
{
|
||||
if (!rx::CanMultiDrawIndirectUseCmd(this, mVertexArray, mode, drawcount, stride))
|
||||
{
|
||||
return rx::MultiDrawElementsIndirectGeneral(this, context, mode, type, indirect, drawcount,
|
||||
stride);
|
||||
}
|
||||
|
||||
// Stride must be a multiple of the size of VkDrawIndexedIndirectCommand (stride = 0 is invalid
|
||||
// when drawcount > 1).
|
||||
uint32_t vkStride =
|
||||
(stride == 0 && drawcount > 1) ? sizeof(VkDrawIndexedIndirectCommand) : stride;
|
||||
|
||||
gl::Buffer *indirectBuffer = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
|
||||
ASSERT(indirectBuffer);
|
||||
VkDeviceSize indirectBufferOffset = 0;
|
||||
@@ -2895,6 +3025,9 @@ angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
|
||||
|
||||
if (mVertexArray->getStreamingVertexAttribsMask().any())
|
||||
{
|
||||
// Handling instanced vertex attributes is not covered for drawcount > 1.
|
||||
ASSERT(drawcount <= 1);
|
||||
|
||||
// We have instanced vertex attributes that need to be emulated for Vulkan.
|
||||
// invalidate any cache and map the buffer so that we can read the indirect data.
|
||||
// Mapping the buffer will cause a flush.
|
||||
@@ -2932,6 +3065,9 @@ angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
|
||||
|
||||
if (mode == gl::PrimitiveMode::LineLoop)
|
||||
{
|
||||
// Line loop only supports handling at most one indirect parameter.
|
||||
ASSERT(drawcount <= 1);
|
||||
|
||||
vk::BufferHelper *dstIndirectBuf;
|
||||
VkDeviceSize dstIndirectBufOffset;
|
||||
|
||||
@@ -2949,72 +3085,10 @@ angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
|
||||
}
|
||||
|
||||
mRenderPassCommandBuffer->drawIndexedIndirect(currentIndirectBuf->getBuffer(),
|
||||
currentIndirectBufOffset, 1, 0);
|
||||
currentIndirectBufOffset, drawcount, vkStride);
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawArrays(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLint *firsts,
|
||||
const GLsizei *counts,
|
||||
GLsizei drawcount)
|
||||
{
|
||||
return rx::MultiDrawArraysGeneral(this, context, mode, firsts, counts, drawcount);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawArraysInstanced(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLint *firsts,
|
||||
const GLsizei *counts,
|
||||
const GLsizei *instanceCounts,
|
||||
GLsizei drawcount)
|
||||
{
|
||||
return rx::MultiDrawArraysInstancedGeneral(this, context, mode, firsts, counts, instanceCounts,
|
||||
drawcount);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawArraysIndirect(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const void *indirect,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride)
|
||||
{
|
||||
return rx::MultiDrawArraysIndirectGeneral(this, context, mode, indirect, drawcount, stride);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawElements(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLsizei *counts,
|
||||
gl::DrawElementsType type,
|
||||
const GLvoid *const *indices,
|
||||
GLsizei drawcount)
|
||||
{
|
||||
return rx::MultiDrawElementsGeneral(this, context, mode, counts, type, indices, drawcount);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawElementsInstanced(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLsizei *counts,
|
||||
gl::DrawElementsType type,
|
||||
const GLvoid *const *indices,
|
||||
const GLsizei *instanceCounts,
|
||||
GLsizei drawcount)
|
||||
{
|
||||
return rx::MultiDrawElementsInstancedGeneral(this, context, mode, counts, type, indices,
|
||||
instanceCounts, drawcount);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawElementsIndirect(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
gl::DrawElementsType type,
|
||||
const void *indirect,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride)
|
||||
{
|
||||
return rx::MultiDrawElementsIndirectGeneral(this, context, mode, type, indirect, drawcount,
|
||||
stride);
|
||||
}
|
||||
|
||||
angle::Result ContextVk::multiDrawArraysInstancedBaseInstance(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const GLint *firsts,
|
||||
|
||||
@@ -207,6 +207,19 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
|
||||
const GLuint *baseInstances,
|
||||
GLsizei drawcount) override;
|
||||
|
||||
// MultiDrawIndirect helper functions
|
||||
angle::Result multiDrawElementsIndirectHelper(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
gl::DrawElementsType type,
|
||||
const void *indirect,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride);
|
||||
angle::Result multiDrawArraysIndirectHelper(const gl::Context *context,
|
||||
gl::PrimitiveMode mode,
|
||||
const void *indirect,
|
||||
GLsizei drawcount,
|
||||
GLsizei stride);
|
||||
|
||||
// ShareGroup
|
||||
ShareGroupVk *getShareGroupVk() { return mShareGroupVk; }
|
||||
PipelineLayoutCache &getPipelineLayoutCache()
|
||||
|
||||
@@ -1949,6 +1949,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
|
||||
mEnabledFeatures.features.imageCubeArray = getFeatures().supportsImageCubeArray.enabled;
|
||||
// Used to support framebuffers with multiple attachments:
|
||||
mEnabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend;
|
||||
// Used to support multi_draw_indirect
|
||||
mEnabledFeatures.features.multiDrawIndirect = mPhysicalDeviceFeatures.multiDrawIndirect;
|
||||
// Used to support robust buffer access:
|
||||
mEnabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess;
|
||||
// Used to support Anisotropic filtering:
|
||||
@@ -2687,6 +2689,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
|
||||
mCustomBorderColorFeatures.customBorderColors == VK_TRUE &&
|
||||
mCustomBorderColorFeatures.customBorderColorWithoutFormat == VK_TRUE && !isSwiftShader);
|
||||
|
||||
ANGLE_FEATURE_CONDITION(&mFeatures, supportsMultiDrawIndirect,
|
||||
mPhysicalDeviceFeatures.multiDrawIndirect == VK_TRUE);
|
||||
|
||||
ANGLE_FEATURE_CONDITION(&mFeatures, disableFifoPresentMode, IsLinux() && isIntel);
|
||||
|
||||
ANGLE_FEATURE_CONDITION(&mFeatures, bindEmptyForUnusedDescriptorSets,
|
||||
|
||||
@@ -357,7 +357,8 @@ void SecondaryCommandBuffer::executeCommands(PrimaryCommandBuffer *primary)
|
||||
{
|
||||
const DrawIndexedIndirectParams *params =
|
||||
getParamPtr<DrawIndexedIndirectParams>(currentCommand);
|
||||
vkCmdDrawIndexedIndirect(cmdBuffer, params->buffer, params->offset, 1, 0);
|
||||
vkCmdDrawIndexedIndirect(cmdBuffer, params->buffer, params->offset,
|
||||
params->drawCount, params->stride);
|
||||
break;
|
||||
}
|
||||
case CommandID::DrawIndexedInstanced:
|
||||
@@ -389,7 +390,8 @@ void SecondaryCommandBuffer::executeCommands(PrimaryCommandBuffer *primary)
|
||||
{
|
||||
const DrawIndirectParams *params =
|
||||
getParamPtr<DrawIndirectParams>(currentCommand);
|
||||
vkCmdDrawIndirect(cmdBuffer, params->buffer, params->offset, 1, 0);
|
||||
vkCmdDrawIndirect(cmdBuffer, params->buffer, params->offset, params->drawCount,
|
||||
params->stride);
|
||||
break;
|
||||
}
|
||||
case CommandID::DrawInstanced:
|
||||
|
||||
@@ -263,6 +263,8 @@ struct DrawIndexedIndirectParams
|
||||
{
|
||||
VkBuffer buffer;
|
||||
VkDeviceSize offset;
|
||||
uint32_t drawCount;
|
||||
uint32_t stride;
|
||||
};
|
||||
VERIFY_4_BYTE_ALIGNMENT(DrawIndexedIndirectParams)
|
||||
|
||||
@@ -295,6 +297,8 @@ struct DrawIndirectParams
|
||||
{
|
||||
VkBuffer buffer;
|
||||
VkDeviceSize offset;
|
||||
uint32_t drawCount;
|
||||
uint32_t stride;
|
||||
};
|
||||
VERIFY_4_BYTE_ALIGNMENT(DrawIndirectParams)
|
||||
|
||||
@@ -1187,9 +1191,10 @@ ANGLE_INLINE void SecondaryCommandBuffer::drawIndexedIndirect(const Buffer &buff
|
||||
{
|
||||
DrawIndexedIndirectParams *paramStruct =
|
||||
initCommand<DrawIndexedIndirectParams>(CommandID::DrawIndexedIndirect);
|
||||
paramStruct->buffer = buffer.getHandle();
|
||||
paramStruct->offset = offset;
|
||||
ASSERT(drawCount == 1);
|
||||
paramStruct->buffer = buffer.getHandle();
|
||||
paramStruct->offset = offset;
|
||||
paramStruct->drawCount = drawCount;
|
||||
paramStruct->stride = stride;
|
||||
|
||||
mCommandTracker.onDraw();
|
||||
}
|
||||
@@ -1246,10 +1251,8 @@ ANGLE_INLINE void SecondaryCommandBuffer::drawIndirect(const Buffer &buffer,
|
||||
DrawIndirectParams *paramStruct = initCommand<DrawIndirectParams>(CommandID::DrawIndirect);
|
||||
paramStruct->buffer = buffer.getHandle();
|
||||
paramStruct->offset = offset;
|
||||
|
||||
// OpenGL ES doesn't have a way to specify a drawCount or stride, throw assert if something
|
||||
// changes.
|
||||
ASSERT(drawCount == 1);
|
||||
paramStruct->drawCount = drawCount;
|
||||
paramStruct->stride = stride;
|
||||
|
||||
mCommandTracker.onDraw();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user