diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 34a9ead..e3b32b6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -71,6 +71,7 @@ jobs: -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ -DBUILD_RUNTIME_BROWSER=ON \ -DBUILD_RUNTIME_NODE=OFF \ + -DPYJS_WEBGPU=ON \ -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DLINK_LIBLZMA=ON \ -DPY_VERSION=$PY_VER \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 868a6f0..2ae2f8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") option(WASM64 "Enable WebAssembly 64-bit support" OFF) +option(PYJS_WEBGPU "Enable WebGPU support (emdawnwebgpu port)" OFF) if (NOT DEFINED PY_VERSION) @@ -219,6 +220,11 @@ target_link_options(pyjs_runtime_browser PUBLIC "SHELL: -lembind" ) +if(PYJS_WEBGPU) + target_compile_options(pyjs_runtime_browser PUBLIC "SHELL: --use-port=emdawnwebgpu") + target_link_options(pyjs_runtime_browser PUBLIC "SHELL: --use-port=emdawnwebgpu") +endif() + # target_link_options(pyjs_runtime_browser PRIVATE # "-sEXPORTED_FUNCTIONS=['_emscripten_dlopen_promise','_dlerror','FS']" diff --git a/tests/atests/async_tests.py b/tests/atests/async_tests.py index b519438..6cb326d 100644 --- a/tests/atests/async_tests.py +++ b/tests/atests/async_tests.py @@ -47,6 +47,48 @@ async def test_callbacks_in_async_2(): assert result == 42 +async def test_js_webgpu(): + + has_webgpu = pyjs.to_py( + pyjs.js.Function( + "return typeof navigator !== 'undefined' && navigator.gpu !== undefined" + )() + ) + assert has_webgpu, "this browser does not expose navigator.gpu" + + async_js_function = pyjs.js.Function( + """ + return async function(){ + const format = navigator.gpu.getPreferredCanvasFormat() + const adapter = await navigator.gpu.requestAdapter() + if (adapter === null){ + return {status: "no adapter", format: format} + } + const device = await adapter.requestDevice() + if (device === null){ + return {status: "no device", format: format} + } + return { + status: "ok", + format: format, + maxComputeWorkgroupSizeX: device.limits.maxComputeWorkgroupSizeX, + } + } + """ + )() + + result = pyjs.to_py(await async_js_function()) + + # no adapter needed to query the preferred canvas format + assert result["format"] in ("bgra8unorm", "rgba8unorm") + + if result["status"] != "ok": + print(f"skip adapter/device part of the browser webgpu test: {result['status']}") + return + + assert result["maxComputeWorkgroupSizeX"] >= 1 + + async def trigger_js_tests(): js_test_path = Path(__file__).parents[1] / "jtests" / "test_main.js"