You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Mar 31, 2023. It is now read-only.
Repository navigation
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
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:
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).
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?
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!
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.
Activity
Ekzuzy commentedon Oct 13, 2017
Well, that depends. Creation and desctruction of framebuffers in each frame is done on purpose:
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).
Ekzuzy commentedon Oct 13, 2017
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?
Ekzuzy commentedon Oct 16, 2017
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!
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!
szihs commentedon Oct 18, 2017
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.