# How the Equilibrium Engine bgfx_system Bridges ECS and the bgfx Rendering Pipeline

> Discover how the bgfx_system bridges Flecs ECS and the bgfx rendering pipeline. It manages initialization, windowing, and frame submission for GPU context access.

- Repository: [Alexander/equilibriumengine](https://github.com/clibequilibrium/equilibriumengine)
- Tags: internals
- Published: 2026-02-27

---

**The `bgfx_system` acts as the sole bridge between the Flecs ECS world and the low-level bgfx graphics API, handling initialization, platform-specific window binding, resize events, and frame submission while exposing a `Bgfx` component that other rendering systems query to access the GPU context.**

The `bgfx_system` in the [Equilibrium Engine](https://github.com/clibequilibrium/equilibriumengine) cleanly decouples platform-specific graphics initialization from rendering logic. By encapsulating bgfx lifecycle management within a dedicated ECS system, the engine enables data-driven rendering pipelines where subsystems like the forward renderer or PBR system simply query the active context without managing low-level API state.

## Architecture Overview

The `bgfx_system` serves four critical responsibilities in the rendering pipeline:

1. **Initialize bgfx** with platform data, renderer type selection, and debug configuration
2. **Expose a `Bgfx` component** that stores `bgfx_init_t` initialization data and reset flags for every window-owning entity
3. **React to window events** (creation and resize) to synchronize swap-chain dimensions and view rectangles
4. **Advance the frame** at the end of each render pass via `bgfx_frame()`

Other rendering subsystems—including `forward_renderer_system`, `pbr_system`, and `light_system`—query this `Bgfx` component to obtain the active context and utilize helper functions in [`bgfx_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/bgfx_utils.h) for creating textures, shaders, and buffers.

## Initialization and Platform Setup

### Component Definition

The `Bgfx` component defined in [`equilibrium/components/bgfx_components.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/bgfx_components.h) stores the initialization state required by all rendering systems:

```c
// equilibrium/components/bgfx_components.h#L7-L11
typedef struct Bgfx {
    bgfx_init_t data;
    uint32_t reset;  // Flags used when calling bgfx_reset()
} Bgfx;

```

This component is attached to any entity possessing a **Renderer**, **AppWindow**, and **AppWindowHandle**, ensuring that each window context maintains its own bgfx configuration.

### Platform Data Configuration

Before bgfx can initialize, the system must extract native window handles using SDL-SysWM. The `SetPlatformData` function in [`equilibrium/systems/bgfx_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/systems/bgfx_system.c) (lines 16-46) populates `bgfx_platform_data_t` with platform-specific handles (`ndt` for display connection, `nwh` for native window handle) across Linux, macOS, and Windows.

```c
// Simplified excerpt from SetPlatformData
bgfx_platform_data_t pd;
pd.nwh = GetNativeWindowHandle(window);  // Platform-specific extraction
pd.ndt = GetNativeDisplayType();         // Required for X11/Wayland
bgfx_set_platform_data(&pd);

```

### Initialization Observer

The `BgfxInitialize` observer triggers on `EcsOnSet` when the prerequisite components (Renderer, AppWindow, AppWindowHandle) are present and the entity lacks a `Bgfx` component. Implemented in [`equilibrium/systems/bgfx_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/systems/bgfx_system.c) (lines 48-82), this function:

1. Calls `SetPlatformData` to bind the native window
2. Selects the renderer type (e.g., Vulkan, Metal, DirectX 11/12)
3. Invokes `bgfx_init()` to create the context
4. Configures the default view with profiling and quality settings

```c
// equilibrium/systems/bgfx_system.c#L70-L78
bgfx_set_debug(BGFX_DEBUG_PROFILER);
uint32_t reset = BGFX_RESET_MAXANISOTROPY | BGFX_RESET_MSAA_X16;
bgfx_reset(app_window->width, app_window->height, reset, format);
bgfx_set_view_clear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x000000ff, 1.0f, 0);
bgfx_set_view_rect(0, 0, 0, app_window->width, app_window->height);

```

The system then stores the initialized `Bgfx` component on the entity, making the context available to downstream systems.

## Runtime Pipeline Integration

### Frame Advancement

At the end of every render frame, the `BgfxEndRender` system—registered in `BgfxSystemImport`—executes on the `OnEndRender` phase. This system simply calls `bgfx_frame(false)` to submit all queued draw calls to the GPU:

```c
// equilibrium/systems/bgfx_system.c#L85-L89
static void BgfxEndRender(ecs_iter_t *it) {
    (void)it;
    bgfx_frame(false);
}

```

### Window Resize Handling

When window dimensions change, the `OnAppWindowResized` observer (lines 91-99) detects the `EcsOnSet` event for `AppWindow` and `Bgfx` components, invoking `bgfx_reset()` with updated width, height, and the stored reset flags from the `Bgfx` component:

```c
// equilibrium/systems/bgfx_system.c#L91-L99
static void OnAppWindowResized(ecs_iter_t *it) {
    // ... field extraction ...
    bgfx_reset(width, height, bgfx->reset, BGFX_TEXTURE_FORMAT_COUNT);
    bgfx_set_view_rect(0, 0, 0, width, height);
}

```

## Interfacing with Rendering Subsystems

### Forward Renderer Integration

The `forward_renderer_system` relies entirely on the view rectangle and context established by `bgfx_system`. In [`equilibrium/systems/rendering/forward_renderer_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/systems/rendering/forward_renderer_system.c) (lines 34-53), the `ForwardRendererBeginFrame` function queries window dimensions from the `AppWindow` component and configures its view using the pre-initialized bgfx context:

```c
// forward_renderer_system.c example usage
bgfx_set_view_rect(default_view, 0, 0, 
                   app_window[i].width, 
                   app_window[i].height);

```

This works because `bgfx_system` has already validated the context and set default view parameters before any rendering systems execute.

### PBR and Resource Management

The PBR system ([`pbr_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/pbr_system.c)) creates shader programs using the `create_program` macro defined in [`equilibrium/utils/bgfx_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/bgfx_utils.h) (lines 47-66). While this macro handles shader compilation and hot-reload registration via the `HotReloadableShader` component, the actual GPU submission (`bgfx_submit`) assumes the view and context initialized by `bgfx_system`.

The **GfxResource system** ([`gfx_resource_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/gfx_resource_system.c)) complements this by destroying bgfx handles when components are removed, but it never reinitializes the API—that remains the exclusive domain of `bgfx_system`.

## Practical Implementation Example

To add a custom rendering pass that interfaces with the `bgfx_system` pipeline, import the module and rely on the pre-initialized context:

```c
#include "bgfx_system.h"
#include "utils/bgfx_utils.h"
#include "components/renderer/renderer_components.h"
#include "flecs.h"

static bgfx_view_id_t custom_view = 2;

static void CustomPassInit(ecs_iter_t *it) {
    FrameData *fd = ecs_field(it, FrameData, 1);
    for (int i = 0; i < it->count; ++i) {
        if (!BGFX_HANDLE_IS_VALID(fd[i].frame_buffer))
            continue;

        bgfx_set_view_name(custom_view, "Custom pass");
        bgfx_set_view_clear(custom_view, BGFX_CLEAR_COLOR, 0x0000FF00, 1.0f, 0);
        bgfx_set_view_rect(custom_view, 0, 0, 
                           fd[i].frame_buffer_width,
                           fd[i].frame_buffer_height);
        bgfx_set_view_frame_buffer(custom_view, fd[i].frame_buffer);
        bgfx_touch(custom_view);
    }
}

static void CustomPassDraw(ecs_iter_t *it) {
    FrameData *fd = ecs_field(it, FrameData, 1);
    for (int i = 0; i < it->count; ++i) {
        bgfx_set_texture(0, fd[i].debug_texture_uniform,
                         fd[i].debug_texture, UINT32_MAX);
        bgfx_submit(custom_view, fd[i].debug_program, 0, BGFX_DISCARD_ALL);
    }
}

void CustomPassSystemImport(world_t *world) {
    ECS_MODULE(world, CustomPassSystem);
    ECS_IMPORT(world, RendererComponents);
    ECS_IMPORT(world, BgfxSystem);  // Guarantees bgfx initialization
    ECS_SYSTEM(world, CustomPassInit, OnBeginRender,
                renderer.components.FrameData);
    ECS_SYSTEM(world, CustomPassDraw, OnRender,
                renderer.components.FrameData);
}

```

**Key integration points:**

- **Import `BgfxSystem`** to ensure `bgfx_init()` completes before your system runs
- **Reuse view IDs** or claim unused ones (view 0 is reserved by the system)
- **Use [`bgfx_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/bgfx_utils.h) helpers** for resource creation to maintain hot-reload compatibility

## Summary

- The `bgfx_system` encapsulates all platform-specific bgfx initialization in [`equilibrium/systems/bgfx_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/systems/bgfx_system.c), creating a clean separation between ECS logic and graphics API setup.
- The **`Bgfx` component** stores `bgfx_init_t` and reset flags, allowing multiple window contexts to coexist while providing a queryable interface for rendering subsystems.
- **Lifecycle observers** (`BgfxInitialize`, `OnAppWindowResized`) handle context creation and dynamic resize events automatically when window components change.
- **Frame advancement** occurs via `BgfxEndRender` on the `OnEndRender` phase, ensuring all rendering systems complete before GPU submission.
- Downstream systems (forward renderer, PBR, lights) depend on the `BgfxSystem` module but never directly manage the API context, enabling fully data-driven rendering pipelines.

## Frequently Asked Questions

### Where is the bgfx initialization struct stored in the ECS?

The initialization struct is stored in the **`Bgfx` component** defined in [`equilibrium/components/bgfx_components.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/bgfx_components.h). This component contains a `bgfx_init_t data` field and a `uint32_t reset` field for resize flags, and it is attached to any entity that has a Renderer, AppWindow, and AppWindowHandle present.

### How does the engine handle window resizing with bgfx?

The `OnAppWindowResized` observer in [`equilibrium/systems/bgfx_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/systems/bgfx_system.c) detects changes to the `AppWindow` component and automatically calls `bgfx_reset()` with the new dimensions and the stored reset flags (such as `BGFX_RESET_MSAA_X16`), then updates the view rectangle to match the new window size.

### Can multiple rendering systems use the same bgfx context?

Yes. All rendering subsystems—including the forward renderer, deferred renderer, and PBR system—query the same `Bgfx` component created by `bgfx_system`. They use helper functions from [`equilibrium/utils/bgfx_utils.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/utils/bgfx_utils.h) to create resources, but share the single initialized context per window entity.

### What happens if I forget to import BgfxSystem in a custom renderer?

If you omit `ECS_IMPORT(world, BgfxSystem)`, your system may attempt to call bgfx functions before `bgfx_init()` has executed, resulting in undefined behavior or crashes. Always import the module to ensure the `BgfxInitialize` observer runs first and validates the platform data.