Tutorial 86: bgfx Backend: Features and Limitations

CNA — C++ XNA 4.0 reimplementation

bgfx overview (full 2D+3D parity, Phase 72)

bgfx is a cross-platform rendering abstraction library that supports OpenGL, Vulkan, Direct3D 11/12, and Metal. CNA's bgfx backend wraps bgfx to provide XNA-compatible rendering. It reached full 2D+3D pixel-verified parity with EasyGL and Vulkan as of this project's Phase 72 — all five stock effects, render targets (MSAA/mip/depth), and all four state classes are real and pixel-tested — with the advantage of bgfx's broad platform reach and Metal support on macOS. Two named gaps remain: custom ShaderEffect source compilation is unsupported (bgfx wants precompiled binary shaders), and OcclusionQuery correctness can't be pixel-verified in this project's CI sandbox (software GL 2.1 driver), though the Begin/End wiring itself is real.

Enabling bgfx backend

# Clone bgfx alongside CNA (sibling directory)
git clone https://github.com/bkaradzic/bgfx.git ../bgfx
git clone https://github.com/bkaradzic/bx.git ../bx
git clone https://github.com/bkaradzic/bimg.git ../bimg

cmake -S . -B build-bgfx \
  -DCNA_GRAPHICS_BACKEND=BGFX \
  -DBGFX_DIR=../bgfx \
  -DCMAKE_BUILD_TYPE=Release
cmake --build build-bgfx -j$(nproc)

What works (basic 3D, SpriteBatch, most effects)

  • Full SpriteBatch 2D rendering including rotation, scale, and color tinting
  • BasicEffect, AlphaTestEffect, DualTextureEffect
  • VertexBuffer, IndexBuffer, and DrawPrimitives / DrawIndexedPrimitives
  • Texture2D (all formats that bgfx supports)
  • RenderTarget2D (basic usage, no MSAA via XNA API)
  • BlendState, DepthStencilState, RasterizerState
  • SamplerState (point, linear, anisotropic)
  • Keyboard, Mouse, GamePad input (via SDL3)
  • SoundEffect / SoundEffectInstance audio (via SDL3_mixer, independent of bgfx)

What's limited

  • Custom ShaderEffect (GLSL/SPIR-V source compilation): unsupported — bgfx wants precompiled binary shaders, so CreateEffectBackend returns nullptr
  • OcclusionQuery: Begin/End wiring is real, but visible-vs-occluded pixel-count correctness can't be pixel-verified under this project's CI sandbox (software GL 2.1 driver, no dedicated-view architecture yet)
  • Wireframe fill mode: not exposed through bgfx's state flags at the CNA level
  • RenderTarget2D MSAA resolve: implemented, but one regression test (Bgfx_RenderTarget2D_MsaaResolve) is a documented pre-existing failure in this project's sandbox specifically (Xvfb has no DRI3 support) — not a code bug

All five stock effects (BasicEffect, AlphaTestEffect, DualTextureEffect, EnvironmentMapEffect, SkinnedEffect) are pixel-tested on bgfx as of Phase 72 — SkinnedEffect and EnvironmentMapEffect are no longer partial.

bgfx's own API layer

bgfx has its own API (bgfx::submit, bgfx::setVertexBuffer, etc.) that is separate from CNA's XNA-style API. CNA's bgfx backend translates XNA calls into bgfx draw calls internally. You do not need to know bgfx's API to use CNA on the bgfx backend, but if you need features not exposed by CNA, you can call bgfx:: functions directly after obtaining the bgfx context from CNA's internal backend handle (not officially supported, use at your own risk).

When to use bgfx

  • macOS with Metal: bgfx supports Metal; EasyGL uses deprecated OpenGL on macOS
  • Windows with Direct3D 11: bgfx can target D3D11 for better Windows compatibility
  • Multi-backend game that needs to run on consoles: bgfx supports PS5/Xbox via NDA platform ports
  • When EasyGL or Vulkan is unavailable on target hardware
# CMakeLists.txt for bgfx backend
cmake_minimum_required(VERSION 3.20)
project(MyGame CXX)
set(CMAKE_CXX_STANDARD 23)

set(CNA_GRAPHICS_BACKEND "BGFX" CACHE STRING "CNA rendering backend")
set(BGFX_DIR "${CMAKE_SOURCE_DIR}/../bgfx" CACHE PATH "bgfx root")

add_subdirectory(../cna ${CMAKE_BINARY_DIR}/cna)

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

Runtime check for backend (bgfx does not expose backend selection at the CNA API level — it is selected at compile time via CMake):

// At runtime you can query which backend was compiled in:
#if defined(CNA_BACKEND_BGFX)
    // bgfx-specific workaround: disable occlusion culling
    useOcclusionQuery_ = false;
#elif defined(CNA_BACKEND_EASYGL)
    useOcclusionQuery_ = true;
#elif defined(CNA_BACKEND_VULKAN)
    useOcclusionQuery_ = true;
#endif