ENTRY
[ESC]Whimsical Log 07/11/26
Gosh have I been busy, and that has led me to neglect writing regular updates.
I promise that I'm hard at work on Whimsical GE when I have time.
Explanation aside(more like excuse), let me catch you up.
So a while back I found this brilliant blog post, by Fabian Sanglard, titled "Doom3 BFG Source Code Review: Multi-threading". Essentially the Author does a very good job explaining how the idtech4 engine works with threads. He does so without going line by line, which is very nice. After reading the post multiple times I said to myself "This is awesome! I can do something similar and not have to implement threading later", I also said, "How hard could it be?"...
But, because Whimsical GE is an engine made by me, for me, I don't really need to have an overly complicated threading scheme. So I will design my engine to have the main thread running the game loop and recording the command buffers, and one thread that simply submits the command buffers to the GPU. There will also be a number of worker threads, "they exist to serve" the "core" threads.
Now, I've only gotten the worker threads done, but it's really neat... Basically each of the core threads are able to submit jobs that need to be done but that they don't feel like doing themselves.
Here is what a job looks like:
struct Job
{
void (*function)(void *);
void *parameters;
const char *job_id;
JobType type;
};
This is taken pretty much directly from the blog-post. I have however added the JobType enum, in order to be able to implement internal worker logic for different job types. For example, I want to be able to submit JobType::Exit when I want the thread to shut down.
What is really neat with the struct is the void* for the parameters, having it be a void pointer means when the caller wants to submit a function that takes certain parameters, they need only to submit the pointer to the object they want the thread to consume and in the function cast the void* to whatever type they intended to submit. Here's an example of what a function can look like:
void example_function(void *ptr)
{
// check if the pointer is invalid
if(ptr == NULL)
SDL_Log("No Parameters Provided");
else
{
// if the pointer is valid then we just cast it to a string pointer
std::string *actual_p = (std::string *)ptr;
SDL_Log("Example function being executed %s", actual_p->c_str());
}
}
There are still things that I haven't figured out yet:
- How can I cleanly free the parameter after the job has run;
- How do I want to handle return values. Say I want Worker_A to load the mesh CyberSpace.gltf, how should I go about storing that data...
Anywho, enough rambling from me. Tomorrow I'll attempt to figure out the two points above, and hopefully next week I'll be able to start splitting up the main thread.
Hope you're creating something that excites you as much as this excites me.
Join the conversation