Open comments for this post
DEVLOG 5 - The ECS Architecture
Since I can now draw something on the screen, I’d say it’s time to start building the actual graphics engine. The first system I need to create for Eve is the management of game objects. There are two options: the first is to use the OOP programming paradigm and therefore manage game objects just like Unity does; the other, which is the one I chose, is to use the ECS (Entity, Component, System) architecture.
To understand why I chose ECS, you need to understand how this architecture works. As I mentioned, the word ECS is an acronym for Entity, Component, and System, which represent the three pillars on which this architecture is based. In short, entities represent objects, the essence of the object; that object simply exists, and they are usually represented by a simple numeric ID. Components, on the other hand, represent pure data; therefore, each entity can have its own components and therefore its own data. Systems, on the other hand, are the part of the code that executes the logic. Let’s take the rendering system as an example. This will iterate over all entities that have mesh components, and a transform will take their data and send it to the GPU for rendering.
This division of responsibilities ensures incredible efficiency, given how the CPU works, since the component data is stored contiguously in memory. This facilitates the work of a CPU component called the Hardware Prefetcher, which tries to predict which portion of RAM the CPU will use next, thus reducing cache misses.
There are many ready-to-use libraries for this architecture, such as Flecs, EnTT, and others. I chose to try and create my own so I could learn and understand more. Currently, I’m using, broadly speaking, the same approach Unity uses with their ECS architecture, which is part of their Unity DOTS ecosystem.
All entities in the game can be classified based on an ID called an Archtype, which identifies the type of entity being viewed based on its components. This way, you can have contiguous arrays and minimize cache misses, thus maximizing CPU efficiency.
I’m still working on it, but I have to say it’s extremely interesting…
Open comments for this post
DEVLOG 4 - Textures!
I finally managed to use textures; Vulkan has a bit of boilerplate in their configuration, especially with the descriptor sets. This was the part that slowed me down a bit.
The code isn’t very tidy at the moment… For now, I’ve focused more on learning, so I haven’t written anything extremely tidy and readable. As I said, I’ve only learned the basics so far.
Now that I feel more confident about the subject, I think I’ll start writing something. I’m thinking of a framework or something simple that allows you to draw geometry on the screen without having to write hundreds of lines of code directly with Vulkan. So, more generally, I think I’ll create a layer of abstraction while still trying to maintain excellent flexibility.
Open comments for this post
DEVLOG 3 - First Cube!!!
How satisfying, my first 3D object!
Since previously all vertices were written manually in the shader, I opted to learn how to create buffers to load more complex 3D geometry onto the screen.
I’m loading the resources directly into a specific portion of memory called Host Visible, where the CPU can also write, and the GPU’s reading isn’t as fast as it could be. If I instead allocate the memory in a portion of VRAM called Device Local, the GPU will be very fast at accessing the data, but the CPU, on the other hand, won’t be able to do anything with that memory. To modify it, you need to first allocate the data in an intermediate buffer called Staging Buffer, and then from there the data can go to Device Local memory (the GPU’s fast memory).
I also added some transformations and rotations with GLM to rotate the cube, and this is the result, which is nice.
I think I’ll try using Device Local memory by loading data to it, as discussed before, with a Staging Buffer and after that I think I’ll start experimenting with textures.
Open comments for this post
DEVLOG 2 - Consolidation of things learned
Well,
What’s new? Just a square? It might not seem like much, but yes. I spent all these hours rewriting the entire code from scratch so I could understand where I had the most doubts and therefore review some concepts.
Synchronization was and still is the most difficult concept to grasp; understanding how the semaphores and barriers are linked together wasn’t easy for me, and I must admit I still have some doubts about it, but certainly much less than before. Given the asynchronous nature of the graphics card, you can’t program operations that will be executed in order, unlike the CPU, and this is one of the graphics card’s strengths and weaknesses. You can parallelize many operations, but you have to be careful how they are linked together and synchronize them as correctly as possible.
My next step, I think, will be to use buffers to give more complex geometry to the shaders, primarily for drawing 3D geometry. I also think I still have to delve deeper and better understand things like semaphores, timeline semaphores, and barriers, which are topics I feel I haven’t internalized as well as others.
Open comments for this post
DEVLOG 1 - Hello Triangle!!!
Finally,
after several hours trying to understand how Vulkan works, watching and reading several tutorials, I got it, my first triangle, isn’t it cute?🫠🫠
I’ve figured out most of the things, but I think I need to delve a little deeper into the process of creating a pipeline with dynamic rendering and synchronization. These are the two topics that have been giving me the most trouble.
I think the next step will be to re-explore the code and try to create something on my own, without a guided tutorial, to see if I’ve really understood the concepts.