Tutorial 86: The bgfx Renderer: Features and Limitations

CNA — C++ XNA 4.0 reimplementation

What you’ll learn

  • What the BGFX renderer covers today, and where its coverage stops.
  • Enabling it, and how CNA's layer relates to bgfx's own API.
  • When bgfx is the right choice — and when it is not.

Before you startTutorial 72: Choosing a Renderer — this is the detail page behind one entry in that page's middleware group. BGFX is a wrapper around a third-party library, and CNA's coverage of it is narrower than bgfx itself.

bgfx overview — narrower than bgfx itself

Read this before choosing bgfx. The upstream bgfx library supports OpenGL, OpenGL ES, Vulkan, Direct3D and Metal. CNA's embedded stock 3D shaders do not cover all of those: the generator emits variants for bgfx's OpenGL, OpenGL ES and Vulkan renderer types only — there are no Direct3D and no Metal variants. On a platform where bgfx resolves to Direct3D or Metal by default, CNA's 3D shader programs have nothing to load. Set the CNA_BGFX_RENDERER environment variable to pin bgfx to a covered renderer type, or pick a different CNA renderer entirely.

CNA's BGFX renderer wraps bgfx to provide XNA-compatible rendering. It is one of the seven portable middleware renderers, and like the rest of that group it inherits both the portability and the indirection: which native API you end up on is bgfx's decision at runtime, not CNA's at configure time.

Note that bgfx's own Direct3D 11/12 support is bgfx's internal abstraction, not CNA's. CNA separately ships native DIRECTX9, DIRECTX11 and DIRECTX12 renderers (Windows-gated, HLSL compiled at runtime, no bgfx dependency) — see Tutorial 72 if you want a direct Direct3D code path.

Enabling the bgfx renderer

bgfx is pulled in automatically via CMake FetchContent at a pinned commit — you do not need to clone it yourself:

cmake -S . -B build-bgfx \
  -DCNA_GRAPHICS_RENDERER=BGFX \
  -DCMAKE_BUILD_TYPE=Release
cmake --build build-bgfx

# Equivalent option form:
#   -DCNA_RENDERER_BGFX=ON

Do not pass --target CNA: CNA is an interface library with no sources and is not buildable. Build CnaTests, a demo target, or the whole build directory.

What works

  • Full SpriteBatch 2D rendering including rotation, scale, and colour tinting
  • The stock effects — BasicEffect, AlphaTestEffect, DualTextureEffect and friends — on a covered bgfx renderer type
  • VertexBuffer, IndexBuffer, DrawPrimitives and DrawIndexedPrimitives
  • BlendState, DepthStencilState, RasterizerState
  • SamplerState (point, linear, anisotropic)
  • Keyboard, Mouse and GamePad input via SDL3, and SoundEffect audio via SDL3_mixer — both independent of the renderer choice

Where the coverage stops

A custom ShaderEffect is accepted and then silently ignored on bgfx. No exception, no warning, no shader — your draw proceeds without it. This is the single most surprising behaviour on this renderer, and it is unique to it: GDI, METAL, HTML_DOM and SVG_DOM throw instead, which at least tells you. If your game depends on hand-written shaders, bgfx is not a renderer you can ship on. See Tutorial 52.

  • No Direct3D or Metal stock shader variants, as above. Pin bgfx's renderer type with CNA_BGFX_RENDERER if the default resolves to one of those.
  • Cube faces inside a multiple-render-target set are unimplemented. bgfx is one of eight otherwise-3D-capable renderers with this gap (the others being DIRECTX9/11/12, the EasyGL family, SDL_GPU, OPENGL2 and OPENGL4). Plain 2D MRT is fine; see Tutorial 62.
  • Only SurfaceFormat::Color textures can be constructed through bgfx; this family defers to the framework's Color-only public gate.
  • No dedicated bgfx gate. None of alpha.1's 21 workflow files provides renderer-specific build or runtime evidence for this family.

bgfx's own API layer

bgfx has its own API (bgfx::submit, bgfx::setVertexBuffer, and so on) separate from CNA's XNA-style API. CNA's renderer translates XNA calls into bgfx draw calls internally, so you do not need to know bgfx's API to use CNA on it. Reaching into bgfx:: directly from game code is not a supported extension point.

When to use bgfx — and when not to

Use it when you are working on the renderer itself, or when you have verified that your target resolves bgfx to a GL, GLES or Vulkan renderer type and you are not relying on custom shaders.

Do not reach for it as the macOS answer: CNA embeds no Metal shader variants, and macOS is served by the dedicated METAL renderer with automated Apple-runner coverage. Equally, do not choose it for Windows Direct3D — CNA has native Direct3D renderers that are Windows-gated and do not go through bgfx's abstraction. See Tutorial 72.

# CMakeLists.txt for a game on the bgfx renderer.
# The C++ framework has no general install/export package; add the source tree directly.
cmake_minimum_required(VERSION 3.20)
project(MyGame CXX)
set(CMAKE_CXX_STANDARD 23)

set(CNA_GRAPHICS_RENDERER "BGFX" CACHE STRING "CNA renderer")
add_subdirectory(../cna ${CMAKE_BINARY_DIR}/cna)

add_executable(MyGame main.cpp)
target_link_libraries(MyGame PRIVATE CNA)

The selected renderer is visible to your code as a preprocessor define emitted by CNA's own configure — CNA_RENDERER_<NAME>, with the five GL profiles sharing CNA_RENDERER_EASYGL:

#if defined(CNA_RENDERER_BGFX)
    // bgfx cannot execute a custom ShaderEffect — fall back to a stock effect
    // rather than submitting one that would be silently dropped.
    useCustomShader_ = false;
#elif defined(CNA_RENDERER_EASYGL) || defined(CNA_RENDERER_VULKAN)
    useCustomShader_ = true;
#endif