How to initialize haiku ?¶
In this tutorial, we will write the mandatory boilerplate code that will allow us to later use the haiku graphics API.
Module initialization¶
Any haiku application or headless compute program starts by initializing the haiku graphics module.
This module allows the library to perform several actions:
It allows to allocate internal data structures inside centralized memory pools.
It allows to log any notification, warning and error messages to the user.
It allows to enable a custom assertion mechanism while debugging.
So the first task of any user is to provide the following:
a required custom allocator callbacks/context,
an optional custom assertion callback/context,
an optional custom logger callback/context
These data structure are given to the function hkgfx_module_create
to properly setup the graphic backend implementation.
Yielding:
hkgfx_module_create( &(hk_module_desc) {
.allocator = {
.context = NULL,
.realloc_fn = my_sample_realloc,
.alloc_fn = my_sample_alloc,
.free_fn = my_sample_free,
},
.assertion = {
.context = NULL,
.assert_fn = my_sample_assert
},
.logger = {
.context = NULL,
.log_fn = my_sample_logger
}
});
Here is an example of a full definition of every custom mechanism used by the module. Besides the allocator, a user can omit assertion and logging system but it is highly recommended during development.
You can also see that haiku uses a typical c99 initialization pattern via designated initializers.
The user provides a temporary reference to a descriptor structure with nested parameters.
So the temporary data structure only lives during the call to hkgfx_module_create
and leaves the stack after the call.
This is a pattern that is used a lot inside haiku
public C-API so you’ll see it often in our samples/tutorials.
Another special note here: if you can omit a field like any .context
for instance, the designated initialization will set the field to zero or null.
Module deinitialization¶
In C, when there’s a initialization call, there’s a deinitialization call to cleanup after you.
So at the end of your program, you’ll call hkgfx_module_destroy
function.
/* [your code here] */
hkgfx_module_destroy();
return EXIT_SUCCESS; // if at the end the main function
Default module implementation¶
In this section, we’ll add a simple implementation of the module callbacks without user-defined context. The required C headers used in the following functions are:
stdlib.h (
malloc
,free
,realloc
)stdio.h (
fprintf
,vfprintf
)stdarg.h (
va_list
,va_start
,va_end
)stddef.h (
size_t
)stdbool.h (
bool
)assert.h (
assert
)
Simple allocator¶
This dummy allocator will fallback calls to standard malloc
, free
and realloc
functions.
void* my_sample_alloc(size_t bytesize, void* ctx)
{
(void) ctx;
void* ptr = malloc(bytesize);
if(ptr==NULL)
{
fprintf(stderr,"Failed to allocate %5zu bytes.\n",
bytesize
);
exit(EXIT_FAILURE);
}
return ptr;
}
void my_sample_free(void* ptr, size_t bytesize, void* ctx)
{
(void) ctx;
(void) bytesize;
free(ptr);
}
void* my_sample_realloc(size_t newsize, void* oldptr, size_t oldsize, void* ctx)
{
(void) ctx;
assert( newsize>0 && "Invalid new size");
assert( newsize>oldsize && "Invalid reallocation size");
void* newptr = realloc(oldptr,newsize);
if(newptr==NULL)
{
fprintf(stderr,"Failed to realloc %5zu bytes from address %p with size %5zu.\n",
newsize,
oldptr,
oldsize
);
exit(EXIT_FAILURE);
}
return newptr;
}
Simple logger¶
This logger will fallback calls to standard fprintf
formatting functions with variading arguments.
void my_sample_logger(void* ctx, int level, const char* message, ...)
{
(void) ctx;
fprintf(stderr, "%s - ", my_logger_level(level));
va_list arguments;
va_start(arguments, message);
vfprintf(stderr, message, arguments);
va_end(arguments);
fprintf(stderr, "\033[0m\n");
}
my_logger_level
starts a colored message based on the level returned by haiku:
const char* my_logger_level(int level)
{
switch(level)
{
case HAIKU_LOG_INFO_LEVEL: return "\033[0;36m[NOTIF]";
case HAIKU_LOG_WARNING_LEVEL: return "\033[0;33m[WARNG]";
case HAIKU_LOG_ERROR_LEVEL: return "\033[0;31m[ERROR]";
default: return "\033[1;0m[NOPE]";
}
}
Simple assertion¶
This assert will print the assertion message and call abort
.
void my_sample_assert(bool expr, const char* message, void* ctx)
{
(void) ctx;
if(!expr)
{
fprintf(stderr, "%s\n", message);
abort();
}
}
Reference¶
The allocator callbacks following the design of this Chris Wellons blog post