I’ve followed the most popular vulkan tutorial , finished it, and am currently learning to do less cargo cult and more understanding of what I am doing. Building off the tutorial, I am currently trying to merge the rendering results of three rendering pipelines into a single image.
What I expect are fragments generated by each pipeline to be depth-tested against each other and presented to the screen. No alpha blending or anything.
What I do:
- Get an image from the swap chain
- Get a free command buffer for each pipeline from the same pool.
- Record, single threadedly, commands for each buffer.
- Get all the recorded buffers, submit them to the queue.
- Present results.
If I do this for each pipeline separately, it works. Although I need to set the loadOp in color attachment for this pipeline to
VK_ATTACHMENT_LOAD_OP_CLEAR, otherwise I get a hall of mirrors effect. Once set, I get no z-fighting, nice image, everything seems fine.
If I try to get the merged results… things happen.
If I omit
VK_ATTACHMENT_LOAD_OP_CLEAR for every pipeline, all things are drawn, but a massive hall of mirrors effect ensues. Seems like depth testing between the pipelines is not done.
If I enable “blending” of results, hall of mirrors is gone, but, obviously, all fragments blend on each other. There is also a lot of flickering.
Combinations of all of these don’t solve my issue.
I’ve been at it for the last three days. Reading tutorials, articles and specification. I don’t have a faintest idea what to do next.
My questions, if anyone would like to throw some aid
If an attachment has its load/store operations set to anything substantial - does this happen per fragment or image? For example - If I make 100x100 render window and produce one pixel, with the rest untouched - will the attachment load just for that one fragment? This seems to happen per image, but I might be missing something.
What happens in my example looks like some sort of a race condition between each pipeline as they read/write to their color/depth/resolve attachments. All of them have the same three images bound - respectively.
Does it mean I need to add a barrier/fence somewhere to synchronize between each pipeline?
Pipeline barriers seem to be per command buffer. I didn’t find any
vkCmdSemaphore to share a semaphore between several pipelines. Should I just submit a single command buffer? I tried different combinations of buffers / submits but to no avail. So I guess - how to synchronize between several pipelines if they were submitted all at once?
- Alternatively - should I just bind different images to attachments of each pipeline and then ‘manually’ merge their results? This seems weird, but considering how expressive Vulkan is, I would not surprise me.
On unrelated note.
vkQueueSubmit, well, submits commands to the GPU driver and they can be asynchronously executed from that point - right/wrong?
vkQueuePresentKHR waits (?) until those commands are executed. Gets the image to the screen and signals the attached semaphore? Or does it just assume that we are done with executing commands and are going to do other things?
I guess - what I am asking is if I do a tight loop like this:
for( int x = 0; x < 10; ++x )
Will I get x frames rendered, or will only from the last ‘present’ - or is it an undefined behavior of some sort to call for a present without waiting for the semaphores passed to
Anyhow - I appreciate any help. I knew that Vulkan is vast. But I’ve been at it for the last two months and it’s been a humbling experience. I’ve been code monkeying for money for the last 18 years…