Limitation on Vulkan subpass amount

Hi everyone! I’m investigating about the Vulkan Subpass feature and I found there’s little discussion about how many subpasses is allowed / recommended in a single render pass.
I wonder if there’s any limitation on the the amount of subpasses. Am I allowed to have 10, 20 subpasses in one render pass? Can I still benefit from the subpass feature with that many subpasses? Is the limitation decided by the device/drive version? And what kind of impact on performance it will result to if there are too many subpasses? Thanks!

There are no limitations on the number of subpasses. There are limitations on the number of attachments a render pass can be given at the start. The only reason to switch subpasses is to use a new set of these attachments. For a given N attachments, there are only so many possible sets of attachments you could use. And while you might use the same set multiple times (to render something in the middle), the reality is that there is little practical utility for this sort of thing.

There’s also the fact that the limitations of the use of attachments within a render pass inevitably make long sequences of subpasses non-functional. Like, one might consider putting the generation of shadow maps in the same render pass as the process consuming them. But that’s not possible. Images attached to a render pass cannot be accessed like normal textures from a shader during that render pass, and shadow mapping requires accessing them arbitrarily. So if you want to render a shadow map, it must be in a separate render pass from the process that consumes it.

As for the question of the performance impact of subpasses, this is again not so much about subpasses but about attachments. In a tile-based renderer, the goal is to not have to write tiles out to main memory, to perform as much of the rendering operation as possible within a tile.

But each attachment being used in a subpass will be allocated some portion of tile memory. The more distinct attachments that a sequence of subpasses have to use/preserve, the less likely it is that the renderer can render that sequence without writing stuff to memory.

Overall, I feel like these questions are kind of missing the point. Why are you even thinking of having so many subpasses? Like, what are you trying to do with all that?

Thank you for the reply! If there’s no limitation on the number of subpasses, will there be any loss cost by the transition between subpasses?

In my case, I’m trying to port a immediate renderer to a tile based renderer. The reason I’m asking this question is that the original immediate rendering pipeline change the order of render target a lot, and these shaders were designed for that. But changing the render targets’ order is not allowed during a subpass as far as I know, so my idea is:

  1. Adding new subpasses when changing the render targets’ order.
  2. Or changing the shaders’ code to fit the order and decrease the amount of subpasses.

Right now I’m not sure which solution is better and I choosed the first one, but then I realized that there can be some potential performance loss for this first solution.

What do you mean by “order of render target?” Are you talking about the output indices of the fragment shader outputs?

Yes, there are a series of shaders writing their output to SV_Target0.

It would be much better if you changed the shader code to specify what output they’re going to. You were probably losing performance by switching around the draw buffers order.

1 Like