Open-source project
gboisse/gfx avatar
gboisse/gfx

gfx wraps Direct3D 12 in a header-only API aimed at rapid prototyping

A minimalist and easy to use graphics API.

526 stars45 forksC++MIT

At a glance

What is it?
gfx is a C++ graphics API built on Direct3D 12 and HLSL that hides root signatures, pipeline states, descriptor tables and register indexing, and adds deferred resource release, automatic barriers, runtime shader reloading and GPU parallel primitives. It is MIT licensed, Windows-only by construction, and its own examples are the documentation.
Who is it for?
Adopt gfx if you are prototyping rendering techniques on Windows in C++ and want to skip the Direct3D 12 boilerplate without giving up control of the underlying work. Do not adopt it if you need a cross-platform renderer, since it is built directly on Direct3D 12, or if you need a production renderer, since the project positions itself as a prototyping and research tool.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What it hides, and what it does not

gfx is described as a minimalist and easy to use graphics API built on top of Direct3D 12 and HLSL, intended for rapid prototyping.

The feature list describes the API in terms of what it removes and what it adds, and the removals come first. Full shader reflection, so no need for root signatures, pipeline states, descriptor tables, register indexing, and the rest of the Direct3D 12 setup surface. Internal management of descriptor heaps, resource views and memory allocation.

The additions are the interesting part, because they are not things a wrapper would normally take on.

There is a garbage collection mechanism that defers the release of freed resources to ensure the GPU is done with it. The README's phrasing is direct about the consequence: you can create and destroy anything at any time without worrying about synchronization. On an API where a destroyed buffer can still be referenced by an in-flight command list, that is a real class of bug removed.

Automatic placement of pipeline barriers and resource transitions is the second one. Direct3D 12 makes the developer declare every state transition, and getting it wrong produces corruption rather than an error. Handing that over is a large simplification for a prototype.

Then runtime shader reloading, which is a single call, gfxKernelReloadAll(). You edit an HLSL file, you call the function, and the new shader is live. For research work, where the shader is the thing you are iterating on, that is the single most valuable feature in the list.

Finally there are basic GPU-based parallel primitives: min, max and sum scans and reductions, plus key-only and key-value pair sorting for various data types. That is a small compute layer shipped with the renderer, which is the kind of thing you would otherwise write while testing an algorithm.

The header-per-layer structure and how you build it

The library is organised as a set of headers, and the layering is the API design.

There is gfx.h as the base, and on top of it three optional layers. gfx_imgui.h adds Dear ImGui support. gfx_scene.h supports loading .obj files, with .gltf coming soon. gfx_window.h handles window creation and basic event management.

The usage instruction is one sentence and it tells you how the library is built. You include the header corresponding to the desired level of functionality, and in one .cpp file you define GFX_IMPLEMENTATION_DEFINE and include that header to include the implementation details.

That is a single-header library pattern where the implementation lives behind a macro, and it has an obvious consequence for a project structure. You get the header-only convenience of not linking a library, but exactly one translation unit carries the implementation. That is a workable arrangement for a prototyping library, where you are writing a handful of .cpp files anyway, and it would be a consideration in a larger codebase with many compilation units.

The repository layout confirms the split. There is gfx.h and gfx.cpp, gfx_core.h and gfx_core.cpp for the internal core, and then a pair per layer: gfx_imgui.h and gfx_imgui.cpp, gfx_scene.h and gfx_scene.cpp, gfx_window.h and gfx_window.cpp, plus gfx_internal_types.h and gfx_internal_types.cpp. There is a third_party/ directory, a CMakeLists.txt, and an examples/ directory.

The examples directory is the part worth noting, because it is the real documentation. There are 00-hellotriangle, 01-rtao, 02-pbr and 03-mesh, plus a common/ directory and its own CMakeLists.txt. A raytraced ambient occlusion example, a physically based rendering example and a mesh example are a considerably more ambitious set of samples than most libraries ship, and they cover exactly the techniques a renderer researcher would want to reproduce.

The licence is MIT, with a LICENSE.md at the repository root, and the primary language is C++ with the default branch master.

The triangle example is the whole API in one function

The README's triangle example is short enough to read in a minute, and it shows the shape of every call in the library.

cpp
// main.cpp

#define GFX_IMPLEMENTATION_DEFINE
#include "gfx_window.h"

int main()
{
    auto window = gfxCreateWindow(1280, 720);
    auto gfx = gfxCreateContext(window);

Then the resources, and note that a program is created by name rather than by compiling a shader blob:

cpp
    float vertices[] = {  0.5f, -0.5f, 0.0f,
                          0.0f,  0.7f, 0.0f,
                         -0.5f, -0.5f, 0.0f };
    auto vertex_buffer = gfxCreateBuffer(gfx, sizeof(vertices), vertices);

    auto program = gfxCreateProgram(gfx, "triangle");
    auto kernel = gfxCreateGraphicsKernel(gfx, program);

And then the frame loop, which is where the deferred release and the automatic barriers pay off:

cpp
        gfxProgramSetParameter(gfx, program, "Color", color);

        gfxCommandBindKernel(gfx, kernel);
        gfxCommandBindVertexBuffer(gfx, vertex_buffer);

        gfxCommandDraw(gfx, 3);

        gfxFrame(gfx);

Two details stand out. gfxCreateProgram takes the string "triangle", which is a shader name the library resolves, and that is what makes the runtime reloading feature possible: the library knows which file to recompile because it was given a name rather than a compiled blob. And gfxProgramSetParameter sets a parameter by name, "Color", which is the reflection working in your favour; there is no register index to compute.

The shaders are correspondingly small. The vertex shader takes a float3 position and returns a float4, and the pixel shader reads a float3 named Color and returns it as a float4. There is no root signature, no input layout, no constant buffer binding, and no pipeline state object. The library infers all of it from reflection.

The loop ends with gfxDestroyContext and gfxDestroyWindow, and the same deferred release guarantee means the destroy calls are safe to make while the GPU is still working.

The motivation explains the design better than the feature list

The README has a Motivation section, and it is short and unusually blunt about why the project exists.

The project was born mostly out of frustration while researching rendering techniques using explicit APIs such as Direct3D 12 or Vulkan.

The reasoning follows in the next paragraph. These APIs intend to deliver higher performance for complex workloads on both the CPU and the GPU by giving more responsibility to the developer, and unfortunately this is to the detriment of productivity, especially during the initial prototyping and research phase, due to their high level of complexity.

That is a fair characterisation of the situation, and it explains why the feature list is shaped the way it is. gfx is not trying to be a faster renderer than Direct3D 12. It is trying to make the first hour of a rendering experiment cheaper, by moving the parts of the API that only matter once you know what you are building out of the way.

The goal is stated as an efficient API that is easy to learn, pleasant to use and quick to get things set up, while offering rapid iterations. The phrase that gives it away is that it allows to get that start from scratch efficiency while still offering access to the basic necessary functionality, with low-level access to GPU work scheduling and drawing UI overlays given as examples.

So gfx is not a black box. It is a convenience layer that stops short of taking away the control that makes research possible. The low-level access to work scheduling and the Dear ImGui integration in gfx_imgui.h are the same point expressed twice: you want to iterate quickly, and you want to be able to look at what the GPU is doing while you do it.

That framing also tells you the audience. This is for a researcher or an engineer experimenting with a rendering technique, on Windows, in C++. It is not a general purpose engine for shipping a product, and it does not pretend to be.

Raytracing support and the compute primitives

Two of the listed features point at what the project is actually for.

The first is DXR-1.1 raytracing, described as using the RayQuery<> object and also known as inline raytracing. That is the DirectX 12 extension where a shader performs ray queries against the scene in the shader itself, rather than through a separate ray tracing pipeline. The README links the Microsoft specification for it.

Inline raytracing matters for prototyping because it is the mechanism behind several techniques that are hard to research without it. Ambient occlusion from rays, reflections that fall back to the screen, and any effect that needs a distance query inside a fragment shader are all awkward without it. The examples directory includes 01-rtao, which is a raytraced ambient occlusion sample, so the feature is exercised rather than merely claimed.

The second is the GPU-based parallel primitives: min, max and sum scans and reductions, plus key-only and key-value pair sorting for various data types.

That is a different category of feature from the rest, and it is worth understanding why it is bundled here. A reduction or a sort on the GPU is the kind of thing you need when you are implementing a GPU-driven renderer with a compute pass for visibility or a radix sort for indirect draws, and building it yourself inside a research prototype is exactly the kind of work that has nothing to do with the research question. Shipping them means the researcher can spend the afternoon on the algorithm instead of on the parallel prefix sum.

Both features also reflect the Direct3D 12 base. Inline raytracing is a DirectX 12 feature with no equivalent in the general compute APIs, and the parallel primitives are expressed as compute kernels, which is where such algorithms live on modern GPUs.

The example set backs this reading. Besides the hello triangle and the RTAO sample there is 02-pbr for physically based rendering and 03-mesh for mesh handling, with a shared common/ directory, so the examples cover the pipeline from a single triangle to a PBR scene with geometry.

Where gfx is the wrong tool

The first limitation is the platform. gfx is built on Direct3D 12 and HLSL, so it is a Windows library. Not a Windows-first library with a cross-platform backend, but a Windows library. If you need the same prototype to run on Linux, or you work on macOS, gfx does not apply and you would be back to the explicit APIs it exists to avoid, or to a different abstraction layer.

The second limitation is that the API hides a lot, and what it hides is exactly what you might need to study. The whole point of Direct3D 12 is that the developer owns the scheduling, and gfx takes over root signatures, pipeline states, descriptor tables, register indexing, descriptor heap management, resource view creation, memory allocation, barrier placement and resource transitions. If your research question is about any of those, gfx is the wrong instrument, because it has removed the thing you are trying to look at.

The third limitation is that it is a research tool with the conventions of one. There is no versioning story in the README, there are no GitHub releases, and the description in the repository metadata is a minimalist and easy to use graphics API. There is no mention of a stability guarantee or a support policy, and the.gltf support in gfx_scene.h is described as coming soon.

The fourth is the build shape. The single GFX_IMPLEMENTATION_DEFINE translation unit and the third_party/ directory bundled in the repository mean you are taking a vendored dependency tree, and the CMake configuration is part of the repository rather than something published as a package.

The alternative to weigh is the explicit route with a thin helper layer of your own, or a different abstraction entirely. If you want to prototype on more than one platform, the alternative is a cross-platform graphics library plus your own layer, which trades portability against taking on more of the boilerplate yourself. If you want a production renderer, the alternative is Direct3D 12 itself, or Vulkan with a framework, and gfx offers nothing there.

There is also the middle path, which is worth naming because it is what many research groups actually do: use gfx while investigating, then rewrite the parts that matter into explicit Direct3D 12 for the final implementation. The deferred release and automatic barrier behaviour means your prototype does not carry the synchronisation bugs that a hand-written version would, and when you port it you have a working reference to check the port against.

Maintenance and the state of the repository

The maintenance record is current. The last push was on 2026-10-20 and the repository is not archived, so the code is being worked on. The repository has no GitHub releases, so there is no tagged version to pin and the build comes from the source tree.

The top level entries show the shape of the project, and it is small and focused. There is gfx.h and gfx.cpp for the public surface and its implementation, gfx_core.h and gfx_core.cpp for the internals, gfx_internal_types.h and gfx_internal_types.cpp for the shared type definitions, then a pair of files for each optional layer: gfx_imgui, gfx_scene and gfx_window. Alongside them are a CMakeLists.txt, the LICENSE.md, the README.md, a .gitignore and the third_party/ directory.

That third_party/ directory is worth a note. A library that vendors its dependencies rather than declaring them through a package manager is making a choice about build reproducibility, and for a research library that is a reasonable trade, since it means a clone of the repository builds without a separate dependency resolution step. The trade is that you inherit those dependency versions and their update policy rather than choosing your own.

The licence is MIT with a LICENSE.md at the root. That is a permissive grant with no copyleft obligation on code you build with it, which matters here because a research library is exactly the kind of thing you vendor into a larger engine. That is a licensing note rather than legal advice.

The example directories, numbered 00 through 03, are the clearest signal about where the project is going. A hello triangle, raytraced ambient occlusion, physically based rendering and a mesh example, in that order, with the RTAO and PBR samples indicating that the scope covers the techniques a graphics researcher would actually want to reproduce rather than just the plumbing of getting a window open.

Editorial conclusion

Adopt gfx if you are prototyping rendering techniques on Windows in C++ and want to skip the Direct3D 12 boilerplate without giving up control of the underlying work. Do not adopt it if you need a cross-platform renderer, since it is built directly on Direct3D 12, or if you need a production renderer, since the project positions itself as a prototyping and research tool. Verify first that you have a Direct3D 12 capable GPU and the SDK, that you can use the build with CMake and the included third_party directory, and that the deferred resource release behaviour matches how your prototype manages lifetime.

Frequently asked questions

What is the gfx graphics API and what does it hide?

gfx is a minimalist C++ graphics API built on Direct3D 12 and HLSL for rapid prototyping. It provides full shader reflection so you need no root signatures, pipeline states, descriptor tables or register indexing, and it manages descriptor heaps, resource views and memory allocation internally.

How do I include gfx in a project?

Include the header matching the functionality you want, gfx.h or one of the optional layers gfx_imgui.h, gfx_scene.h or gfx_window.h. In one .cpp file define GFX_IMPLEMENTATION_DEFINE and include that same header to pull in the implementation details.

How does gfx handle resource lifetime and synchronisation?

It has a garbage collection mechanism that defers the release of freed resources until the GPU is done with them, so you can create and destroy anything at any time without worrying about synchronisation. It also places pipeline barriers and resource transitions automatically.

Does gfx support raytracing and GPU compute?

It supports DXR-1.1 inline raytracing using the RayQuery<> object, and it ships basic GPU-based parallel primitives including min, max and sum scans and reductions plus key-only and key-value pair sorting. The examples directory includes a raytraced ambient occlusion sample.

What licence is gfx released under and what platforms does it support?

MIT, with a LICENSE.md at the repository root. gfx is built directly on Direct3D 12 and HLSL, so it is a Windows library. The last push was on 2026-10-20, the repository is not archived, and it publishes no GitHub releases.

Official sources

  1. gboisse/gfx on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gboisse-gfx.svg)](https://hysenlabs.com/projects/gboisse-gfx)