XUI 渲染缓存:SELF/SUBTREE/TILED/DISPLAY_LIST/AUTO 策略、状态缓存、自定义渲染回调。
XUI 缓存策略控制控件渲染结果的复用方式:
• NONE (0):不缓存,每帧重绘
• SELF (1):仅缓存自身绘制,子控件仍重绘
• SUBTREE (2):缓存整棵子树(含子控件)
• SUBTREE_TILED (3):子树分块缓存,大控件局部失效
• DISPLAY_LIST (4):录制绘制指令列表,重放无需重新计算
• AUTO (5):引擎自动选择最优策略
缓存命中时跳过绘制,仅做纹理合成,大幅降低 CPU/GPU 开销。
| 函数 | 说明 |
|---|---|
int xuiWidgetSetCachePolicy(pW, pPolicy) | 设置缓存策略 |
xui_cache_policy_t xuiWidgetGetCachePolicy(pW) | 获取策略 |
int xuiWidgetSetCacheRenderCallback(pW, onRender, pUser) | 自定义缓存渲染 |
int xuiWidgetSetCacheStateCount(pW, iCount) | 状态缓存数量 |
int xuiWidgetSetCacheStateId(pW, iIndex, iStateId) | 状态缓存 ID |
gcc -O2 -I. -o ch192.exe ch192_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch192.exe
// 静态面板:子树缓存
xui_cache_policy_t tPolicy = { 0 };
tPolicy.iPolicy = XUI_CACHE_POLICY_SUBTREE;
xuiWidgetSetCachePolicy(pPanel, &tPolicy);
// 按钮:多状态缓存(Normal / Hover / Pressed)
xui_cache_policy_t tBtnPolicy = { 0 };
tBtnPolicy.iPolicy = XUI_CACHE_POLICY_SELF;
xuiWidgetSetCachePolicy(pButton, &tBtnPolicy);
xuiWidgetSetCacheStateCount(pButton, 3);
xuiWidgetSetCacheStateId(pButton, 0, 0 /* 默认态 */);
xuiWidgetSetCacheStateId(pButton, 1, XUI_WIDGET_STATE_HOVER);
xuiWidgetSetCacheStateId(pButton, 2, XUI_WIDGET_STATE_ACTIVE);
// 大画布:分块缓存
xui_cache_policy_t tTilePolicy = { 0 };
tTilePolicy.iPolicy = XUI_CACHE_POLICY_SUBTREE_TILED;
tTilePolicy.iTileSize = 256;
xuiWidgetSetCachePolicy(pCanvas, &tTilePolicy);将以下代码保存为 ch192_main.c,编译后运行即可看到缓存策略对渲染性能的影响:
#include "xge.h"
#include "xui.h"
static xui_context g_pCtx;
static int onFrame(void* pUser) {
(void)pUser;
xgeClear(0x1a1a2e);
xui_vec2_t pos;
xgeMouseGet(&pos.x, &pos.y);
xuiInputPointerMove(g_pCtx, pos.x, pos.y);
if (xgeMouseDown(XGE_MOUSE_LEFT))
xuiInputPointerDown(g_pCtx, pos.x, pos.y, 0);
else
xuiInputPointerUp(g_pCtx, pos.x, pos.y, 0);
xuiUpdate(g_pCtx, xgeGetDelta());
xuiLayout(g_pCtx);
xuiRender(g_pCtx, NULL, NULL, 0);
return XGE_OK;
}
int main(void) {
xge_desc_t d = {0};
d.iWidth = 640; d.iHeight = 480;
d.sTitle = "ch192 - Cache Policy";
d.iFlags = XGE_INIT_VSYNC;
xgeInit(&d);
xuiCreate(&g_pCtx);
extern const xui_proxy_t tXgeProxy;
xui_proxy_t tXgeProxy = xuiProxyXge();
xuiSetProxy(g_pCtx, &tXgeProxy);
xuiSetViewportSize(g_pCtx, 640, 480);
xui_widget pRoot;
xuiPanelCreate(g_pCtx, &pRoot, NULL);
xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 640, 480});
/* 静态面板:子树缓存 */
xui_widget pPanel;
xuiPanelCreate(g_pCtx, &pPanel, NULL);
xuiWidgetAddChild(pRoot, pPanel);
xuiWidgetSetRect(pPanel, (xui_rect_t){40, 40, 260, 200});
xuiWidgetSetRect(pPanel, (xui_rect_t){0, 0, 260, 200});
xui_cache_policy_t tSub = {0};
tSub.iPolicy = XUI_CACHE_POLICY_SUBTREE;
xuiWidgetSetCachePolicy(pPanel, &tSub);
xui_widget pLbl;
xuiLabelCreate(g_pCtx, &pLbl, NULL);
xuiWidgetAddChild(pPanel, pLbl);
xuiLabelSetText(pLbl, "SUBTREE cached panel");
xuiWidgetSetRect(pLbl, (xui_rect_t){20, 20, 220, 32});
xuiWidgetSetRect(pLbl, (xui_rect_t){0, 0, 220, 32});
/* 按钮:多状态缓存 */
xui_widget pBtn;
xuiButtonCreate(g_pCtx, &pBtn, NULL);
xuiWidgetAddChild(pRoot, pBtn);
xuiLabelSetText(pBtn, "State Cached");
xuiWidgetSetRect(pBtn, (xui_rect_t){360, 80, 180, 48});
xuiWidgetSetRect(pBtn, (xui_rect_t){0, 0, 180, 48});
xui_cache_policy_t tSelf = {0};
tSelf.iPolicy = XUI_CACHE_POLICY_SELF;
xuiWidgetSetCachePolicy(pBtn, &tSelf);
xuiWidgetSetCacheStateCount(pBtn, 3);
xuiWidgetSetCacheStateId(pBtn, 0, 0);
xuiWidgetSetCacheStateId(pBtn, 1, XUI_WIDGET_STATE_HOVER);
xuiWidgetSetCacheStateId(pBtn, 2, XUI_WIDGET_STATE_ACTIVE);
/* 信息标签 */
xui_widget pInfo;
xuiLabelCreate(g_pCtx, &pInfo, NULL);
xuiWidgetAddChild(pRoot, pInfo);
xuiLabelSetText(pInfo, "Hover button: state cache switches");
xuiWidgetSetRect(pInfo, (xui_rect_t){340, 160, 260, 32});
xuiWidgetSetRect(pInfo, (xui_rect_t){0, 0, 260, 32});
xgeRun(onFrame, NULL);
xuiDestroy(g_pCtx);
xgeUnit();
return 0;
}