4

I am currently learning vulkan and came across above question that I can't seem to answer by reading the spec.

When looking at the spec and code samples, it's always the same simplified workflow:

begin commandbuffer 
    begin renderpass
        bind stuff (pipeline, buffers, descriptor sets)
        draw
    end renderpass
end commandbuffer

create_submit_info
submit_to_graphics_queue

Now the first thing that's a little unclear to me is when to clear the attachments. If I create my attachments with LOAD_OP_CLEAR then I have to supply clear values for VkRenderPassBeginInfo, but every command buffer contains a vkBeginRenderpass. So does that mean that every submitted command buffer starts a new renderpass and so clears the attachments? That does not sound right.

If I specify LOAD_OP_DONT_CARE then I have to use vkCmdClear which kind of asks for a seperate command buffer just for clearing the attachments. Which can't be right either.

So can someone please clearify the relation between command buffers and render passes for me?

Or is it a misunderstanding of vkCmdBeginRenderPass? Does it not actually begin a new render pass when there is one running already?!

Thank you for helping.

C. Göbeler
  • 65
  • 1
  • 8

2 Answers2

5

Command buffers are responsible for storing commands that later get submitted to queue(s) and processed by the hardware. It is the only way to perform operations in Vulkan - record them and then submit. But the important thing is that each command buffer is totally independent from all other command buffers. If You want to perform a specific job, You need to record all the necessary commands that set appropriate state into the command buffer. If You want to perform similar job in another command buffer, You need to record the same set of commands in this other command buffer because there is no state sharing between command buffers. They are all independent. (There are some exceptions but they are not relevant for this discussion as they involve only secondary command buffers).

Next, in Vulkan rendering can only occur inside render passes. Render pass is a general definition of steps (called subpasses) drawing commands are divided into and of rendering resources (and relationships between them) needed for these drawing commands (attachments). But this is just description, metadata. You define how these attachments are used (as color attachments, as depth attachment, as input attachments) and what are their layouts in each subpass. You also define what to do with each attachment before the render pass (load op) and after the render pass (store op).

Now the actual resources used for these attachments are defined through framebuffers. This way You can perform similar rendering operations on various sets of images (by using various but compatible framebuffers) without the need to recreate render passes. And which framebuffer should be used during rendering is defined when You start a render pass.

Now when we combine the above information, render pass and command buffer, we get this: each command buffer is independent, so rendering must start and end during a single command buffer (excluding secondary command buffers). So that also means that You need to start and end a render pass within a single command buffer (but of course You can also start and end multiple render passes in a single command buffer).

So does that mean that every submitted command buffer starts a new renderpass and so clears the attachments?

If You want a command buffer that only performs math calculations by executing compute shaders, then You don't need render passes. So such command buffer doesn't need to start and end any render pass and it doesn't need to clear any attachments. But if You want to render in a command buffer, then yes, each such command buffer must start (and end) a render pass. If rendering involves clearing, then each command buffer that needs to perform such operation will also need to clear attachments.

Or is it a misunderstanding of vkCmdBeginRenderPass? Does it not actually begin a new render pass when there is one running already?!

vkCmdBeginRenderPass() starts a new render pass, yes, but in a single command buffer You cannot start another render pass until previous render pass is ended. You must explicitly start a render pass and end it. Only after that You can start another render pass (in the same command buffer).

As for clears, they are also defined during beginning of a render pass, which allows You to clear attachments with different colors. This way You don't have to create a separate render pass every time You want to change "background" color.

And one more thing about attachment clearing: unless really necessary, use render pass clears (LOAD_OP_CLEAR) instead of explicit clears (vkCmdClear()) as they may hurt performance (render pass clears are recommended by most of the vendors as far as I know).

I hope this hope clarifies this topic.

Ekzuzy
  • 3,193
  • 1
  • 16
  • 14
  • It does clearify things a little, what I dont understand is how I would ever be able to submit a second command buffer for a frame without having its internal renderpass clear the color attachment and basically clearing/deleting whatever has been rendered by the previous command buffer. – C. Göbeler Jan 30 '18 at 14:32
  • By recording multiple render passes in a single command buffer (first will clear resources, other won't or will clear only some of them). Or by creating another render pass that doesn't clear attachments at all and by providing appropriate framebuffers for each of them. Or by creating render passes that operate on different sets of images - in first command buffer You clear attachments and render into them; in following command buffers You read from attachments from previous command buffer and use other images as attachments (so they can also be cleared). – Ekzuzy Jan 30 '18 at 14:39
  • "so rendering must start and end during a single command buffer (excluding secondary command buffers)" that was the key to my problem. I was expecting to be able to record command buffers for individual parts of my scene and submit them if necessary (visible after culling) and came across the clearing problem. so instead I have to rebuild one large commandbuffer anytime something changes? Or use secondary buffers. – C. Göbeler Jan 30 '18 at 14:41
  • I didn't use secondary command buffers too much. But as far as I remember - secondary command buffers (may!) inherit render pass state (when You provide it). This means that a secondary command buffer "knows" in which subpass of the primary command buffer it is executed from (so You don't have to start a render pass in it). But if You want to divide rendering of Your scene into multiple command buffers, then yes - in general You need to start and end a render pass in each of them. So You may need one command buffer that clears attachments and others that don't do that. – Ekzuzy Jan 30 '18 at 14:46
0

To answer your questions: Normaly you clear when the frame begins, before you render something. beginRenderpass can only be called by the primary commandbuffer, secondary commandbuffer must not invoke this call. Basically you are starting a renderpass instance in the primary commandbuffer(only commandbuffer that you can submit to the queue), This is what you will be doing on each frame.

but you can clear one or more regions of color and depth/stencil attachments inside a render pass instance, by calling vkCmdClearAttachments regardless whether it is LOAD_OP_CLEAR / LOAD_OP_DONT_CARE, or if you want to do it out side the renderpass you use vkCmdClearColor/DepthStencilImage. this can be called by either the primary command buffer or secondary commandbuffer.

Tip: using LOAD_OP_DONT_CARE may optimized on some drivers, if you are sure that you will overwrite the entire the screen written by the previous frame. so the drivers don't have to load/copy the memory from the presenation buffer for the current renderpass to clear it.

you can use vkCmdClearAttachment command in the secondary comandbuffer to clear any attachment. But you cannot submit them by itself, it has to be put inside the primary commandbuffer.

So does that mean that every submitted command buffer starts a new renderpass and so clears the attachments? is it a misunderstanding of vkCmdBeginRenderPass? yes every submit commandbuffer starts the renderpass and clear the fbo attachments.

Does it not actually begin a new render pass when there is one running already? Renderpass contains the executation order of the framebuffer. it has states. the states are reused on each frame. you can use another renderpass (different state) with the same fbo. so the first renderpass can clear it and the second renderpass don't clear at the beginning of the frame.

you cannot call another renderpass inside renderpass instance. what you see below is invalid

Commandbuffer.beginRenderpass(renderpass1, fbo, ClearValues);
Commandbuffer.beginRenderpass(renderpass2, fbo, ClearValues);// ERROR 
Commandbuffer.end;

you have to end the renderpass1 instance before you begin the second renderpass. should be like this

Commandbuffer.beginRenderpass(renderpass1, fbo, ClearValues);
// draw scene
Commandbuffer.end;// renderpass is ended 

Commandbuffer.beginRenderpass(renderpass2, fbo, ClearValues);
// draw full screen quad
Commandbuffer.end;

Commandbuffer.beginRenderpass(renderpass3, fbo, ClearValues); 
// draw full screen quad
Commandbuffer.end;

let say that in the above example the fbo has 3 attachment. we are using 3 renderpass here. First: Render the scene in to the attachment 1 using the renderpass1. Second: Read from the attachment 1 and do a Vertical Blur and write into attachment 2 using renderpass2. third: Read from the attachment 2 and do a Horinzontal blur and write in to the swapchain image using renderpass3. (Note: for this particular techniqueue we cannnot use multiple subpass thats why I'm using 3 renderpasses for the same fbo.)

Senthuran
  • 41
  • 4