Chapter 10 · 引擎基础

自定义平台/图形后端

理解 XGE 的后端抽象层,学习如何替换默认的平台后端和图形后端,将引擎嵌入你自己的窗口系统。

10

概念:后端抽象

XGE 将"窗口/事件"和"图形 API"分为两个独立的后端接口。默认使用 Sokol(跨平台窗口)+ OpenGL 3.3(图形)。你可以替换其中任何一个,甚至两个都替换。

典型场景:将 XGE 嵌入已有窗口(如 MFC、Qt)、使用 Vulkan/Metal 替代 OpenGL、在无窗口环境(服务器)中运行。

平台后端接口

typedef struct xge_platform_backend_t {
    int         iType;    // 后端类型标识
    const char* sName;    // 后端名称(调试用)
    int  (*init)(void* pUser);    // 初始化(创建窗口等)
    void (*unit)(void* pUser);    // 销毁
    int  (*poll)(void* pUser);    // 轮询事件(每帧调用)
    void (*present)(void* pUser); // 呈现(SwapBuffers)
    void* pUser;                   // 用户数据
} xge_platform_backend_t;

图形后端接口

typedef struct xge_graphics_backend_t {
    int         iType;    // 后端类型标识
    const char* sName;    // 后端名称
    int  (*init)(void* pUser);  // 初始化 GL 上下文
    void (*unit)(void* pUser);  // 销毁
    int  (*begin)(void* pUser); // 帧开始(MakeCurrent)
    int  (*end)(void* pUser);   // 帧结束
    void* pUser;
} xge_graphics_backend_t;

API 速查

函数说明
xge_platform_backend_t xgePlatformBackendDefault(void)获取默认平台后端(Sokol)
int xgePlatformBackendSet(const xge_platform_backend_t*)设置自定义平台后端(xgeInit 之前)
xge_platform_backend_t xgePlatformBackendGet(void)获取当前平台后端
xge_graphics_backend_t xgeGraphicsBackendDefault(void)获取默认图形后端
int xgeGraphicsBackendSet(const xge_graphics_backend_t*)设置自定义图形后端(xgeInit 之前)
xge_graphics_backend_t xgeGraphicsBackendGet(void)获取当前图形后端

编译本章示例

gcc -O2 -I. -o ch10.exe ch10_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch10.exe

示例:自定义平台后端骨架

#include "xge.h"

// 你的窗口系统(伪代码)
static MyWindow* g_pWindow;

static int myInit(void* pUser) {
    g_pWindow = MyCreateWindow(800, 600, "Custom");
    MyCreateGLContext(g_pWindow);
    return XGE_OK;
}

static void myUnit(void* pUser) {
    MyDestroyWindow(g_pWindow);
}

static int myPoll(void* pUser) {
    // 将你的事件转换为 XGE 事件
    MyEvent e;
    while (MyPollEvent(&e)) {
        // xgeInputEventPost(...); // 推入 XGE 输入事件
    }
    return XGE_OK;
}

static void myPresent(void* pUser) {
    MySwapBuffers(g_pWindow);
}

int main(void) {
    // 在 xgeInit 之前设置自定义后端
    xge_platform_backend_t backend = {0};
    backend.iType   = XGE_PLATFORM_BACKEND_CUSTOM;
    backend.sName   = "MyWindow";
    backend.init    = myInit;
    backend.unit    = myUnit;
    backend.poll    = myPoll;
    backend.present = myPresent;

    xgePlatformBackendSet(&backend);

    // 正常初始化(引擎将使用你的后端)
    xge_desc_t d = {0};
    d.iWidth = 800; d.iHeight = 600;
    xgeInit(&d);
    xgeRun(onFrame, NULL);
    xgeUnit();
    return 0;
}
重要:xgePlatformBackendSet 和 xgeGraphicsBackendSet 必须在 xgeInit 之前调用。初始化后不可更改。

完整代码

本章权威、可运行源码位于 examples/tutorial_capture/ch10_main1.c。它在默认引擎初始化后只读取 xgePlatformBackendGet 和 xgeGraphicsBackendGet,并可视化平台层与图形层的职责;这样可以安全验证当前后端配置。真正调用 xgePlatformBackendSet 或 xgeGraphicsBackendSet 时,必须把设置代码放在 xgeInit 之前,并为目标平台实现完整回调。

后端类型常量

平台后端图形后端
XGE_PLATFORM_BACKEND_NONE (0)XGE_GPU_BACKEND_NONE (0)
XGE_PLATFORM_BACKEND_SOKOL (1)XGE_GPU_BACKEND_OPENGL33 (1)
XGE_PLATFORM_BACKEND_MINIPROGRAM (2)XGE_GPU_BACKEND_GLES30 (2)
XGE_PLATFORM_BACKEND_EGL (3)XGE_GPU_BACKEND_WEBGL2 (3)
XGE_PLATFORM_BACKEND_CUSTOM (100)XGE_GPU_BACKEND_CUSTOM (100)

要点与陷阱

  • 大多数应用不需要自定义后端——默认的 Sokol 后端已覆盖 Win/Mac/Linux/Android/iOS/Web。
  • 自定义后端的责任:你需要自己创建 GL 上下文、管理窗口生命周期、转换输入事件。这是高级用法。
  • poll 返回非 XGE_OK:引擎将终止主循环。可用于在自定义事件循环中检测退出。
  • 图形后端的 begin/end:对应每帧的 MakeCurrent / 释放上下文。多线程渲染时需要特别注意。

进阶练习

  1. 用 xgePlatformBackendGet() 打印当前使用的后端名称。
  2. 实现一个最简自定义平台后端:init 中打印 "Custom init",poll 中计数帧数。
  3. 研究 XGE_PLATFORM_BACKEND_EGL 后端,理解嵌入式 Linux 上的离屏渲染流程。
XGE 平台后端与图形后端关系示例
图:本章权威示例查询当前默认平台与图形后端,并可视化 init/poll/present 与 init/begin/end 的两层职责;替换后端必须发生在 xgeInit 之前。