With my games I have a global array `end_of_frame_tasks` which just collects callbacks and calls them at the end of the frame. The callbacks can perform arbitrary logic and their number usually doesn't exceed 100 tasks per frame, so it's not a perf issue. To do that in Odin, I guess I'd have to replicate a closure with a function pointer and a buffer with saved context for the function?
You could expand this to be multi-stage and batch the cleanup tasks by the earliest point at which you could execute them. For example, if you're drawing two passes and don't need a resource from the first pass for the second, you could clean that up well before the frame ends.
Subscribed man, great simple explanation of command buffers, the grocery shopping metaphor was perfect. Maybe an expanded video on queuing commands and batching by priority for a more advanced expansion to this would be awesome. For the really advanced, multi-threaded update/render loops with asynchronous command buffers.
Thanks for the video! I _just_ wrote a naive debug draw buffer with raylib in C and was storing separate arrays for each type (cube, sphere, grid etc) - using unions will help! Though in C will need to track type...
tagged unions let you figure out the type, then you just cast it. the advantage of a separate array for each type is that they're going to be more tightly packed, which will mean more items will fit in the CPU RAM cache at once, and you can handle just that type when looping over the items, which will speed up branch prediction. the advantage of a single array of a union type is that you just have the one array, which might be more convenient for your use case (for example if you're copying the data to some other layer, like the GPU, or have to serialize it to disk). but the cost is that your loops will have to dispatch to different bits of handler code for each item in the array, harming branch prediction, and there will be wasted space because each member of a union has the size of the largest union member, and has to add padding to compensate.
I guess (without looking right now) that is probably just a queue c: Command queueing is kinda of different since you're reifying that struct so you can use it whenever. There's actually a lot of use cases and is super useful.
With my games I have a global array `end_of_frame_tasks` which just collects callbacks and calls them at the end of the frame.
The callbacks can perform arbitrary logic and their number usually doesn't exceed 100 tasks per frame, so it's not a perf issue.
To do that in Odin, I guess I'd have to replicate a closure with a function pointer and a buffer with saved context for the function?
You could expand this to be multi-stage and batch the cleanup tasks by the earliest point at which you could execute them. For example, if you're drawing two passes and don't need a resource from the first pass for the second, you could clean that up well before the frame ends.
Subscribed man, great simple explanation of command buffers, the grocery shopping metaphor was perfect. Maybe an expanded video on queuing commands and batching by priority for a more advanced expansion to this would be awesome. For the really advanced, multi-threaded update/render loops with asynchronous command buffers.
Thanks for the video!
I _just_ wrote a naive debug draw buffer with raylib in C and was storing separate arrays for each type (cube, sphere, grid etc) - using unions will help! Though in C will need to track type...
I have a hunch that you could use an array of void* pointers and an array that stores the type of each void*
Not sure if that's stupid or not lol
tagged unions let you figure out the type, then you just cast it.
the advantage of a separate array for each type is that they're going to be more tightly packed, which will mean more items will fit in the CPU RAM cache at once, and you can handle just that type when looping over the items, which will speed up branch prediction.
the advantage of a single array of a union type is that you just have the one array, which might be more convenient for your use case (for example if you're copying the data to some other layer, like the GPU, or have to serialize it to disk). but the cost is that your loops will have to dispatch to different bits of handler code for each item in the array, harming branch prediction, and there will be wasted space because each member of a union has the size of the largest union member, and has to add padding to compensate.
I haven't looked but isn't this what raylib does internally too?
What exactly?
Raylib doesn't provide game loop, only reading inputs, play sounds you make it play and draw things you make it to draw.
@NeZversSounds the batching that happens when you are calling draw functions with the same draw state, is kind of a command buffer of shapes
I guess (without looking right now) that is probably just a queue c:
Command queueing is kinda of different since you're reifying that struct so you can use it whenever.
There's actually a lot of use cases and is super useful.
great concise video. thanks, subscribed.
Nice to the point video.
Great that it uses Odin and Raylib, make things clear (for me at least).
Thanks!
Glad you liked it!
What about doing all of the update and drawing between BeginDrawing and EndDrawing?
Everyone and should are red flags to me.
Also would have been nice to know when and when not to use this.
Great video, but I really thought the video was going to go into input buffering, a technique many fighting games employ.
Edit out the keyboard thanks