了解 XGE 的多线程渲染架构,学习如何启用独立渲染线程、查询线程能力,以及 EGL 上下文配置。
默认情况下,XGE 在主线程上执行所有操作:事件轮询、逻辑更新、GL 绘制、SwapBuffers。这对大多数应用足够。
但对于高负载场景(大量绘制命令、复杂 Shader),主线程可能被 GPU 提交阻塞。启用渲染线程后,绘制命令的提交和 Present 在独立线程执行,主线程可以更早开始下一帧的逻辑计算。
| 函数 | 说明 |
|---|---|
int xgeRenderThreadSet(int bEnabled) | 启用(1)/ 禁用(0)渲染线程 |
int xgeRenderThreadGet(void) | 查询渲染线程是否启用 |
int xgeRenderThreadCapsGet(xge_render_thread_caps_t* pCaps) | 查询渲染线程能力 |
int xgeRenderThreadEGLSet(const xge_egl_desc_t* pDesc) | 设置渲染线程的 EGL 上下文参数 |
gcc -O2 -I. -o ch19.exe ch19_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch19.exe
typedef struct xge_render_thread_caps_t {
int bSupported; // 平台是否支持渲染线程
int bEnabled; // 当前是否已启用
int bWorkerDrain; // 工作线程是否支持 drain
int bGLContextOwned; // GL 上下文是否由引擎拥有
int bAsyncFlush; // 是否支持异步 flush
int bCanUseWithCurrentContext; // 能否与现有上下文共存
} xge_render_thread_caps_t;typedef struct xge_egl_desc_t {
void* pNativeDisplay; // 原生显示连接
void* pNativeWindow; // 原生窗口句柄
int iWidth; // 缓冲宽度
int iHeight; // 缓冲高度
int bPBuffer; // 使用 PBuffer 离屏
int bSurfaceless; // 无表面模式
int bBoardLinux; // 嵌入式 Linux 标识
void* pUser; // 用户数据
} xge_egl_desc_t;// 先查询平台是否支持
xge_render_thread_caps_t caps = {0};
xgeRenderThreadCapsGet(&caps);
if (caps.bSupported) {
xgeLogWrite(XGE_LOG_INFO, "Render thread supported, enabling...");
xgeRenderThreadSet(1);
} else {
xgeLogWrite(XGE_LOG_WARN, "Render thread not supported on this platform");
}
// 验证状态
int bEnabled = xgeRenderThreadGet(); // 1 = 已启用// 在嵌入式 Linux 上,渲染线程需要独立的 EGL 上下文
xge_egl_desc_t egl = {0};
egl.pNativeDisplay = myDisplay; // EGLDisplay
egl.pNativeWindow = myWindow; // EGLNativeWindowType
egl.iWidth = 1920;
egl.iHeight = 1080;
egl.bPBuffer = 0; // 使用窗口表面
xgeRenderThreadEGLSet(&egl);
xgeRenderThreadSet(1); // 启用// 单线程模式(默认):
// [Main Thread] Poll → Update → Draw → Flush → Present → Sleep
//
// 多线程模式:
// [Main Thread] Poll → Update → Draw(录制命令) → 提交
// [Render Thread] 接收命令 → GL 执行 → Present将以下代码保存为 ch19_main.c,编译后运行即可查询当前平台的渲染线程能力:
#include "xge.h"
static int onFrame(void* pUser) {
(void)pUser;
xgeClear(0x081114FF);
// 绘制简单场景(无论是否启用渲染线程,绘制代码相同)
xgeShapeRectFill(200, 150, 400, 300, 0x1A2A30FF);
xgeShapeCircleFill(400, 300, 80, 0x4FD8C2FF);
return XGE_OK;
}
int main(void) {
// 查询渲染线程能力
xge_render_thread_caps_t caps = {0};
xgeRenderThreadCapsGet(&caps);
xgeLogWrite(XGE_LOG_INFO, "Render thread supported: %d", caps.bSupported);
xgeLogWrite(XGE_LOG_INFO, "Async flush: %d", caps.bAsyncFlush);
// 如果支持则启用
if (caps.bSupported) {
xgeRenderThreadSet(1);
xgeLogWrite(XGE_LOG_INFO, "Render thread enabled");
}
xge_desc_t d = {0};
d.iWidth = 800;
d.iHeight = 600;
d.sTitle = "ch19 - Render Thread";
d.iFlags = XGE_INIT_VSYNC;
xgeInit(&d);
xgeRun(onFrame, NULL);
xgeUnit();
return 0;
}xgeRenderThreadCapsGet(&caps) 查询平台是否支持渲染线程,应在 xgeInit 之前调用。xgeRenderThreadSet(1) 启用渲染线程,绘制命令在独立线程执行。xgeRenderThreadCapsGet。xgeRenderThreadSet 和 xgeRenderThreadEGLSet 应在初始化前调用。bAsyncFlush 的含义,理解命令缓冲区的提交时机。