You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JS中调用C函数并基于SDL在Canvas渲染,实现函数持续调用

Emscripten+SDL2模块持续调用C函数的问题解决

问题

我用SDL2结合Emscripten构建了一个渲染到Canvas的模块,需要在SSE事件触发时持续调用C函数set_num传递数据,但目前该函数只能被调用一次。

原因

当前代码把Module.onRuntimeInitialized赋值放在SSE.onmessage回调里,而onRuntimeInitialized是Emscripten模块初始化完成时仅触发一次的回调。第一次收到SSE消息时赋值的回调会在模块初始化后执行一次,但后续收到消息时重新赋值的回调不会再被触发,导致无法继续调用C函数。

解决方案

调整代码逻辑,跟踪模块初始化状态,直接在SSE事件中调用C函数(初始化完成后),同时暂存初始化前的消息避免丢失:

修改后的JavaScript代码:

var Module = {
    canvas: (function () {
        var canvas = document.getElementById('canvas');
        canvas.addEventListener('webglcontextlost', e => {
            alert('WebGL上下文丢失,请重新加载页面。');
            e.preventDefault();
        }, false);
        return canvas;
    })(),
    // 标记模块是否初始化完成
    isInitialized: false,
    // 暂存初始化前收到的消息
    pendingMessages: [],
    onRuntimeInitialized: function() {
        this.isInitialized = true;
        // 处理初始化前积压的消息
        this.pendingMessages.forEach(msg => {
            this.ccall('set_num', null, ['number'], [parseInt(msg.data)]);
        });
        this.pendingMessages = [];
    }
};

SSE.onmessage = msg => {
    // 提取SSE消息中的数字数据(C函数接收int类型)
    const num = parseInt(msg.data);
    if (Module.isInitialized) {
        // 模块已初始化,直接调用C函数
        Module.ccall('set_num', null, ['number'], [num]);
    } else {
        // 模块未初始化,先暂存消息
        Module.pendingMessages.push(msg);
    }
}

关键修改点

  • 给Module添加isInitialized标志位,跟踪初始化状态
  • 新增pendingMessages队列,避免模块初始化前收到的消息丢失
  • onRuntimeInitialized仅在Module定义时赋值一次,初始化完成后处理暂存消息
  • SSE事件回调中根据初始化状态选择直接调用C函数或暂存消息
  • 注意:SSE的msg是MessageEvent对象,实际数据在msg.data属性中,需要转换为整数后传递给C函数

编译配置

override CFLAGS += -std=c11\
                -Os\
                -sUSE_SDL_TTF=2\
                -sUSE_SDL_IMAGE=2\
                -sSDL2_IMAGE_FORMATS=["png"]\
                -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap']\
                -sUSE_SDL=2\
                -sWASM=1\
                -sASSERTIONS\
                --preload-file ./res

C代码

#ifdef __EMSCRIPTEN__
EMSCRIPTEN_KEEPALIVE
#endif
void set_num(int num) { g_obj->num = num; }

内容的提问来源于stack exchange,提问作者nim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 23:05:21