Gfx - A minimalist and easy to use graphics API.

gfx

gfx is a minimalist and easy to use graphics API built on top of Direct3D12/HLSL intended for rapid prototyping.

It supports:

  • Full shader reflection; no need for root signatures, pipeline states, descriptor tables, register indexing, etc.
  • Internal management of descriptor heaps, resource views, memory allocation, etc.
  • "Garbage collection" defers the release of freed resources to ensure the GPU is done with it; you can create and destroy anything at any time without worrying about synchronization.
  • Automatic placement of pipeline barriers and resource transitions.
  • Runtime shader reloading; simply call the gfxKernelReloadAll() function.
  • Basic GPU-based parallel primitives (min/max/sum scans and reductions as well as key-only/key-value pair sorting for various data types).
  • DXR-1.1 raytracing (i.e. using RayQuery<> object); also known as inline raytracing.

On top of gfx.h, three optional layers are available:

  • gfx_imgui.h: adds Dear ImGui support.
  • gfx_scene.h: supports loading .obj files (.gltf coming soon).
  • gfx_window.h: window creation and basic event management.

Usage

Include the header corresponding to the desired level of functionality.

In one .cpp file, define #define GFX_IMPLEMENTATION_DEFINE and include said header to include the implementation details.

Motivation

This project was born mostly out of frustration while researching rendering techniques using explicit APIs such as Direct3D12 or Vulkan.

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

gfx aims to provide an efficient API that's easy to learn, pleasant to use and quick to get things set up, while offering rapid iterations; it allows to get that "start from scratch" efficiency while still offering access to the basic necessary functionality (low-level access to GPU work scheduling, drawing UI overlays, etc.).

Drawing a triangle

Some example code for drawing a simple colored triangle:

// main.cpp

#define GFX_IMPLEMENTATION_DEFINE
#include "gfx_window.h"

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

    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);

    for (auto time = 0.0f; !gfxWindowIsCloseRequested(window); time += 0.1f)
    {
        gfxWindowPumpEvents(window);

        float color[] = { 0.5f * cosf(time) + 0.5f,
                          0.5f * sinf(time) + 0.5f,
                          1.0f };
        gfxProgramSetParameter(gfx, program, "Color", color);

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

        gfxCommandDraw(gfx, 3);

        gfxFrame(gfx);
    }

    gfxDestroyContext(gfx);
    gfxDestroyWindow(window);

    return 0;
}

Here's the corresponding vertex shader:

// triangle.vert

float4 main(float3 pos : Position) : SV_Position
{
    return float4(pos, 1.0f);
}

And pixel shader:

// triangle.frag

float3 Color;

float4 main() : SV_Target
{
    return float4(Color, 1.0f);
}
Owner
Guillaume Boissé
Graphics coder at AMD, previously SIE R&D (PlayStation).
Guillaume Boissé
Comments
  • Pass shader defines in gfxCreate**Kernel

    Pass shader defines in gfxCreate**Kernel

    Hi,

    This seems very trivial but I cannot set the value of a define when passing as compiler argument.

    For example, how would you pass the following define as a createKernelargument?

    #define MYDEFINE 64

  • Going headless

    Going headless

    How? Context creation offers two overloads - one asks for a window handle and the other asks for a D3D device handle. For headless mode, I guess we have to use the second overload using D3D device handle. However, I'm stuck at creating a D3D device.

    I need some something simple: like: getMeADevice(int index), where index represents one of the several GPU adapters in the system. Please let me know!

    As a side note: I can already decouple rendering resolution from display-frame-buffer resolution using custom render-targets or compute-shaders.

  • Add support for non-opaque geometry.

    Add support for non-opaque geometry.

    This sets the opaque flag onto geometry in the spatial structure to improve traversal performance in the case that an objects material does not contain an alpha mask. This enables quickly detecting alpha masked geometry during ray traversal.

    The main changes are that the gltf loader will now not automatically convert images to 4 channel. This allows us to detect which images have an alpha channel in the source and use that to detect non-opaque geometry. The conversion to 4 channel is than moved to gltf.

    The RaytracingPrimitiveBuild functions now take an additional parameter used to signal to the spatial structure whether that object contains opaque or non-opaque geometry by setting the corresponding flag (before this was unset which flags everything as non-opaque)

  • CMakeLists Error - Beginner

    CMakeLists Error - Beginner

    Hi,

    Can I ask if there is any basic tutorial how to build the project using CMakeLists?

    By default I get the following errors on Windows Visual Studio 2019 x64:

    image

  • Using RWByteAddressBuffer and ByteAddressBuffer

    Using RWByteAddressBuffer and ByteAddressBuffer

    Host side:

    byteBuffer = gfxCreateBuffer<uint32_t>(gfx, (nBytes / sizeof(uint32_t) + 1));
    gfxProgramSetParameter(..., .., "byteBufferRW", byteBuffer);
    gfxProgramSetParameter(..., .., "byteBuffer", byteBuffer);
    

    Comp Shader:

    RWByteAddressBuffer byteBufferRW;
    byteBufferRW.Store(idx, value);
    
    ByteAddressBuffer byteBuffer;
    loadVal = byteBuffer.Load(idx);
    

    value and loadVal aren't same. Seems like I am creating the byte addressable buffer wrong?

  • Array of textures

    Array of textures

    Hi,

    I'm trying to do texture mapping using ray-query. Shader side code would look something like this -

    myArrayOfTextures[giveMeMaterialIdx(committedInstanceIndex)].Load(uv)

    As such, I need to create an array-of-textures. Texture2DArrays aren't helpful as all slices must have the same resolution. Any suggestions or alternatives?

  • Simple example how to render a cube and add imgui buttons?

    Simple example how to render a cube and add imgui buttons?

    Hi, your tool/engine looks great, from https://twitter.com/ocornut/status/1371548539046727680 What are the plans for that tool? I realize this is still early on, but I tried to create a simple 'hello world' but couldn't render a simple obj cube (and a ImGUI:Button)

    Could you help? Here is the code:

    #include "gfx_window.h"
    #include "gfx_scene.h"
    #include "gfx_imgui.h"
    
    int main(int argc, char* argv[])
    {
    	GfxWindow window = gfxCreateWindow(1024, 768, "hello gfx");
    	GfxContext context = gfxCreateContext(window);
    	GfxScene scene  = gfxCreateScene();
    	gfxImGuiInitialize(context);
    
    	GfxResult res = gfxSceneImport(scene, "cube.obj");
    	auto cam = gfxSceneCreateCamera(scene);
    	gfxSceneSetActiveCamera(scene, cam);
    	
    	while (!gfxWindowIsCloseRequested(window))
    	{
    		GfxResult res = gfxWindowPumpEvents(window);
    		
    		// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
    		bool key = gfxWindowIsKeyDown(window, 0x42); 
    		if (key)		{			printf("hi!\n");		}
    		
    		gfxFrame(context);
    		
    		gfxImGuiRender();
    		
    		gfxFinish(context);
    
    	}
    
    	gfxSceneClear(scene);
    	gfxDestroyScene(scene);
    	gfxDestroyContext(context);
    	gfxDestroyWindow(window);
    }
    

    Add to CMakeLists.txt

    add_executable(test test.cpp)
    target_link_libraries(test gfx)
    

    cube_obj.zip

  • Dumping textures to file

    Dumping textures to file

    Well, what are my options here?

    I don't see a gfxCommandCopyTextureToBuffer(), but I can copy Gpu-Buffers to Cpu memory and access it for processing.

    Maybe this is an option - copy texture (gpu) to gpu-buffer with a shader, then copy gpu-buffer to mapped cpu-memory?

    Is there a better option?

  • Requesting Non-PBR material support

    Requesting Non-PBR material support

    Is it possible to extend materials to have kd, ks and shininess loaded from .mtl files? Tinyobjloader already loads these properties, just need support from gfx.

    Alternatively, an approximate conversion from non-pbr to pbr would also help. e.g. metallicity = ks / (ks + kd) and roughness = sqrt(sqrt(2 / (2 + shininess))).

  • Fix compilation with msvc c++20.

    Fix compilation with msvc c++20.

    GFX doesnt currently compile when enabling conformance (enabled by default with C++20 ) with msvc compiler. This PR fixes that with 2 changes:

    • Needed this-> added to handle to get it correctly picked up as the class member variable
    • Added std::is_void_v<TYPE> to cause delayed instantiation of default template as otherwise the static_assert will always trigger (The choice of is_void_v is somewhat random as all it needs is some way to delay template evaluation and void type should never occur anyway.
  • Fix light animation

    Fix light animation

    Firstly I changed the delta light transform to point toward the light instead of away (and fixed a bug)

    Then ive updated the animation code as when there are multiple animations the current behavior assigns every detected animated node to every animation. This breaks animations as multiple incorrect animations are applied to each node wrongly attached to it. After spending alot of time digging around trying to understand what was going on I realised my fix is very similar to the one Sylvain did earlier that was reverted. So let me know if this version has any similar issues

  • Providing correct types for sharing constant buffer structures between C++ and HLSL

    Providing correct types for sharing constant buffer structures between C++ and HLSL

    A common pattern for implementing constant buffer is to share a header between C++ and HLSL :

    #ifndef GPU_SHARED_H
    #define GPU_SHARED_H
    
    #ifdef __cplusplus
    
    #include <glm/gtx/type_aligned.hpp>
    #include <glm/gtx/compatibility.hpp>
    
    typedef uint32_t uint;
    
    typedef glm::ivec2 int2;
    typedef glm::ivec4 int4;
    
    typedef glm::uvec2 uint2;
    typedef glm::aligned_uvec3 uint3;
    typedef glm::uvec4 uint4;
    
    typedef glm::aligned_vec4 float4;
    typedef glm::aligned_vec3 float3;
    typedef glm::aligned_vec2 float2;
    
    typedef glm::bool3 bool3;
    
    typedef glm::mat4 float4x4;
    
    #endif // __cplusplus
    
    enum MyEnum
    {
        VALUE1 = 0,
        VALUE2
    };
    
    struct MyContants
    {
        float  attribute0;
        uint   attribute1;
        uint2  attribute2;
        uint   attribute3;
        uint   attribute4;
        MyEnum attribute5;
    };
    
    #endif // GPU_SHARED_H
    

    These typedef declarations are probably wrong :

    • float2 and int2 don't match ?
    • what about bool3 ?
    • ...

    HLSL contant buffer alignment rules aren't obvious, and we still can't use -not_use_legacy_cbuf_load with DXC.

    I propose gfx provide a small set (subset?) of types we can use and arrange freely in constant buffers.

  • gfxBufferSetData

    gfxBufferSetData

    Hi, I would like to update a small buffer from CPU (every frame) and then use it in a compute shader.

    I am not sure how to use buffers with kGfxCpuAccess_Write enabled.

  • Logging

    Logging

    gfx relies a lot on logging to report errors. When developing in Visual Studio or another IDE, we always can read the debug output but when the application is run by Pix or another tool, we can't anymore.

    Ensuring a console is always available would be great.

  • Frame graph

    Frame graph

    gfx_scene.h is of great help for loading assets.

    Some kind of gfx_frame_graph.h would help a lot of managing resources and developing/reusing/sharing render techniques (a set of render passes).

Related tags
GFX Demo for the ESP-IDF
GFX Demo for the ESP-IDF

Display Drivers and Demo for GFX This is a Demo of GFX With Several Display Drivers This is not GFX itself, but it includes it. GFX Documentation is b

Dec 4, 2022
Adafruit GFX compatible arduino library for using cat thermal printers with the ESP32
Adafruit GFX compatible arduino library for using cat thermal printers with the ESP32

CatGFX This library offers a Adafruit GFX "driver" for ESP32 and the cheap cat (or rabbit?) BLE thermal printers like this one: For usage information

Sep 23, 2022
Handcrafted Flutter application well organized and easy to understand and easy to use.

Handcrafted Flutter application well organized and easy to understand and easy to use.

Feb 1, 2022
GraphicsFuzz provides tools for automatically finding and simplifying bugs in graphics drivers, specifically graphics shader compilers.

GraphicsFuzz GraphicsFuzz is a set of tools for testing shader compilers GraphicsFuzz provides tools for automatically finding and simplifying bugs in

Dec 15, 2022
Second life for famous JPEGView - fast and tiny viewer/editor for JPEG, BMP, PNG, WEBP, TGA, GIF and TIFF images with a minimalist GUI and base image processing.
Second life for famous JPEGView - fast and tiny viewer/editor for JPEG, BMP, PNG, WEBP, TGA, GIF and TIFF images with a minimalist GUI and base image processing.

JPEGView-Image-Viewer-and-Editor Updated Dec 07 2021. Version 1.1.1.0 has been released. Download link1, link2 added. Second life for famous JPEGView

Dec 27, 2022
F Graphics Library (FGL) is a small graphics C++ portable library for LCD displays on embedded systems

F Graphics Library (FGL) Full documentation: fgl.docsforge.com (By Filipe Chagas) F Graphics Library is a C++ library that I created for use in embedd

Oct 31, 2022
CSC404: Computer Graphics [CG] & CSL402: Computer Graphics Lab [CG Lab]

COMPUTER-GRAPHICS-AND-COMPUTER-GRAPHICS-LAB CSC404: CG & CSL402: CG LAB [SEMESTER IV] Syllabus CG - Reference Books THE WALL MEGA SATISH - AUTHOR CG C

Apr 28, 2022
Minimalist protocol buffer decoder and encoder in C++

protozero Minimalistic protocol buffer decoder and encoder in C++. Designed for high performance. Suitable for writing zero copy parsers and encoders

Dec 23, 2022
F3D - Fast and minimalist 3D viewer
 F3D - Fast and minimalist 3D viewer

F3D - Fast and minimalist 3D viewer By Michael Migliore and Mathieu Westphal. F3D (pronounced /fɛd/) is a VTK-based 3D viewer following the KISS princ

Jan 9, 2023
isabel - Simple, minimalist note manager.

isabel isabel - Simple, minimalist note manager. Usage Type name and body of note and press Ctrl+s for save note. Press Tab to open notes list. Press

Oct 2, 2021
Legacy stepper motor analyzer - A DYI minimalist hardware stepper motor analyzer with graphical touch screen.
Legacy stepper motor analyzer - A DYI minimalist hardware stepper motor analyzer with graphical touch screen.

Simple Stepper Motor Analyzer NOTE: This is the legacy STM32 based design which was replaced by the single board, Raspberry Pi Pico design at https://

Dec 26, 2022
A Sol-inspired minimalist Lua binding for Zig.
A Sol-inspired minimalist Lua binding for Zig.

zoltan A Sol-inspired minimalist Lua binding for Zig. Features Supports Zig 0.9.0 Lua tables table creation from Zig get/set/create methods possible k

Dec 4, 2022
Reference Implementations of P0267, the proposed 2D graphics API for ISO C++

P0267 Reference Implementation Please read the LICENSE before cloning or forking the code as there is important information there! Please see the wiki

Dec 3, 2022
Rewritten version of the MiniLibX graphics API used by 42, using glfw & glad. Running on OpenGL.
Rewritten version of the MiniLibX graphics API used by 42, using glfw & glad. Running on OpenGL.

Written by W2.Wizard for the 42 Network A recreation of the MiniLibX library used by 42, using GLFW & glad, running on OpenGL. The goal of MLX42 is to

Dec 29, 2022
A small and easy to use neural net implementation for C++. Just download and #include!
A small and easy to use neural net implementation for C++. Just download and #include!

NN++ A short, self-contained, and easy-to-use neural net implementation for C++. It includes the neural net implementation and a Matrix class for basi

Nov 11, 2022
Fast and easy to use, high frequency trading framework for betfair

Hedg Fast and easy to use, high frequency trading framework for betfair About Hedg In the sports trading industry, low latency is really important. Th

Jun 11, 2022
Oct 6, 2021
Open Source Cheat for Apex Legends, designed for ease of use. Made to understand reversing of Apex Legends and respawn's modified source engine as well as their Easy Anti Cheat Implementation.
Open Source Cheat for Apex Legends, designed for ease of use. Made to understand reversing of Apex Legends and respawn's modified source engine as well as their Easy Anti Cheat Implementation.

Apex-Legends-SDK Open Source Cheat for Apex Legends, designed for ease of use. Made to understand reversing of Apex Legends and respawn's modified sou

Jan 8, 2023
MasterPlan is a project management software / visual idea board software. It attempts to be easy to use, lightweight, and fun.
MasterPlan is a project management software / visual idea board software. It attempts to be easy to use, lightweight, and fun.

MasterPlan is a customizeable graphical project management software for independent users or small teams. If you need to share plans across a whole co

Dec 23, 2022