Results 1 to 8 of 8

Thread: FrameBuffer attachments clarification

  1. #1

    FrameBuffer attachments clarification

    I use two swapchain images, two command buffer, two framebuffers etc.
    I allow for up to two frames to be in flight at a time.

    If I want to attach a depth buffer, do I need a unique one per framebuffer since in theory the previous one could still be in use while rendering the new one?

    I found it hard to locate proper information or examples for this.

    Most example code don't allow multiple frames to be 'inflight' and the code I seen sometimes share the depth buffer, so its hard to know if its valid.

    I assume once the above has been answered it will be equal for other attachments as well, so if I attach another color buffer it will also need to be duplicated if the depth buffer has to be.

    Can someone please clarify the exact requirements here?

    My initial gut feeling is that like everything else that might still be in use you would have to duplicate things.

  2. #2
    Some research I already did:
    - VkQuake seems to be sharing the depth buffer between inflight frames and also other attachments.
    - vulkan-tutorial.com seems to be sharing the depth buffer.
    - misc other samples seems to be duplicating it.

    If attachments can be shared without explicit synchronization then why is that the case?

  3. #3
    in theory the previous one could still be in use while rendering the new one?
    And how exactly would that happen?

    The reason you need multiple presentable images is because one (or more) of them is in the process of being presented. During that time (which could take a while), you still want the GPU to be doing stuff. Since it can't "do stuff" to the image that's being presented, it would have to "do stuff" to some other image.

    But you're not presenting your depth buffer, are you? None of the above applies.

    The only overlap that could happen is if there were no synchronization between frames. That is, if you don't prevent the rendering of frame 2 while frame 1 is still being rendered. However, you usually do have such synchronization; after all, you can't present an image unless you synchronize the presentation command with the queue operation that renders to it. So if the pipeline has already stalled, adding an extra bit of synchronization isn't going to hurt.

  4. #4
    As I said I am trying to understand this issue as tutorials are unclear and conflicting in how they handle it. Most actually completely ignore the issue by their choice of per frame synchronization.
    So for a new person learning he API he might not actually remember all of the Vulkan spec details or know exactly how the synchronizations occur inside of Vulkan.

    Take something as simple as were to put the fence while drawing:

    The vulkan-tutorial.com at https://vulkan-tutorial.com/Drawing_...ames_in_flight
    Puts it just before the new frame is started and right before vkAcquireNextImageKHR.

    Others put the fence just before they start using the command buffer again, which seems to have the same effect as vulkan-tutorial. (https://developer.samsung.com/game/usage)

    However, the lunar examples at https://vulkan.lunarg.com/doc/sdk/1....draw_cube.html
    Puts it before vkQueuePresentKHR and it implies that you need to wait for the command buffer before doing a vkQueuePresentKHR.

    To my current understanding all of these will work, but "lunars" will be less efficient and its reason for waiting at the chosen point is wrong.
    Is that true? (if so its kind of bad that such a high-profile example is wrong).


    Now back to my original question and the answer above

    If I only have two, I might see your point for my given example.
    But what about if I had three or more buffers and allowed for the same number to be 'inflight' (this code was meant to be scalable from 1-x frames in flight).
    Frame 1 would be presented on screen, frame 2 renders and is queued via vkQueuePresentKHR (as far as I understand the queue does not necessarily present right away, it's kind of in the name), frame 3 starts to render

    I am really trying to understand which call prevents the depth buffer from frame 2 from being overwritten when frame 3 starts (given the queued present of 2 has not been executed yet).

    To provide more context I am using code similar to: https://vulkan-tutorial.com/Drawing_...ames_in_flight
    This should clear up exactly how the app code I use do synchronization (it could be doing it wrong, I am open to that)

    I might have misunderstood something which is why I asked for clarification and multiple people do seem to be confused about it.


    I also read The Most Common Vulkan Mistakes" and he mentions "Command queues run independently of each other.".
    So, given my synchronization scheme in the app and the above example.

    The result of command buffer 1 is being presented, command buffer 2 has been filled and queued.
    Command buffer 3 is being filled and then queued.

    Since command buffer 2+3 run independently of each other what would prevent both of them from drawing to the depth buffer at the same time if sharing a depth buffer.

    Vulkan tutorial also duplicates its UBO's for the inflight frames which is what I would expect to be necessary as there are multiple queues possible rendering at the same time.
    Again, this leads me back to the original question if a depth buffer can be shared safely why can't the UBO's.

    Leading me to conclude I am missing something, hence the need for clarification.
    Last edited by VulkanBuilder; 11-08-2018 at 06:57 AM.

  5. #5
    Doh I just realized he wrote "command queues" not "command buffers" in common Vulkan mistakes.
    Next he writes "When submitted to queue A, command buffers execute in the specified order".

    So I guess that is the reason why a depth buffer can be shared, since command buffer 1 will be completed before command buffer 2 can start executing!
    As long as its on the same command queue.

    Which again would imply only 'things' shared with the CPU needs to be duplicated.

  6. #6
    frame 2 renders and is queued via vkQueuePresentKHR (as far as I understand the queue does not necessarily present right away, it's kind of in the name), frame 3 starts to render

    I am really trying to understand which call prevents the depth buffer from frame 2 from being overwritten when frame 3 starts (given the queued present of 2 has not been executed yet).
    As I said, you presumably used some kind of synchronization between frames 2 and 3. Barriers, events, semaphores, fences, an external dependency from the renderpass that renders to it, any of those would work.

    Vulkan tutorial also duplicates its UBO's for the inflight frames which is what I would expect to be necessary as there are multiple queues possible rendering at the same time.
    That's different. With uniform buffers, you're providing new data to each frame of rendering. And this data must be preserved until the render process that uses that buffer is finished with it. It's not about preventing Vulkan from writing to the buffer again; it's about preventing you from writing to the buffer again (or more specifically, allowing you to continue preparing the next frames' rendering without breaking the current one).

    By contrast, the contents of the depth buffer are its own. Its contents are generated by on-GPU processes: the renderpass load/clear operation, subpasses that use it as a depth attachment, etc. Once you're finished generating an image with the depth buffer, you don't need it anymore. So that buffer can be immediately reused by another rendering process.

    Therefore, as I said, the only potential synchronization issue is that you have to prevent the next frame's rendering commands from starting until the current frame's commands have finished with the depth buffer. And since you usually have plenty of other reasons for imposing synchronization between frames, that synchronization should be sufficient.

  7. #7
    Quote Originally Posted by Alfonse Reinheart View Post
    As I said, you presumably used some kind of synchronization between frames 2 and 3. Barriers, events, semaphores, fences, an external dependency from the renderpass that renders to it, any of those would work.



    That's different. With uniform buffers, you're providing new data to each frame of rendering. And this data must be preserved until the render process that uses that buffer is finished with it. It's not about preventing Vulkan from writing to the buffer again; it's about preventing you from writing to the buffer again (or more specifically, allowing you to continue preparing the next frames' rendering without breaking the current one).

    By contrast, the contents of the depth buffer are its own. Its contents are generated by on-GPU processes: the renderpass load/clear operation, subpasses that use it as a depth attachment, etc. Once you're finished generating an image with the depth buffer, you don't need it anymore. So that buffer can be immediately reused by another rendering process.

    Therefore, as I said, the only potential synchronization issue is that you have to prevent the next frame's rendering commands from starting until the current frame's commands have finished with the depth buffer. And since you usually have plenty of other reasons for imposing synchronization between frames, that synchronization should be sufficient.
    Hmm.. as I posted before your answer.

    Uber-general Vulkanís GPU-side command execution rules:
    1. Command queues run independently of each other.
    2. When submitted to queue A, command buffers execute in the specified order
    From http://32ipi028l5q82yhj72224m8j-wpen...ulkan-apps.pdf


    So since I use one queue and each command buffer submitted on a queue executes in the specified order.
    Then command buffers can reuse attachments like depth buffers since any command buffer that shares it on the same queue will have finished executing.

    Isn't that the correct reason and not because of any in app synchronization?

  8. #8
    So for other interested parties it basically boils down to:

    1. Command buffers submitted to a single queue respect the submission order https://www.khronos.org/registry/vul...tals-execmodel
      This is the primary reason why it works.
    2. The fence protection on the app side that prevents the app from reusing the command buffer before its been executed.
    Last edited by VulkanBuilder; 11-08-2018 at 10:19 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Proudly hosted by Digital Ocean