emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.62k stars 3.28k forks source link

Please provide an example of creating a WebGPU program using offscreen canvas and webgpu_cpp.h? #21915

Open xrui94 opened 4 months ago

xrui94 commented 4 months ago

In OpenGL or WebGL, i can create a offscreen canvas app, the code just like:

    ......
void initContextGL()
{
    EmscriptenWebGLContextAttributes attr;
    emscripten_webgl_init_context_attributes(&attr);
    attr.explicitSwapControl = EM_TRUE;
    attr.alpha = 0;
#if MAX_WEBGL_VERSION >= 2
    attr.majorVersion = 2;
#endif
    printf("create context fallback\n");
    attr.proxyContextToMainThread = EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK;//EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK
    attr.renderViaOffscreenBackBuffer = EM_TRUE;
    EMSCRIPTEN_WEBGL_CONTEXT_HANDLE glContext = emscripten_webgl_create_context(g_pHwd, &attr);
    assert(glContext);
    //emscripten_set_canvas_element_size(g_pHwd, 355, 233);
    EMSCRIPTEN_RESULT res=emscripten_webgl_make_context_current(glContext);
    assert(res == EMSCRIPTEN_RESULT_SUCCESS);
    assert(emscripten_webgl_get_current_context() == glContext);

    printf("create context success.\n");
}

void* initRender(void *hWindow)
{ 
......
initContextGL();
......
}

int main(int, char**)
{
if (!emscripten_supports_offscreencanvas())
    {
        printf("Current browser does not support OffscreenCanvas. Skipping the rest of the tests.\n");
#ifdef REPORT_RESULT
        REPORT_RESULT(1);
#endif
        return false;
    }

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    emscripten_pthread_attr_settransferredcanvases(&attr, g_pHwd);
    pthread_t thread;
    printf("Creating thread.\n");
    pthread_create(&thread, &attr, initRender, NULL);
    pthread_detach(thread);
    ......

}

so, i wonder how to create offscreen canvas app? I know there is some ways such as:

    wgpu::SurfaceDescriptorFromCanvasHTMLSelector canvasDesc{};
    canvasDesc.selector = "#canvas";

    wgpu::SurfaceDescriptor surfaceDesc{
            .nextInChain = &canvasDesc
    };
    m_Surface = m_Instance.CreateSurface(&surfaceDesc);

However, how to do it in thread by using offscreenCanvas and WebGPU( webgpu_cpp.h from emscripten )? There is an example?

kripken commented 4 months ago

cc @kainino0x

Diyou commented 3 months ago

Looks like CreateSurface() got broken in 3.1.52 when used in a pthread. It worked in 3.1.51.

HelloTriangle.js:240 TypeError: Cannot read properties of undefined (reading 'getContext')
    at _wgpuInstanceCreateSurface (http://localhost:6931/HelloTriangle.js:10209:24)
    at HelloTriangle.wasm.wgpu::Instance::CreateSurface(wgpu::SurfaceDescriptor const*) const (http://localhost:6931/HelloTriangle.wasm:wasm-function[5898]:0x38c609)
    at invoke_viii (http://localhost:6931/HelloTriangle.js:11034:29)
    at HelloTriangle.wasm.Context@Diyou::From(Window@Diyou const&, std::__2::function<void (Context@Diyou&&)>) (http://localhost:6931/HelloTriangle.wasm:wasm-function[386]:0xc832)
    at invoke_vii (http://localhost:6931/HelloTriangle.js:11023:29)
    at HelloTriangle.wasm.Renderer::CreateFrom(Window@Diyou&&) (http://localhost:6931/HelloTriangle.wasm:wasm-function[371]:0x8fa6)
    at invoke_vi (http://localhost:6931/HelloTriangle.js:11012:29)
    at HelloTriangle.wasm.main (http://localhost:6931/HelloTriangle.wasm:wasm-function[360]:0x781e)
    at HelloTriangle.wasm.__main_void (http://localhost:6931/HelloTriangle.wasm:wasm-function[3569]:0x346864)
    at HelloTriangle.wasm._main_thread (http://localhost:6931/HelloTriangle.wasm:wasm-function[3571]:0x3468fd)
juj commented 5 days ago

While Emscripten WebGPU headers don't yet integrate OffscreenCanvas, this offscreen_canvas.c example (also a variant with pthreads and proxy-to-pthread) shows one approach of how this can be achieved in user projects in context of Wasm Workers or pthreads using a different API.