Skip to content

zeozeozeo/rafx

Repository files navigation

rafx

Rafx is a C graphics abstraction library designed around modern graphics workflows.

It is based on the NVIDIA Render Interface (NRI).

Features

  • Fully bindless rendering approach (no CPU bindgroups, descriptor sets, ...)
  • Automatic tracking of resource states, barrier placement and transitions
  • Full parity between Vulkan, D3D12 and Metal (through MoltenVK/KosmicKrisp)
  • Support for Enhanced Barriers on DirectX 12 Ultimate
  • Built-in windowing (using RGFW, GLFW or SDL3), fully cross-platform
  • Built-in support for NRD denoisers (ReBLUR, ReLAX, Sigma) rfxCmdDenoise
  • Native integration with the Slang shader language
  • Graphics, compute, raytracing and mesh shaders
  • Support for hardware RT and opacity micromaps
  • Support for common upscalers (NVIDIA DLSS, AMD FSR, Intel XeSS, NVIDIA DLSS Ray Reconstruction, NIS)
  • printf inside shaders, toggleable hot-reloading rfxWatchShader
  • Suitable for tile-based rendering architectures
  • Tight integration with AMD's Virtual Memory Allocator (VMA) for Vulkan and D3D12 for optimal memory reuse
  • Async compute (parallel execution of graphics and compute workloads)
  • Variable rate shading (VRS) support
  • MSAA, anisotropic filtering, mipmapping and BCn texture compression with a simple toggle
  • Multidraw
  • Occlusion queries
  • Low latency support (aka NVIDIA Reflex)
  • GPU profiler, timeline annotations (GAPI, Nsight, PIX), resource naming
  • ImGui extension rfxCmdDrawImGui
  • Shader cache / precompilation
  • Honored user-provided memory allocator
  • Lots of examples to get you started

Examples

async compute bloom compute boids
async compute bloom compute boids
compute triangle compute voronoi cube
compute triangle compute voronoi cube
denoise hot reloading low latency
denoise hot reloading low latency
mesh triangle rt boxes rt triangle
mesh triangle rt boxes rt triangle
shadow mapping texcube triangle
shadow mapping texcube triangle
upscaler
upscaler

A triangle:

#include <rafx.h>

// minified for readme sake
const char* src = "struct V { float3 p:POSITION; float4 c:COLOR; }; "
                  "struct O { float4 p:SV_Position; float4 c:COLOR; }; "
                  "[shader(\"vertex\")] O vs(V i) { O o; o.p=float4(i.p,1); o.c=i.c; return o; } "
                  "[shader(\"fragment\")] float4 ps(O i):SV_Target { return i.c; }";

struct Vertex {
    float x, y, z, r, g, b, a;
};

int main() {
    rfxOpenWindow("Rafx", 1280, 720);

    struct Vertex data[] = { { 0, .5, 0, 1, 0, 0, 1 }, { .5, -.5, 0, 0, 1, 0, 1 }, { -.5, -.5, 0, 0, 0, 1, 1 } };
    RfxBuffer vb = rfxCreateBuffer(sizeof(data), sizeof(data[0]), RFX_USAGE_VERTEX_BUFFER, RFX_MEM_GPU_ONLY, data);
    RfxShader s = rfxCompileShaderMem(src, NULL, 0, NULL, 0);

    RfxVertexLayoutElement layout[] = { { 0, RFX_FORMAT_RGB32_FLOAT, 0, "POSITION" }, { 1, RFX_FORMAT_RGBA32_FLOAT, 12, "COLOR" } };
    RfxPipeline pip = rfxCreatePipeline(&(RfxPipelineDesc){
        .shader = s,
        .vertexLayout = layout,
        .vertexLayoutCount = 2,
        .colorFormat = rfxGetSwapChainFormat(),
        .vertexStride = sizeof(struct Vertex),
    });

    while (!rfxWindowShouldClose()) {
        rfxBeginFrame();
        RfxCommandList cmd = rfxGetCommandList();

        rfxCmdBeginSwapchainRenderPass(cmd, RFX_FORMAT_UNKNOWN, RFX_COLOR(20, 20, 20, 255));
        rfxCmdBindPipeline(cmd, pip);
        rfxCmdBindVertexBuffer(cmd, vb);
        rfxCmdDraw(cmd, 3, 1);
        rfxCmdEndRenderPass(cmd);

        rfxEndFrame();
    }

    rfxDestroyPipeline(pip);
    rfxDestroyShader(s);
    rfxDestroyBuffer(vb);

    return 0;
}