Skip to content
This repository was archived by the owner on Mar 31, 2023. It is now read-only.
This repository was archived by the owner on Mar 31, 2023. It is now read-only.

Draw loop should not be destroying and recreating framebuffers each frame #20

Open

Description

In Tutorial4 onwards, the render loop is destroying and recreating framebuffers every frame. Creation and destruction of objects in Vulkan are not lightweight operations - they are expected to have a sizeable runtime cost, and indeed do on some implementations.
This is documented in the Vulkan spec itself in fact, the second paragraph here: https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#fundamentals-objectmodel-lifetime

The offending lines are here in Tutorial04, for instance:

bool Tutorial04::CreateFramebuffer( VkFramebuffer &framebuffer, VkImageView image_view ) {

These objects should be created once and re-used, the same as all other objects in a robust Vulkan application.

Activity

  1. Ekzuzy commented on Oct 13, 2017

    @Ekzuzy
    Collaborator

    Well, that depends. Creation and desctruction of framebuffers in each frame is done on purpose:

    • as far as I know, framebuffers are not so heavy, so the cost of their creation is not too big (or at least is much lower than for example pipelines)
    • we may not know up front what images/render targets will be required for the render pass; so creating a framebuffer just before it is used is much easier to perform
    • there may be many different combinations of images/render targets involved in rendering, so we may need to create plenty of framebuffer objects
    • if swapchain images are used as render targets (what is quite common), everytime swapchain is recreated we also need to recreate all the framebuffers in which they are used

    All this leads to the most important factor - with such approach our code will be much harder to maintain, to read and to understand. We can't create all the framebuffers at initialization phase, because some of them depend on the swapchain. And we also need to recreate framebuffers that use swapchain images, every time the swapchain is recreated. But we don't need to recreate all of them (though we can, of course). Such code isn't too good for a tutorial. So this was the main reason I didn't do it.

    But of course, if we want to improve the performance of our application, we should create all the resources we can before the main, rendering loop. We just can't forget that this is a tradeof between the performance and the factors mentioned above (code readability, complexity, maintainability).

  2. Ekzuzy commented on Oct 13, 2017

    @Ekzuzy
    Collaborator

    I agree with You. But still, I do it to simplify the code - this approach makes code much cleaner, easier to read and to understand. I just create framebuffers and destroy after several frames. It also fits the presented way of managing several number of independent "virtual frames". Recreating them along with swapchains or adding even more advanced logic, for example to check whether such framebuffer already exists, isn't necessary to explain presented topics (especially at this, rather low, level of complexity). It just clutters the code and draws away reader's attention from more important things.

    But You just brought an interesting idea. Not for the tutorials as in those I just want to explain the very basics of the Vulkan API. But for other usecases, the mentioned cache sounds really handy. For example cache storing arbitrary number (i.e. 20) of framebuffers used during rendering. If we need 21st framebuffer, the least recently used one just gets destroyed. Is this something You were thinking about?

  3. Ekzuzy commented on Oct 16, 2017

    @Ekzuzy
    Collaborator

    Information about the consequences of such approach, and the reason why it was chosen for the tutorial, definitely wouldn't hurt ;-). I will add a note about it somewhere in the tutorial.
    But!

    We had a developer thinking this was just something they should do in their app, or was reasonable to do, with hefty performance consequences.

    I've talked about it and consulted it with several people and most of them agreed that such approach is reasonable. But this may come from the fact that we (or at least I) were thinking more about desktop GPUs. I don't have any experience with mobile development or mobile GPUs so I didn't know the impact of such approach may be much more severe on mobile platforms.

    I will add a paragraph about it in the 4th tutorial to clarify things a bit. Thanks for pointing this out!

  4. szihs commented on Oct 18, 2017

    @szihs

    Hello Tobias,
    I agree object creation/destruction should be out of performance critical path.
    However I am interested to know why desktop GPU and mobile would have difference on say, this particular API
    "
    Firstly, the assumption that it's cheap probably holds for desktop GPUs, but on mobile it doesn't quite work - framebuffer creation is expensive on at least Imagination's implementation, and for good reason. I highly suspect that other mobile vendors have the same high cost creation for similar underlying reasons."

    Is it related to TBDR Vs immediate mode base renderer? Is so, would you be kind enough to explain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions