MadLadSquad
Contents

The bgfx renderer uses the bgfx library to do rendering operations in an API-agnostic manner.

Testing the bgfx renderer

Building

In your root project directory, clone bgfx.cmake with submodules:

user $ git clone https://github.com/bkaradzic/bgfx.cmake --recursive

Next, in your Config/cmake/UImGuiDemo.cmake, make sure your custom setup and compile steps look like this:

function(custom_setup_step)
    # bgfx.cmake declares these with option(), and CMP0077 makes option() defer to a variable that already
    # exists, so setting them here wins without editing anything inside the bgfx.cmake checkout
    set(BGFX_CONFIG_MULTITHREADED OFF CACHE BOOL "" FORCE)
    set(BGFX_BUILD_TOOLS          OFF CACHE BOOL "" FORCE)
    set(BGFX_BUILD_EXAMPLES       OFF CACHE BOOL "" FORCE)
    set(BGFX_INSTALL              OFF CACHE BOOL "" FORCE)

    add_subdirectory(bgfx.cmake/ EXCLUDE_FROM_ALL)

    if(EMSCRIPTEN)
        # bx.cmake adds -msse4.2 as PUBLIC, which propagates to bimg_encode via
        # its public bx link. That defines __SSE4_1__, causing ProcessRGB.cpp to
        # include <x86intrin.h>, which pulls in ia32intrin.h with non-WASM builtins
        # (RDPMC, WBINVD, EFLAGS, etc.) that have no WebAssembly equivalent.
        # Strip the flag from bx's propagated interface; bx itself retains it in
        # its own COMPILE_OPTIONS for internal SIMD math.
        get_target_property(_bx_iface_opts bx INTERFACE_COMPILE_OPTIONS)
        if(_bx_iface_opts)
            list(REMOVE_ITEM _bx_iface_opts "$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-msse4.2>")
            set_target_properties(bx PROPERTIES INTERFACE_COMPILE_OPTIONS "${_bx_iface_opts}")
        endif()
        target_compile_options(bx PUBLIC -msimd128)
    endif()
endfunction()
 
function(custom_compile_step)
    if (EMSCRIPTEN)
        target_link_libraries(UImGuiDemo bgfx)
    elseif (WIN32)
         target_link_libraries(UntitledImGuiFramework bgfx)
         target_compile_options(UntitledImGuiFramework PRIVATE "/Zc:preprocessor")
    else ()
        target_link_libraries(UImGuiDemoLib bgfx)
    endif ()
    include_directories(bgfx.cmake/bgfx/include bgfx.cmake/bx/include bgfx.cmake/bimg/include)
endfunction()

Caution

BGFX_CONFIG_MULTITHREADED must be OFF. Leaving it enabled will result in nothing being output to the screen, as the example backend code is not written to be used in a multithreaded configuration.

Tip

BGFX_BUILD_TOOLS, BGFX_BUILD_EXAMPLES and BGFX_INSTALL are turned off purely to save build time. The example backend renders dear imgui with the pre-compiled shader blobs in vs_ocornut_imgui.bin.h and fs_ocornut_imgui.bin.h through BGFX_EMBEDDED_SHADER, so shaderc is never needed to build it.

Important

EXCLUDE_FROM_ALL on the add_subdirectory call is what keeps the build to the targets you actually link. Without it, the default all target additionally builds bimg_decode and bimg_encode, which nothing here uses - they exist for the texturec tool and the bgfx examples, both disabled above.

That is not only wasted build time. bimg_decode compiles bimg’s vendored copy of libavif, whose src/io.c uses static_assert without including <assert.h>. static_assert only became a keyword in C23, so on a libc that does not pull assert.h in transitively the way glibc does - notably emscripten’s - the file fails to compile and takes the whole build down with it. Clang builds on macOS hit the same thing.

Integrating the renderer

In Source/Instance.hpp, include the bgfx renderer:

#include <UImGuiRendererExamples/bgfx/bgfx.hpp>

And create an instance of the UImGuiRendererExamples::BGFXRenderer class as a member variable inside the UImGuiDemo::Instance class.

Important

Setting renderer: custom also points the texture backend at the custom slot, because RendererInternal::loadConfig sets textureRendererType from rendererType. If you register a custom renderer without also registering a custom texture, every UImGui::Texture fails with “Invalid custom renderer backend!”. Unless you redirect UImGui::Renderer::data().textureRendererType at one of the built-in backends, follow the “Integrating the custom texture” section below as well.

After that, in Source/Instance.cpp, make sure your constructor looks like this:

UImGuiDemo::Instance::Instance() noexcept
{
    initInfo =
    {
        .titlebarComponents = { reinterpret_cast<UImGui::TitlebarComponent*>(&title) },
        .windowComponents = { reinterpret_cast<UImGui::WindowComponent*>(&demoWindow) },
        .customRenderer = &bgfxRenderer,
        UIMGUI_INIT_INFO_DEFAULT_DIRS,
    };
}

Integrating the custom texture

A custom texture renderer is also provided. To use it, include the following in Source/Instance.hpp:

#include <UImGuiRendererExamples/bgfx/bgfx.hpp>
#include <UImGuiRendererExamples/bgfx/bgfx_texture.hpp>

Create an instance of UImGuiRendererExamples::BGFXTexture as a member variable inside the UImGuiDemo::Instance class and then pass the instance to the init info:

UImGuiDemo::Instance::Instance() noexcept
{
    initInfo =
    {
        .titlebarComponents = { reinterpret_cast<UImGui::TitlebarComponent*>(&title) },
        .windowComponents = { reinterpret_cast<UImGui::WindowComponent*>(&demoWindow) },
        .customRenderer = &bgfxRenderer,
        .customTexture = &bgfxTexture,
        UIMGUI_INIT_INFO_DEFAULT_DIRS,
    };
}

Testing

The example bgfx renderer can run on any operating system that is supported by the framework. It can also be compiled with Emscripten for targeting WASM.