Context:
https://dawn-review.googlesource.com/c/dawn/+/18120/3/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp#294
cc @Richard-Yunchao
Thanks Kai for raising this issue. @kainino0x .
Recently, I am working on resource (say buffer and texture) usage tracking. Definitely there is a resource usage tracking rule: it is allowed to have multiple readable usage (like vertex buffer, index buffer, uniform buffer, readonly storage buffer) upon the same buffer, but it is not allowed to have readable and writable usage or multiple writable usages within one pass upon the same buffer. Texture usage tracking follows the similar rule as buffer.
Below are a few ways to use a resource in render/compute pass:
However, when I inspect these method to trace resource usage, I found two corner cases which might be not very clear:
1) overwritten cases: For example, within one draw/dispatch, we call multiple SetBindGroup on the same bind group index, multiple SetVertexBuffer on the same index, or multiple SetIndexBuffer. The latter call will definitely overwrite the previous one. So the former calls are not useful at all. So, we can either disallow this usage (and resource usage tracking is not necessary at all), or allow this usage then trace or not trace the resource usage.
2) unused bindings for a particular render/compute pass. For example, we can set visibility 0 or COMPUTE stage bindings in a bind group, but use that bind group in the render pass. Then such bindings are useless in this render pass. We can either disallow this usage, or allow this usage but trace the unused resource or not.
Some thoughts and discussions about these two corner cases:
Regarding overwritten cases, we may allow overwritten cases for resource binding and trace the resource usage and report error if resources' usage break the read/write usage rule. Because the check will be done during during app development. It is not during app runtime.
For unused bindings, I don't know whether this situation is useful: use a resource as writable in compute pass, and read it in a render pass. Then we can set these two bindings in one single bind group, and bind it for both compute and render pass. If we disallow unused bindings, or allow unused bindings and trace the usage, it will make this invalid. We can definitely create two bind groups and bind the one we need for compute and render pass respectively. So it is not a problem except that it can save one bind group. So I'd like to know your thoughts.
Let me make this issue title more general.
Like we discussed during the review of Dawn tests and issues, WebGPU shouldn't optimize for applications that set resources redundantly so all calls to setVertexBuffer/IndexBuffer/BindGroup should count the resources towards the render pass usage. The rules for compute passes might be slightly different because each dispatch is its own synchronization scope.
For unused bindings, it would be very expensive to check the bindings actually used by the pipeline when draw/dispatch is called. So I think we should track usage of all resources in the bindgroup but don't have an opinion on whether we should use the visibility to filter the resources or not.