groufix is a cross-platform, thread-friendly and hardware accelerated graphics engine built in C11. The library is primarily focused on the Vulkan API (1.1+). It is compatible with C11 and up, GNU++11 and up and C++20 and up. The main repository is hosted on GitHub.
The engine currently supports the following targets:
- Unix-like (GCC, Clang)
- Windows (XP+) (Mingw-w64)
- macOS (experimental) (Xcode Command Line Tools) (MoltenVK)
Check out all source code:
git clone https://github.com/Ckef/groufix.git
cd groufix
git submodule update --init --recursive
The project is shipped with a Makefile, run make
or mingw32-make
without a target to view all possible build targets. Each supported operating system has an explicit target. It is also possible to cross-compile groufix to Windows using the mingw-w64
package.
The Makefile takes the following flags:
-
CC=xxx
tells the Makefile to use a given compiler collection.xxx
defaults togcc
, to cross-compile to Windows, this must be set toi686-w64-mingw32-gcc
orx86_64-w64-mingw32-gcc
. -
DEBUG=xxx
tells the Makefile whether or not to compile groufix with debug options enabled. If not compiling with debug options, optimization settings will be applied.xxx
can be eitherON
orOFF
and defaults toON
.SANITIZE=xxx
tells the Makefile to enable sanitizers. This setting is ignored if not compiling with debug options.xxx
can be any-fsanitize
option, e.g.address,undefined
.
-
USE_WAYLAND=xxx
tells the Makefile whether to compile for Wayland or not, as it will default to X11 when building on Linux.xxx
can be eitherON
orOFF
and defaults toOFF
.
Most major dependencies are included as submodules in the repository (see the deps/
directory). They are automatically built and linked by the included Makefile.
To build and run with debug options enabled, the VulkanSDK needs to be installed on your system. All other dependencies based on your setup are:
When building on Linux:
gcc
orclang
: for building source files, use theCC
flag to pick a compiler collection.make
andcmake
: for building source files.xorg-dev
orlibwayland-dev
: for building GLFW.python3
: for building Shaderc.
When cross-compiling to Windows:
mingw-w64
: for building source files for windows (in addition to the above packages), theCC
flag needs to be set as described under #Building.
When building on Windows:
- CMake and Mingw-w64 need to be installed, which should include the
cmake.exe
andmingw32-make.exe
binaries. To use these to build groufix, add thebin
directory of both to yourPATH
variable. Make sure to install the compiler usingPOSIX
threads. - Git and Python 3 need to be installed for building Shaderc, make sure to install both to your
PATH
variable.
Once groufix is built and used by an executable, the following environment variables can be set:
-
GROUFIX_DEFAULT_LOG_LEVEL
: used to set the default log level during init. Value can be set to one ofNONE
,FATAL
,ERROR
,WARN
,INFO
,DEBUG
,VERBOSE
,ALL
, case insensitive. -
GROUFIX_PRIMARY_VK_DEVICE
: used to influence the primary device selection. It will prioritize matching physical Vulkan devices. A device matches if the set value is a substring of its name, case insensitive.
All core functionality can be included in your code with #include <groufix.h>
. To use the engine, it must be initialized with a call to gfx_init
. The thread that initializes the engine is considered the main thread. Any other function of groufix cannot be called before gfx_init
has returned succesfully, the only exceptions being gfx_terminate
, gfx_attach
, gfx_detach
and the gfx_log*
function family. When the engine will not be used anymore, it must be terminated by the main thread with a call to gfx_terminate
. Once the engine is terminated, it behaves exactly the same as before initialization.
- groufix will not clean up after you. This means that any object you create or initialize should be destroyed or cleared by you as well, before termination. In practice this means any call to a
gfx_create_*
orgfx_*_init
function should be followed up by a call to the associatedgfx_destroy_*
andgfx_*_clear
functions.
All names starting with gfx
or GFX
are reserved by groufix, using any such name in conjunction with the engine might result in redefinitions.
Similarly to initializing the engine, any thread that wants to make any groufix calls needs to attach itself to the engine with a call to gfx_attach
. Before an attached thread exits, it must be detached with a call to gfx_detach
. The main thread is the only exception, it does not have to be explicitly attached or detached. The threading model is designed around low overhead in multiple concurrent threads, it aims to stall as little as possible when accessing objects. The following rules are defined for all groufix objects to aid in this goal:
-
groufix will not reference count. This means that whenever you destroy, clear or free an object with a call to the associated
gfx_destroy_*
,gfx_*_clear
orgfx_free_*
function, any other object may not reference this object anymore. If an object is still referenced during any such call, behaviour is undefined. -
groufix objects are not thread-safe. Function calls that operate on the same object (or descendants thereof) are not synchronized and cannot be called concurrently from different threads. However, objects referencing each other that do not share a common ancestor created with a call to
gfx_create_*
are internally synchronized and can always be operated on concurrently. For example, simultaneously operating on aGFXRenderer
and aGFXHeap
(orGFXWindow
) referenced by it is thread-safe. -
All functions directly related to the window manager of the host platform are thread-affine. These functions can only be called from the main thread. These functions are
gfx_poll_events
,gfx_wait_events
and all functions defined ingroufix/core/window.h
(these are thegfx_*monitor*
andgfx_*window*
function families). All other functions can be called from any thread.
When an exception is made to any of the listed rules, this will always be noted alongside the relevant functions of the object in question. The following are a few of the most noteworthy exceptions:
-
Devices : Any function that takes a
GFXDevice
is thread-safe with respect to that given device. -
Heap allocations : To facilitate concurrent creation of resources, all
gfx_alloc_*
andgfx_free_*
functions are thread-safe with respect to theGFXHeap
. -
Resource operations : To facilitate concurrent modification of memory resources, operations performed on different resources are thread-safe with respect to the
GFXHeap
that allocated them. -
Dependency objects : To facilitate concurrent synchronization of resources, the
gfx_dep_*
macro family is thread-safe with respect to theGFXDependency
. -
Techniques and sets : To facilitate concurrent creation and modification of resources, the
gfx_*tech*
andgfx_*set*
function families are thread-safe with respect to theGFXRenderer
.- Except for modification during frame operations, i.e. during
gfx_renderer_acquire
or from the momentgfx_frame_start
is called up untilgfx_frame_submit
returns.
- Except for modification during frame operations, i.e. during
-
Recorders : To facilitate concurrent initialization of threads and subsequent threaded recording, the
gfx_*recorder*
function family is thread-safe with respect to theGFXRenderer
.- Except for creation and modification during frame operations, much like modification of techniques and sets.