-
Notifications
You must be signed in to change notification settings - Fork 312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DrawIndirectCount #1354
Comments
Of note, our current drawIndirect/drawIndexedIndirect can only do one draw call - we don't even have a drawCount parameter like Vulkan's vkCmdDrawIndirect. This is because of the multiDrawIndirect feature which is available on many but not all Android devices.
Also note the drawIndirectCount feature is optional in Vulkan, and
I think we would be interested in adding optional support for both multiDrawIndirect and drawIndirectCount, but since they're optional this will be post-1.0. |
Yep, it would be great to have that extension in the future. |
True! I think we can even poly-fill this everywhere. We could schedule a compute operation to happen before the render pass that would fill out a temporary GPU indirect buffer. I.e. we'd copy over the indirect data for Anyway, I don't think it's worth pursuing at this point, we better focus on MVP essentials instead. |
I agree that it looks like not very important extensions. But with can make super awesome WebGPU showcases with it. CPU emulation will not work when the number of draw calls is getting more than several thousand. The driver will do the job better. Or we will wait for better times :) |
Just a small note, that I actually found it on 11% of Android devices according to this search: |
Ah, didn't realize it was previously an extension (still getting used to the new refactored vulkan.gpuinfo.org that splits by vulkan version).
I must have meant "not required"? |
So iOS on 6S and above has a full implementation of indirect draw, but the 63% Android score means it's limited to 1 draw call in WebGPU 1.0? This is a call that one would only use when it's supported, and fallback to explicit draws if not. Only having 1 draw is a reason not to use this at all. In the iOS9 api, also seems like iOS is missing a drawCount in the draw call where Vulkan has one. This means that the drawIndexedPrimitive and offset into the buffer must be called for each indirect draw. This kind of defeat the purpose of reducing draws, but at least allows Vulkan to benefit while Metal can catch up later. |
Hello, I'm asking about that particular extension because compute shaders are useless without the ability to draw the result. Or everything will be limited by a single draw call which is only suitable for simple things like terrain or grass. This is okay for CPU-driven technologies. But compute shaders allows moving everything on compute level. And boosting performance and power efficiency as a result. This is a link to our benchmark: https://gravitymark.com/ And I think that it must work on WebGPU. Otherwise, I don't know why the WebGPU project was initiated. We don't need much from the functionality level. The engine is perfectly working on OpenGLES 3.1 feature set level. And WebGPU should be at least equal to OpenGLES. Moreover, OpenGLES is an outdated API for everybody. We have full WebGPU and WGSL support. And there is a minimal list of features which is stopping us from running our engine on WebGPU:
It is possible to workaround multi_draw_indirect_count on platforms where it's not supported by additional synchronization and loop of draw indirect command inside. And sometimes, it's working even faster than the driver. Guys, you already did tremendous work with WebGPU. Please don't stop with it :) |
AFAIK, in order to achieve compute-driven multidraw right now, you need to issue one indirect draw call for each possible draw call you want to do, then use a compute shader to generate up-to that many draw calls, zeroing out the ones you don't need. This isn't amazing, but it still might be able to achieve good performance, at least if you have a reasonable bound on the maximum number of draw calls. Unfortunately I don't know the characteristics of this technique on different architectures. Most likely we'll later have optional features for all of those things you listed, but unlikely before MVP so we can focus on the core. |
I have to 2nd the need for |
It's doable to emulate MDI with Metal. It's working much faster with Apple GPU. But all AMD GPUs are losing a lot of performance with it. Because the driver will do a redundant job of converting draw calls back to MDI format: https://tellusim.com/metal-mdi/ |
If we do emulation like that we could enable it on Apple GPUs but not on AMD GPUs if it doesn't perform well! 👀 |
@kainino0x The GPU Info DB shows percentages based on reported device support, but this percentage isn't usable as a proxy for real world device market share. Was there any analysis done on an estimate of actual devices in the wild that don't support |
@jeremyong We don't use the percentages on gpuinfo.org to understand market share; instead, we use it as a rough estimate (i.e. is it very close to 0% or 100%?). To actually figure out what actual devices we would lose by requiring a feature we have to dig deeper - see #1069 (comment). In this case the claim I made was incorrect because I looked only at the core 1.2 feature |
The reports on gpuinfo.org are mostly taken from Linux driver installs that are often homegrown. They don't seem to reflect many of the better drivers on Windows that are way more prevalant installs of Vulkan. Android reports are more reflective of that platform. So I wouldn't rely on percentages there as a in-use percentage like the Steam charts. Apple A9 has ICB with the ability to draw a range from CPU, and A11 can generate the range and count from the GPU, and repack missing elements in the array that is output via that blit encoder. Mali doesn't have multiDrawIndirect, but Adreno does. But even then, one needs the VK_EXT_descriptor_indexing extension to switch the descriptorSet within the drawIndirect calls for varied materials. Also Mali and Adreno are missing VK_conditional_rendering extension to skip instances, but that stinks for multiDrawIndirect. Can use VTF to vertkill all the verts if a visibility buffer reports that a shape is occluded. |
This CL adds unimplemented stub tests for the `transpose` builtin. Issue: gpuweb#1246
I think there is a potential for a performance regression compared to WebGL for renderers using https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_multi_draw if this is not included. |
Just tried to use EDIT: I think I'm hitting a chrome bug with this when trying to call |
Recording integers to an array is much faster than making a draw call. Allowing web workers (or even later -- compute) to fill in these parameters to a shared array opens up many optimization opportunities and possibly power efficiency gains. I strongly favor seeing a count parameter added to drawIndirect, even if for now the count value must be supplied at call time and not found in some other buffer (say, GPU local). Otherwise, as is, this functionality is no better than supplying the parameters directly, and possibly worse. I see this is being explored in even richer territory (multidrawindirect) here: #2315 which I find promising! |
Is there any news on this feature? Even behind a feature flag at device creation time, it would be valuable to support this. For many domains, ie large game worlds or CAD applications, it makes no sense to play them on mobile or older hardware anyways; the target audience already has support for it, but right now it's hidden away from wgpu while available everywhere else. |
Still not implemented ? Even as an extension, it really is a must have and is the main reason we would use WebGPU instead of WebGL |
we need at least MultiDrawIndirect for GPU-driven rendering. |
I totally agree, MultiDrawIndirect + Bindless textures are a must have if we want WebGPU to perform as well as a desktop app on scene with a large amount of meshes (e.g. CAD data) |
We need this feature in the AEC (Architecture Engineering and Construction) industry to enable rendering of medium to large-size architectural models (aka BIM for Building Information Models) on browsers. Right now, only small models can be rendered with reasonable FPS. |
Bindless textures can be emulated with array textures, but MD / MDI can't |
We clearly need to reevaluate the priority here so moving to M1 for us to at least re-triage. |
Oops, just realized I had a duplicated bug in #4349. Let me move this here: Originally posted by @mrshannon in #1949
|
See #4349 for gpuinfo-vulkan-query results and Nov 2023 meeting minutes also. |
Just to be clear MDI isn't universal. It's available on Vulkan desktop and that's it. On Android, Mali Vulkan is limited to 1 draw from the buffer per draw call. And much of the older Android vulkan hw. And on Metal, it's the same. For some reason, Apple decided to hobble the MDI API on A9 and encourage use of a different more complex API that has range support, but is far more challenging to encode on the gpu. That encoding support didn't happen until A11. There's almost no universal support for the indirect count that is also needed. I still think there's value in MDI + count 1 though. Since the content is in a buffer, the GPU can generate it, and can zero or mod the instance count in the MDI buffer structs. But it means that the cpu has to specify a higher count, and then draw zero count MDI structs. Then A13 is needed for descriptor indexing for material indirection. This is way simpler to use than Apple's current indirect draw arguments. |
There's two concerns at play. The user API and the underlying implementation. For a user to specify an array of draw parameters is from an application design perspective already a win towards future proofing if the underlying implementation has to run under emulation, and it's probably no worse in that case than the user doing essentially the same work of issuing a draw per array item in a loop anyway. The question seems to be related to performance expectations (non-emulated vs accelerated). But again, for hardware that doesn't natively accelerate MDI would be fed draw calls via a loop of some kind, whether from a user application or the graphics library. So offering the API generally seems like a net win to me all around. |
Behind a feature flag passed at device creation time, this would be perfect. If it's there, use it, if not fallback to single draws in a loop. I think it's more valuable to offer advanced APIs as optional features, than not offering them at all. |
There is no emulation of a GPU driven count with MDI. There is the fixed count from the cpu, and the potential for a dynamic count from the GPU. |
The implementation could issue a hard gpu -> cpu sync in that case but I think most (including myself) would prefer an error instead. Presumably there could be MultiDrawCount and MultiDrawIndirectCount, where the latter is restricted behind a feature flag. |
Actually, you can use a compute shader to emulate this fairly easily by zeroing out the |
Worth pointing out that for many years (I'm not familiar with the current state of the codebase), |
That doesn't work. This isn't cpu driven. The MDI data must reside in a buffer, then compute or vertex shader can modify the values, and then the draw needs to increment 1 buffer slot on iOS/Mali/older Android to the cpu count, or by multidraw indirect set by the gpu into a buffer. The idea of offering two apis with multidraw count indirect optional is probably best. iOS and older Android just wouldn't offer that, but there are Apple devs on this thread. Also the iOS MDI API can't have additional data (no stride), but Vulkan can. |
dispatchCount and indirectCount aren't always easy to emulate, or possible. There's a hack I'm using by doing a mod/div over the instanceIndex or globalInvocationId, but when the counts differ from batch to batch it's no longer possible. For example, doing GPU culling means a series of indirect draws each using a different instanceCount and startInstance for each draw. Doing a naive loop over drawIndirect on the CPU right now, but also issuing 1500 draw calls instead of 1, most of which are zero'd out. It's 1ms of javascript time being wasted. Having optional support behind a feature flag means users whose hardware support it can handle exponentially larger scenes, while those without support also see reduced simulation limits but can still run it. I think the need for all target hardware to support a given feature is a downgrade, because it forces high-end machines to the level of the lowest common denominator. More feature flags makes webgpu also more attractive to developers with higher-end hardware in mind. |
I want to note that On top of that, it also has the |
Oh it has push constants too, nice. Let's get these on the web too :) |
With web you get LCD. Push constants are problematic in other ways. Some support fp16 and some don't (AMD). Maybe WebGPU doesn't even offer fp16 support. |
I don't need f16 push constants. If I can write u32 push constants, then I can encode/decode anything I need. |
GPU Web WG 2024-03-27
|
I'm on the way to support webgpu on God bless whoever implements this! |
Hello,
It would be awesome if the drawIndirectCount functionality will be available in WebGPU.
DrawIndirect functionality is already available, and it's excellent, but DrawIndirectCount allows to render more advanced things.
DrawIndirectCount is available under almost all platforms now: Vulkan, OpenGL, Direct3D12, Direct3D11 with AMD AGS.
Metal API has an Argument buffer extension, which should be able to emulate such functionality.
Thank you!
void vkCmdDrawIndirectCount( VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
void vkCmdDrawIndexedIndirectCount( VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
The text was updated successfully, but these errors were encountered: