Conversation
kvark
left a comment
There was a problem hiding this comment.
This looks much detailed, thank you for the proposal!
We'll probably not expose this on Metal for some time, but having the ICB backing it is an interesting concept.
I think, just polyfilling it entirely on base WebGPU takes a similar amount of effort:
- copy the indirect arguments into a temporary buffer
- run a compute shader, which will read the count value from the counts buffer, and then it will zero out the instance count on all of the indirect argument entries (in the temp copies) that are behind the read count value.
- record the
maxDrawCountconsecutivedrawIndirectinvocations, advancing the offset in each, and pointing to the temporary indirect buffer.
Given that it's roughly the same complexity as Metal's ICB workaround, I'm not seeing the latter to be feasible. We might as well polyfill this on all the platforms (that don't support it natively), or not involve any compute-based polyfill at all (leaving Apple platforms behind, and asking users to implement this polyfill on their side).
spec/index.bs
Outdated
|
|
||
| undefined drawIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset); | ||
| undefined drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset); | ||
| undefined drawIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset, |
There was a problem hiding this comment.
Did you consider adding the extra methods (e.g. vkCmdDrawIndirectCount) instead of overloading the existing ones?
There was a problem hiding this comment.
I considered adding multiDrawIndirect and multiDrawIndexedIndirect. No other feature added methods so I was not sure what would be preferred. I can modify the PR if that is what the committee would prefer. I see 3 options:
- Add the
drawCountargument to the existing methods and make new methods withdrawCountBufferanddrawCountOffset. - Put all multi-draw features in a new set of methods,
multiDrawIndirectandmultiDrawIndexedIndirect. - Add both
multiDrawIndirectandmultiDrawIndexedIndirect, andmultiDrawIndirectCountandmultiDrawIndexedIndirectCount.
DX12 does not separate the GPU derived count vs CPU derived count, but Vulkan does.
spec/index.bs
Outdated
| undefined drawIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset); | ||
| undefined drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset); | ||
| undefined drawIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset, | ||
| optional GPUSize32 maxDrawCount = 1, |
There was a problem hiding this comment.
can this number be anything, or do we need an extra limit?
Glancing at gpuinfo, some Android devices report it as 1.
There was a problem hiding this comment.
Yes, I think we would need another limit (but maybe not for Android), maxIndirectDrawCount seems to only be 1 for devices that do not support multiDrawIndirect.
spec/index.bs
Outdated
| - |drawCountBuffer| is `null`, unless the {{GPUFeatureName/"multi-draw-indirect"}} [=feature=] is enabled. | ||
| - |drawCountBuffer| is [$valid to use with$] |this|. | ||
| - |drawCountBuffer|.{{GPUBuffer/[[usage]]}} contains {{GPUBufferUsage/INDIRECT}}. | ||
| - |drawCountOffset| + sizeof([=indirect draw count=]) ≤ |
There was a problem hiding this comment.
Are we taking sizeof of the number here?
There was a problem hiding this comment.
It will always be 32-bit, I could just specify 4 bytes.
|
+1 on this PR being nicely detailed, and the functionality already being polyfillable with compute shaders that copy the draw argument data in a buffer with maxCount drawIndirect (and zero-out unused draws). Because of the compute shader validation that needs to happen I don't think we'll be able to implement this any time soon (that's why during OT Chromium won't have |
On Metal this works because So this brings the question, should:
all be separate features, and let the user zero out The issue with this is it does not fit well with our current model of ask for what you need and either get it or get nothing, because at first a user might ask for all of it. Then fallback on zeroing out |
|
It sounds to me that we can split the |
I will split that off, but what are the thoughts on overloading the existing draws vs adding new ones. |
|
Editors chatted and we think the multidraw calls are too different in shape and functionality - so preference for using a different name instead of overloading with optional arguments. |
We talked about it some more with the editors, and we think it would really help to know how much the |
On Vulkan |
just to confirm, are we sure that the set of hardware is different by a small margin, or is it just the total percent/number that is different? |
|
|
Why are we considering adding a new feature ostensibly for performance without any performance data? WebGL and WebGPU have very different CPU overhead characteristics. We can't use the existence of this extension in WebGL as motivation for it in WebGPU. |
I just did some benchmarking using Vulkan. I have primarily been an OpenGL user and thus my assumption on the performance increase was wrong, I had expected at least an order of magnitude based on my OpenGL experience. By reusing the command buffer and using non-zero Next I simulated culling out 20,000 of those calls on the GPU and did the culling by setting Therefore, in cases where pipelines and bind groups are consistent between frames (so render bundles can be used) and the number of draws is fairly consistent, a user could polyfill using I do not know what the performance loss would be with dynamic uniform/storage offset changes between indirect draws in the render bundle (which would be required without |
|
Now that |
This extension doesn't exist in WebGL, which doesn't have indirect draws at all. WebGL has non-indirect multi-draw as an extension. However the presence of this feature in Vulkan is some evidence of its value. |
This makes sense, though if we find that it's unnecessary to expose them separately, we could give it a more generic name like "draw-indirect2" or something. |
The Metal Feature Set Tables indicates that support on Mac is limited to |
|
Resolution:
|
Just realized this was a confusing snip. From context, it's clear that "versions which are still maintained" was referring to OS releases, not hardware. The hardware requirement may have been overlooked. |
Corrected in PR comment, was unfamiliar with how Apple lists capabilities. Metal docs only list OS version. |
|
Resolution: accepted, merge after #2022 has landed and this is rebased over it. |
|
superseded by #2315 |
Indirect drawing with multiple indirect drawing commands is a common technique for drawing complex scenes that would otherwise be infeasible due to either an excessive number of CPU issued draw calls or scene complexity that cannot be built by the CPU alone. This is done by:
This PR addresses adding a
multi-draw-indirectfeature. In particular it addresses adding:multiDrawIndirectandmultiDrawIndexedIndirectmethods onGPURenderEncoderBase.firstInstancefordrawIndirect,drawIndexedIndirect,multiDrawIndirect, andmultiDrawIndexedIndirect.Compatibility
The required backend features to implement
multi-draw-indirectare available on:See the sections below for details.
Vulkan
Multi-Draw
Requires the 0 or 1 restriction on the
drawCountargument ofvkCmdDrawIndirectandvkCmdDrawIndexIndirectto be relaxed to any non-negative integer. This requires themultiDrawIndirectfeature which is supported on:NOTE: The
strideargument will always be set for tight packing, in order to maintain compatibility with DX12.Draw Count
Requires the
vkCmdDrawIndirectCountandvkCmdDrawIndexedIndirectCountfunctions which are provided by either thedrawIndirectCountfeature of Vulkan 1.2 or one of the following extensions:VK_AMD_draw_indirect_countVK_KHR_draw_indirect_countBecause
drawIndirectCountwas introduced in driver updates the statistics at https://vulkan.gpuinfo.org cannot be relied upon. The following is based on the oldest card that supportsdrawIndirectCountfrom each manufacturer, if newer cards dropped support fordrawIndirectCountthat is not captured here.drawIndirectCount.drawIndirectCount.drawIndirectCount.For Android:
drawIndirectCountis supported on 100% of devices that support Vulkan 1.2.drawIndirectCountis supported, as an extension, on 28% of devices that do not support Vulkan 1.2.Non-zero
firstInstanceRequires the
firstInstanceproperty of theVkDrawIndirectCommandandVkDrawIndexedIndirectCommandto be non-zero. This requires thedrawIndirectFirstInstancefeature which is supported on:DX12
All required features are core to DX12.
Multi-Draw
Uses
ExecuteIndirectwhere theMaxCommandCountargument is greater than 1 and thepArgumentBufferargument points to a GPU buffer containing an array ofD3D12_DRAW_ARGUMENTSorD3D12_DRAW_INDEXED_ARGUMENTS.NOTE: The binary layout of these structs are compatible with Vulkan.
Draw Count
Uses
ExecuteIndirectwhere thepCountBufferargument is not NULL.Non-zero
firstInstanceThis is the
StartInstanceLocationof theD3D12_DRAW_ARGUMENTSorD3D12_DRAW_INDEXED_ARGUMENTSstructures. Has native support for values greater than 0.Metal
Multi-Draw
Can be emulated with Indirect Command Buffers (ICBs) and an extra compute shader invocation to translate from the Vulkan-like indirect draw buffer to an ICB.
Requires
Non-zero
firstInstanceNatively supported with the
baseInstanceargument.Draw Count
Don't record commands past this count in the ICB and use
optimizedIndirectCommandBuffer.Requires
Preview | Diff