I'm not accepting pull requests, but the code is available publicly as I think it is valuable information for people who are looking to make their abstraction layer on top of graphic APIs.
This code is a thin layer on top of Metal and DirectX 11 APIs. The goal of this module is to write render code in an immediate and simple way. Currently it powers all my projects that play with graphics.
I liked the "immediate" feeling of DirectX 11 API, its inner state machine reduces boilerplate and goes more in my programming style. So internally, I create pipeline states (PSO) on the fly and then cache them in a lookup table. If you have many PSOs, this could have some impact on the first few frames, but I think it's manageable with relatively simple techniques.
The library load Slang shaders, and you'll get binding information alongside the corresponding shader program; I use the Slang reflection system to find the name of bindings, slot numbers, and types.
Here's a snippet to see the shape of the user code, for the complete example,
see demo/demo.jai:
MAX_FRAME_IN_FLIGHT :: 2;
VERTEX_BIND_INDEX :: 10;
vertex_buffers : [MAX_FRAME_IN_FLIGHT] GFX_Buffer;
main :: () {
success := create_context(platform_window);
assert(success == true);
// We can load and compile Slang shader. Shader could be packed in memory too (like now).
vertex_shader, pixel_shader := add_shader("ui", "ui.slang", SHADER_SRC);
for 0..MAX_FRAME_IN_FLIGHT - 1 {
vertex_buffers[it] = create_buffer("UI Vertices", size_of(Vertex) * 6, xx size_of(Vertex), null, .CPU_WRITE, .VERTEX_BUFFER);
}
while !quit {
begin_frame();
vertex_buffer := *vertex_buffers[get_backbuffer_index()];
// Copy vertices to GPU buffer.
{
vertices := Vector2.[
.{ (window_width / 2) , window_height * 0.2 },
.{ (window_width / 2 + window_width / 4), window_height * 0.8 },
.{ (window_width / 2 - window_width / 4), window_height * 0.8 }
];
map(vertex_buffer, .WRITE_AND_FLUSH);
memcpy(vertex_buffer.data_ptr, vertices.data, size_of(Vector2) * vertices.count);
unmap(vertex_buffer);
}
{
pass_desc: GFX_Render_Pass_Desc;
set_color_attachment(*pass_desc, 0, get_swapchain_texture());
clear_color(*pass_desc, 0, xyzw(0, 0, 0, 1));
pass := begin_render_pass("Debug name for my Render Pass", pass_desc);
{
set_pso_name("Debug name for my PSO");
set_vertex_shader(vertex_shader);
set_pixel_shader(pixel_shader);
set_blend_mode(.ADDITIVE);
set_vertex_layout(Vertex, VERTEX_BIND_INDEX);
set_viewport(*pass, .{ width = window_width, height = window_height});
set_vertex_buffer(*pass, VERTEX_BIND_INDEX, vertex_buffer, 0, vertex_buffer.size, size_of(Vertex));
draw(*pass, 3, 1);
}
end_render_pass(*pass);
present();
}
}
if quit {
SDL_DestroyWindow(window);
destroy_context();
}
}
#import "Basic";
#import "Math";
#import "Pixel_Maker"(MAX_FRAME_IN_FLIGHT = 2);
using, except(NO) SDL :: #import "SDL";
SHADER_SRC :: #string END
struct Vertex_Out {
float4 position : SV_Position;
};
struct Vertex {
float2 position : TEXCOORD0;
};
ConstantBuffer<float4x4> ortho;
[shader("vertex")]
Vertex_Out vertex_main(Vertex vertex) {
Vertex_Out result;
float4 position = float4(vertex.position.xy, 0, 1);
result.position = mul(ortho, position);
return result;
}
[shader("fragment")]
float4 fragment_main(Vertex_Out input) : SV_Target {
return float4(1, 1, 1, 1);
}
END
Right now, your project has to link dynamically with slang-compiler.dll or libslang.dylib (on macOS). Make sure those sit next to your executable.
A special thanks goes to Stefan. He convinced me it was worth spending some time on an abstraction layer and using Slang as our shader language. He wrote the first version of the abstraction layer for the game, back when we used OpenGL on Windows and the API had a different design. You can find him here.
The article written by Sebastian Aaltonen, No Graphics API opened my eyes on many things, and drove me towards this similar design (but DX11 is blocking me a bit tho, and I'm not ready to move on).
MIT License
Copyright (c) 2026 Alexandre Chêne
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.