diff --git a/src/jsifier.mjs b/src/jsifier.mjs index b30a4f8d71b5f..bb916859e5689 100644 --- a/src/jsifier.mjs +++ b/src/jsifier.mjs @@ -288,7 +288,7 @@ function handleI64Signatures(symbol, snippet, sig, i53abi) { const newArgs = []; let argConversions = ''; if (sig.length > argNames.length + 1) { - error(`handleI64Signatures: signature too long for ${symbol}`); + error(`handleI64Signatures: signature '${sig}' too long for ${symbol}(${argNames.join(', ')})`); return snippet; } for (let i = 0; i < argNames.length; i++) { diff --git a/test/test_browser.py b/test/test_browser.py index 5de846338809d..941ffec8ff94f 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -26,6 +26,7 @@ from common import HttpServerThread, requires_dev_dependency from tools import shared from tools import ports +from tools.shared import config from tools.shared import EMCC, WINDOWS, FILE_PACKAGER, PIPE, DEBUG from tools.utils import delete_dir @@ -4454,30 +4455,24 @@ def test_webgl_simple_extensions(self, webgl_version, simple_enable_extensions): self.btest_exit('webgl2_simple_enable_extensions.c', cflags=cmd) @parameterized({ - '': ([],), - 'closure': (['-sASSERTIONS', '--closure=1'],), - 'closure_advanced': (['-sASSERTIONS', '--closure=1', '-O3'],), - 'main_module': (['-sMAIN_MODULE=1'],), + '': (True, []), + 'closure': (True, ['-sASSERTIONS', '--closure=1']), + 'closure_advanced': (True, ['-sASSERTIONS', '--closure=1', '-O3']), + # Not precached with PIC + 'main_module': (False, ['-sMAIN_MODULE=1']), + # Not precached with SHARED_MEMORY + 'pthreads': (False, ['-pthread', '-sOFFSCREENCANVAS_SUPPORT']), }) @requires_webgpu - def test_webgpu_basic_rendering(self, args): - self.btest_exit('webgpu_basic_rendering.cpp', cflags=['-Wno-error=deprecated', '-sUSE_WEBGPU'] + args) + def test_webgpu_basic_rendering(self, assume_precached, args): + if config.FROZEN_CACHE and not assume_precached: + self.skipTest("test doesn't work with frozen cache") + self.btest_exit('webgpu_basic_rendering.cpp', cflags=['--use-port=emdawnwebgpu', '-sEXIT_RUNTIME'] + args) @requires_webgpu def test_webgpu_required_limits(self): - self.btest_exit('webgpu_required_limits.c', cflags=['-Wno-error=deprecated', '-sUSE_WEBGPU', '-sASYNCIFY']) - - @requires_webgpu - def test_webgpu_basic_rendering_pthreads(self): - self.btest_exit('webgpu_basic_rendering.cpp', cflags=['-Wno-error=deprecated', '-sUSE_WEBGPU', '-pthread', '-sOFFSCREENCANVAS_SUPPORT']) - - @requires_webgpu - def test_webgpu_get_device(self): - self.btest_exit('webgpu_get_device.cpp', cflags=['-Wno-error=deprecated', '-sUSE_WEBGPU', '-sASSERTIONS', '--closure=1']) - - @requires_webgpu - def test_webgpu_get_device_pthreads(self): - self.btest_exit('webgpu_get_device.cpp', cflags=['-Wno-error=deprecated', '-sUSE_WEBGPU', '-pthread']) + self.set_setting('DEFAULT_TO_CXX') # emdawnwebgpu uses C++ internally + self.btest_exit('webgpu_required_limits.c', cflags=['--use-port=emdawnwebgpu']) # Tests the feature that shell html page can preallocate the typed array and place it # to Module.buffer before loading the script page. diff --git a/test/test_other.py b/test/test_other.py index 8e01ea79763ce..34cb72c91878a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2586,6 +2586,7 @@ def test_contrib_ports(self): @requires_network def test_remote_ports(self): + self.set_setting('DEFAULT_TO_CXX') # emdawnwebgpu uses C++ internally self.emcc(test_file('hello_world.c'), ['--use-port=emdawnwebgpu']) @crossplatform @@ -9652,13 +9653,15 @@ def test_closure_full_js_library(self, args): @also_with_wasm64 def test_closure_webgpu(self): - # This test can be removed if USE_WEBGPU is later included in INCLUDE_FULL_LIBRARY. + if config.FROZEN_CACHE and self.get_setting('MEMORY64'): + # CI configuration doesn't run `embuilder` with wasm64 on ports + self.skipTest("test doesn't work with frozen cache") + self.set_setting('DEFAULT_TO_CXX') # emdawnwebgpu uses C++ internally self.build('hello_world.c', cflags=[ '--closure=1', '-Werror=closure', - '-Wno-error=deprecated', '-sINCLUDE_FULL_LIBRARY', - '-sUSE_WEBGPU', + '--use-port=emdawnwebgpu', ]) # Tests --closure-args command line flag @@ -12298,16 +12301,8 @@ def test_standalone_syscalls(self): for engine in config.WASM_ENGINES: self.assertContained(expected, self.run_js('test.wasm', engine)) - @parameterized({ - '': ([],), - 'assertions': (['-sASSERTIONS'],), - 'closure': (['-sASSERTIONS', '--closure=1'],), - 'dylink': (['-sMAIN_MODULE'],), - }) - def test_webgpu_compiletest(self, args): - self.run_process([EMXX, test_file('webgpu_jsvalstore.cpp'), '-Wno-error=deprecated', '-sUSE_WEBGPU', '-sASYNCIFY'] + args) - @flaky('https://github.com/emscripten-core/emscripten/issues/25343') + @crossplatform @also_with_wasm64 @parameterized({ '': ([],), @@ -12315,7 +12310,10 @@ def test_webgpu_compiletest(self, args): 'closure_assertions': (['--closure=1', '-Werror=closure', '-sASSERTIONS'],), }) def test_emdawnwebgpu_link_test(self, args): - self.run_process([EMXX, test_file('test_emdawnwebgpu_link_test.cpp'), '--use-port=emdawnwebgpu', '-sASYNCIFY'] + args) + if config.FROZEN_CACHE and self.get_setting('MEMORY64'): + # CI configuration doesn't run `embuilder` with wasm64 on ports + self.skipTest("test doesn't work with frozen cache") + self.emcc(test_file('test_emdawnwebgpu_link_test.cpp'), ['--use-port=emdawnwebgpu', '-sASYNCIFY'] + args) def test_signature_mismatch(self): create_file('a.c', 'void foo(); int main() { foo(); return 0; }') diff --git a/test/webgpu_basic_rendering.cpp b/test/webgpu_basic_rendering.cpp index 7016a1f127f49..f3de907208f2c 100644 --- a/test/webgpu_basic_rendering.cpp +++ b/test/webgpu_basic_rendering.cpp @@ -4,6 +4,8 @@ // found in the LICENSE file. // Based on https://github.com/kainino0x/webgpu-cross-platform-demo +// (specifically on an old version that didn't use Asyncify; here we've +// intentionally kept Asyncify off to have some coverage of that case). #include @@ -16,7 +18,32 @@ #include #include -#include +#include + +EM_JS_DEPS(deps, "$keepRuntimeAlive"); + +// Keeps track of whether async tests are still alive to make sure they finish +// before exit. This tests that keepalives exist where they should. +static int sScopeCount = 0; +class ScopedCounter { + public: + ScopedCounter(const ScopedCounter&&) { Increment(); } + ScopedCounter(const ScopedCounter&) { Increment(); } + ScopedCounter() { Increment(); } + ~ScopedCounter() { Decrement(); } + private: + void Increment() { sScopeCount++; } + void Decrement() { assert(sScopeCount > 0); sScopeCount--; } +}; + +void RegisterCheckScopesAtExit() { + atexit([](){ + // Check we don't exit before the tests are done. + // (Make sure there's a keepalive for everything the test has scopes for.) + // Build with -sRUNTIME_DEBUG to trace keepalives. + assert(sScopeCount == 0); + }); +} static const wgpu::Instance instance = wgpuCreateInstance(nullptr); @@ -39,53 +66,50 @@ static wgpu::Device device; static wgpu::Queue queue; static wgpu::Buffer readbackBuffer; static wgpu::RenderPipeline pipeline; -static int testsCompleted = 0; -void GetAdapter(void (*callback)(wgpu::Adapter)) { - instance.RequestAdapter(nullptr, [](WGPURequestAdapterStatus status, WGPUAdapter cAdapter, const char* message, void* userdata) { - if (message) { - printf("RequestAdapter: %s\n", message); +void GetDevice(void (*callback)()) { + instance.RequestAdapter(nullptr, wgpu::CallbackMode::AllowSpontaneous, [=](wgpu::RequestAdapterStatus status, wgpu::Adapter a, wgpu::StringView message) { + if (message.length) { + printf("RequestAdapter: %.*s\n", int(message.length), message.data); } - assert(status == WGPURequestAdapterStatus_Success); + assert(status == wgpu::RequestAdapterStatus::Success); - wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter); - reinterpret_cast(userdata)(adapter); - }, reinterpret_cast(callback)); -} + wgpu::DeviceDescriptor desc; + desc.SetUncapturedErrorCallback( + [](const wgpu::Device&, wgpu::ErrorType errorType, wgpu::StringView message) { + printf("UncapturedError (type=%d): %.*s\n", errorType, int(message.length), message.data); + }); -void GetDevice(void (*callback)(wgpu::Device)) { - adapter.RequestDevice(nullptr, [](WGPURequestDeviceStatus status, WGPUDevice cDevice, const char* message, void* userdata) { - if (message) { - printf("RequestDevice: %s\n", message); - } - assert(status == WGPURequestDeviceStatus_Success); + adapter = a; + adapter.RequestDevice(&desc, wgpu::CallbackMode::AllowSpontaneous, [=](wgpu::RequestDeviceStatus status, wgpu::Device d, wgpu::StringView message) { + if (message.length) { + printf("RequestDevice: %.*s\n", int(message.length), message.data); + } + assert(status == wgpu::RequestDeviceStatus::Success); - wgpu::Device device = wgpu::Device::Acquire(cDevice); - reinterpret_cast(userdata)(device); - }, reinterpret_cast(callback)); + device = d; + callback(); + }); + }); } void init() { - device.SetUncapturedErrorCallback( - [](WGPUErrorType errorType, const char* message, void*) { - printf("%d: %s\n", errorType, message); - }, nullptr); - queue = device.GetQueue(); wgpu::ShaderModule shaderModule{}; { - wgpu::ShaderModuleWGSLDescriptor wgslDesc{}; + wgpu::ShaderSourceWGSL wgslDesc{}; wgslDesc.code = shaderCode; wgpu::ShaderModuleDescriptor descriptor{}; descriptor.nextInChain = &wgslDesc; shaderModule = device.CreateShaderModule(&descriptor); - shaderModule.GetCompilationInfo([](WGPUCompilationInfoRequestStatus status, const WGPUCompilationInfo* info, void*) { - assert(status == WGPUCompilationInfoRequestStatus_Success); - assert(info->messageCount == 0); - std::printf("Shader compile succeeded\n"); - }, nullptr); + shaderModule.GetCompilationInfo(wgpu::CallbackMode::AllowSpontaneous, + [=](wgpu::CompilationInfoRequestStatus status, const wgpu::CompilationInfo* info) { + assert(status == wgpu::CompilationInfoRequestStatus::Success); + assert(info->messageCount == 0); + printf("Shader compile succeeded\n"); + }); } { @@ -162,41 +186,29 @@ void render(wgpu::TextureView view, wgpu::TextureView depthStencilView) { queue.Submit(1, &commands); } -void issueContentsCheck(const char* functionName, - wgpu::Buffer readbackBuffer, uint32_t expectData) { - struct UserData { - const char* functionName; - wgpu::Buffer readbackBuffer; - uint32_t expectData; - }; - - UserData* userdata = new UserData; - userdata->functionName = functionName; - userdata->readbackBuffer = readbackBuffer; - userdata->expectData = expectData; - +void issueContentsCheck(ScopedCounter scope, std::string functionName, wgpu::Buffer readbackBuffer, uint32_t expectData) { readbackBuffer.MapAsync( - wgpu::MapMode::Read, 0, 4, - [](WGPUBufferMapAsyncStatus status, void* vp_userdata) { - assert(status == WGPUBufferMapAsyncStatus_Success); - std::unique_ptr userdata(reinterpret_cast(vp_userdata)); + wgpu::MapMode::Read, 0, 4, wgpu::CallbackMode::AllowSpontaneous, + [=, scope=scope](wgpu::MapAsyncStatus status, wgpu::StringView message) { + if (message.length) { + printf("readbackBuffer.MapAsync: %.*s\n", int(message.length), message.data); + } + assert(status == wgpu::MapAsyncStatus::Success); - const void* ptr = userdata->readbackBuffer.GetConstMappedRange(); + const void* ptr = readbackBuffer.GetConstMappedRange(); - printf("%s: readback -> %p%s\n", userdata->functionName, + printf("%s: readback -> %p%s\n", functionName.c_str(), ptr, ptr ? "" : " <------- FAILED"); assert(ptr != nullptr); uint32_t readback = static_cast(ptr)[0]; - userdata->readbackBuffer.Unmap(); + readbackBuffer.Unmap(); printf(" got %08x, expected %08x%s\n", - readback, userdata->expectData, - readback == userdata->expectData ? "" : " <------- FAILED"); - - testsCompleted++; - }, userdata); + readback, expectData, + readback == expectData ? "" : " <------- FAILED"); + }); } -void doCopyTestMappedAtCreation(bool useRange) { +void doCopyTestMappedAtCreation(ScopedCounter scope, bool useRange) { static constexpr uint32_t kValue = 0x05060708; size_t size = useRange ? 12 : 4; wgpu::Buffer src; @@ -238,10 +250,10 @@ void doCopyTestMappedAtCreation(bool useRange) { } queue.Submit(1, &commands); - issueContentsCheck(__FUNCTION__, dst, kValue); + issueContentsCheck(scope, __FUNCTION__, dst, kValue); } -void doCopyTestMapAsync(bool useRange) { +void doCopyTestMapAsync(ScopedCounter scope, bool useRange) { static constexpr uint32_t kValue = 0x01020304; size_t size = useRange ? 12 : 4; wgpu::Buffer src; @@ -253,32 +265,23 @@ void doCopyTestMapAsync(bool useRange) { } size_t offset = useRange ? 8 : 0; - struct UserData { - const char* functionName; - bool useRange; - size_t offset; - wgpu::Buffer src; - }; - - UserData* userdata = new UserData; - userdata->functionName = __FUNCTION__; - userdata->useRange = useRange; - userdata->offset = offset; - userdata->src = src; - - src.MapAsync(wgpu::MapMode::Write, offset, 4, - [](WGPUBufferMapAsyncStatus status, void* vp_userdata) { - assert(status == WGPUBufferMapAsyncStatus_Success); - std::unique_ptr userdata(reinterpret_cast(vp_userdata)); - - uint32_t* ptr = static_cast(userdata->useRange ? - userdata->src.GetMappedRange(userdata->offset, 4) : - userdata->src.GetMappedRange()); - printf("%s: getMappedRange -> %p%s\n", userdata->functionName, + std::string functionName = __FUNCTION__; + src.MapAsync( + wgpu::MapMode::Write, offset, 4, wgpu::CallbackMode::AllowSpontaneous, + [=](wgpu::MapAsyncStatus status, wgpu::StringView message) { + if (message.length) { + printf("src.MapAsync: %.*s\n", int(message.length), message.data); + } + assert(status == wgpu::MapAsyncStatus::Success); + + uint32_t* ptr = static_cast(useRange ? + src.GetMappedRange(offset, 4) : + src.GetMappedRange()); + printf("%s: getMappedRange -> %p%s\n", functionName.c_str(), ptr, ptr ? "" : " <------- FAILED"); assert(ptr != nullptr); *ptr = kValue; - userdata->src.Unmap(); + src.Unmap(); wgpu::Buffer dst; { @@ -291,16 +294,16 @@ void doCopyTestMapAsync(bool useRange) { wgpu::CommandBuffer commands; { wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - encoder.CopyBufferToBuffer(userdata->src, userdata->offset, dst, 0, 4); + encoder.CopyBufferToBuffer(src, offset, dst, 0, 4); commands = encoder.Finish(); } queue.Submit(1, &commands); - issueContentsCheck(userdata->functionName, dst, kValue); - }, userdata); + issueContentsCheck(scope, functionName, dst, kValue); + }); } -void doRenderTest() { +void doRenderTest(ScopedCounter scope) { wgpu::Texture readbackTexture; { wgpu::TextureDescriptor descriptor{}; @@ -343,10 +346,10 @@ void doRenderTest() { wgpu::CommandBuffer commands; { wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - wgpu::ImageCopyTexture src{}; + wgpu::TexelCopyTextureInfo src{}; src.texture = readbackTexture; src.origin = {0, 0, 0}; - wgpu::ImageCopyBuffer dst{}; + wgpu::TexelCopyBufferInfo dst{}; dst.buffer = readbackBuffer; dst.layout.bytesPerRow = 256; wgpu::Extent3D extent = {1, 1, 1}; @@ -357,7 +360,7 @@ void doRenderTest() { // Check the color value encoded in the shader makes it out correctly. static const uint32_t expectData = 0xff0080ff; - issueContentsCheck(__FUNCTION__, readbackBuffer, expectData); + issueContentsCheck(scope, __FUNCTION__, readbackBuffer, expectData); } wgpu::Surface surface; @@ -365,33 +368,31 @@ wgpu::TextureView canvasDepthStencilView; const uint32_t kWidth = 300; const uint32_t kHeight = 150; -void frame() { +void frame(void* vp_scope) { + auto scope = std::unique_ptr(reinterpret_cast(vp_scope)); + wgpu::SurfaceTexture surfaceTexture; surface.GetCurrentTexture(&surfaceTexture); wgpu::TextureView backbuffer = surfaceTexture.texture.CreateView(); render(backbuffer, canvasDepthStencilView); - // TODO: Read back from the canvas with drawImage() (or something) and - // check the result. - + // Test should complete when runtime exists after all async work is done. emscripten_cancel_main_loop(); - - // exit(0) (rather than emscripten_force_exit(0)) ensures there is no dangling keepalive. - exit(0); } void run() { init(); - doCopyTestMappedAtCreation(false); - doCopyTestMappedAtCreation(true); - doCopyTestMapAsync(false); - doCopyTestMapAsync(true); - doRenderTest(); + ScopedCounter scope; + doCopyTestMappedAtCreation(scope, false); + doCopyTestMappedAtCreation(scope, true); + doCopyTestMapAsync(scope, false); + doCopyTestMapAsync(scope, true); + doRenderTest(scope); { - wgpu::SurfaceDescriptorFromCanvasHTMLSelector canvasDesc{}; + wgpu::EmscriptenSurfaceSourceCanvasHTMLSelector canvasDesc{}; canvasDesc.selector = "#canvas"; wgpu::SurfaceDescriptor surfDesc{}; @@ -405,9 +406,9 @@ void run() { .device = device, .format = capabilities.formats[0], .usage = wgpu::TextureUsage::RenderAttachment, - .alphaMode = wgpu::CompositeAlphaMode::Auto, .width = kWidth, .height = kHeight, + .alphaMode = wgpu::CompositeAlphaMode::Auto, .presentMode = wgpu::PresentMode::Fifo}; surface.Configure(&config); @@ -419,33 +420,15 @@ void run() { canvasDepthStencilView = device.CreateTexture(&descriptor).CreateView(); } } - emscripten_set_main_loop(frame, 0, false); + + emscripten_set_main_loop_arg(frame, new ScopedCounter(), 0, false); } int main() { - GetAdapter([](wgpu::Adapter a) { - adapter = a; - - wgpu::AdapterInfo info; - adapter.GetInfo(&info); - printf("adapter vendor: %s\n", info.vendor); - printf("adapter architecture: %s\n", info.architecture); - printf("adapter device: %s\n", info.device); - printf("adapter description: %s\n", info.description); - - GetDevice([](wgpu::Device dev) { - device = dev; - run(); - }); - }); + GetDevice(run); - // The test result will be reported when the main_loop completes. - // emscripten_exit_with_live_runtime isn't needed because the WebGPU - // callbacks should all automatically keep the runtime alive until - // emscripten_set_main_loop, and that should keep it alive until - // emscripten_cancel_main_loop. - // - // This code is returned when the runtime exits unless something else sets - // it, like exit(0). - return 99; + RegisterCheckScopesAtExit(); + // This is the return code once all runtime-keepalives have completed + // (unless something crashes before then). + return 0; } diff --git a/test/webgpu_get_device.cpp b/test/webgpu_get_device.cpp deleted file mode 100644 index 80ef054bf3c66..0000000000000 --- a/test/webgpu_get_device.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -int main() { - EM_ASM({ - Module['preinitializedWebGPUDevice'] = { this_is: 'a_dummy_object' }; - }); - emscripten_webgpu_get_device(); -} diff --git a/test/webgpu_jsvalstore.cpp b/test/webgpu_jsvalstore.cpp deleted file mode 100644 index b37f02d1c22ea..0000000000000 --- a/test/webgpu_jsvalstore.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2020 The Emscripten Authors. All rights reserved. -// Emscripten is available under two separate licenses, the MIT license and the -// University of Illinois/NCSA Open Source License. Both these licenses can be -// found in the LICENSE file. - -// Make sure this header exists and compiles -// (webgpu_cpp.h includes webgpu.h so that's tested too). -#include - -#include -#include - -class EmJsHandle { -public: - EmJsHandle() : mHandle(0) {} - EmJsHandle(int handle) : mHandle(handle) {} - ~EmJsHandle() { - if (mHandle != 0) { - emscripten_webgpu_release_js_handle(mHandle); - } - } - - EmJsHandle(const EmJsHandle&) = delete; - EmJsHandle& operator=(const EmJsHandle&) = delete; - - EmJsHandle(EmJsHandle&& rhs) : mHandle(rhs.mHandle) { rhs.mHandle = 0; } - - EmJsHandle& operator=(EmJsHandle&& rhs) { - int tmp = rhs.mHandle; - rhs.mHandle = this->mHandle; - this->mHandle = tmp; - return *this; - } - - int Get() { return mHandle; } - -private: - int mHandle; -}; - -EM_ASYNC_JS(int, init_js_device, (), { - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); - return JsValStore.add(device); -}); - -wgpu::Device init_device() { - EmJsHandle deviceHandle = EmJsHandle(init_js_device()); - wgpu::Device device = wgpu::Device::Acquire(emscripten_webgpu_import_device(deviceHandle.Get())); - return device; -} - -int main() { - wgpu::Device device = init_device(); - - wgpu::BufferDescriptor desc = {}; - desc.size = 4; - desc.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc; - wgpu::Buffer buffer = device.CreateBuffer(&desc); - - EmJsHandle bufferHandle = EmJsHandle(emscripten_webgpu_export_buffer(buffer.Get())); - EM_ASM( - { - const b = JsValStore.get($0); - b.mapAsync(GPUMapMode.WRITE).then(() => { - console.log('Mapping length', b.getMappedRange().byteLength); - b.unmap(); - }); - }, bufferHandle.Get()); - - EmJsHandle deviceHandle = EmJsHandle(emscripten_webgpu_export_device(device.Get())); - EmJsHandle textureHandle = EmJsHandle(EM_ASM_INT( - { - const device = JsValStore.get($0); - const t = device.createTexture({ - size : [ 16, 16 ], - usage : GPUTextureUsage.COPY_DST, - format : 'rgba8unorm', - }); - return JsValStore.add(t); - }, - deviceHandle.Get())); - - EmJsHandle canvasHandle = - EmJsHandle(EM_ASM_INT({ return JsValStore.add(document.createElement('canvas')); })); - EM_ASM( - { - const device = JsValStore.get($0); - const canvas = JsValStore.get($1); - const texture = JsValStore.get($2); - console.log('Copy', canvas, 'to', texture, 'with', device); - }, - deviceHandle.Get(), canvasHandle.Get(), textureHandle.Get()); - -#ifdef REPORT_RESULT - REPORT_RESULT(0); -#endif -} diff --git a/test/webgpu_required_limits.c b/test/webgpu_required_limits.c index 6250cdfc67d80..a3c68d3e9f004 100644 --- a/test/webgpu_required_limits.c +++ b/test/webgpu_required_limits.c @@ -3,12 +3,10 @@ #include #include -WGPUSupportedLimits adapter_supported_limits = { - 0, -}; +static WGPULimits adapter_supported_limits = {0}; -void assertLimitsCompatible(WGPULimits required_limits, - WGPULimits supported_limits) { +static void assertLimitsCompatible(WGPULimits required_limits, + WGPULimits supported_limits) { #define ASSERT_LIMITS_COMPATIBLE(limitName) \ assert(required_limits.limitName == supported_limits.limitName) ASSERT_LIMITS_COMPATIBLE(maxTextureDimension1D); @@ -33,7 +31,6 @@ void assertLimitsCompatible(WGPULimits required_limits, ASSERT_LIMITS_COMPATIBLE(maxBufferSize); ASSERT_LIMITS_COMPATIBLE(maxVertexAttributes); ASSERT_LIMITS_COMPATIBLE(maxVertexBufferArrayStride); - ASSERT_LIMITS_COMPATIBLE(maxInterStageShaderComponents); ASSERT_LIMITS_COMPATIBLE(maxInterStageShaderVariables); ASSERT_LIMITS_COMPATIBLE(maxColorAttachments); ASSERT_LIMITS_COMPATIBLE(maxColorAttachmentBytesPerSample); @@ -46,43 +43,50 @@ void assertLimitsCompatible(WGPULimits required_limits, #undef ASSERT_LIMITS_COMPATIBLE } -void on_device_request_ended(WGPURequestDeviceStatus status, - WGPUDevice device, - char const* message, - void* userdata) { +static void on_device_request_ended(WGPURequestDeviceStatus status, + WGPUDevice device, + WGPUStringView message, + void* userdata1, void* userdata2) { assert(status == WGPURequestDeviceStatus_Success); - WGPUSupportedLimits device_supported_limits; + WGPULimits device_supported_limits = {0}; wgpuDeviceGetLimits(device, &device_supported_limits); // verify that the obtained device fullfils required limits - assertLimitsCompatible(adapter_supported_limits.limits, - device_supported_limits.limits); + assertLimitsCompatible(adapter_supported_limits, + device_supported_limits); + + wgpuDeviceRelease(device); + exit(0); } -void on_adapter_request_ended(WGPURequestAdapterStatus status, - WGPUAdapter adapter, - char const* message, - void* userdata) { +static void on_adapter_request_ended(WGPURequestAdapterStatus status, + WGPUAdapter adapter, + WGPUStringView message, + void* userdata1, void* userdata2) { assert(status == WGPURequestAdapterStatus_Success); wgpuAdapterGetLimits(adapter, &adapter_supported_limits); - // for device limits, require the limits supported by adapter - WGPURequiredLimits device_required_limits = {0,}; - device_required_limits.limits = adapter_supported_limits.limits; + WGPUDeviceDescriptor device_desc = { + // for device limits, require the limits supported by adapter + .requiredLimits = &adapter_supported_limits, + }; + wgpuAdapterRequestDevice(adapter, &device_desc, (WGPURequestDeviceCallbackInfo){ + .mode = WGPUCallbackMode_AllowSpontaneous, + .callback = on_device_request_ended, + }); - WGPUDeviceDescriptor device_desc = {0,}; - device_desc.requiredFeatureCount = 0; - device_desc.requiredLimits = &device_required_limits; - wgpuAdapterRequestDevice(adapter, &device_desc, on_device_request_ended, NULL); + wgpuAdapterRelease(adapter); } int main() { const WGPUInstance instance = wgpuCreateInstance(NULL); - WGPURequestAdapterOptions adapter_options = {0,}; - wgpuInstanceRequestAdapter(instance, &adapter_options, on_adapter_request_ended, NULL); + wgpuInstanceRequestAdapter(instance, NULL, (WGPURequestAdapterCallbackInfo){ + .mode = WGPUCallbackMode_AllowSpontaneous, + .callback = on_adapter_request_ended, + }); // This code is returned when the runtime exits unless something else sets // it, like exit(0). diff --git a/tools/ports/emdawnwebgpu.py b/tools/ports/emdawnwebgpu.py index d0a2c3221ddee..51073d5401179 100644 --- a/tools/ports/emdawnwebgpu.py +++ b/tools/ports/emdawnwebgpu.py @@ -3,7 +3,7 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -# https://dawn.googlesource.com/dawn/+/faa7054b5b65c3ce3774151952a68aa7668aa20b/src/emdawnwebgpu/pkg/README.md +# https://dawn.googlesource.com/dawn/+/01940842b667a7812d0e4ca0ef4367fbec294241/src/emdawnwebgpu/pkg/README.md r""" This "remote port" instructs Emscripten (4.0.10+) how to automatically download the actual port for Emdawnwebgpu. See README below for instructions. @@ -150,14 +150,14 @@ print('Please see documentation inside this file for details on how to use this port.') sys.exit(1) -_VERSION = 'v20250926.144300' +_VERSION = 'v20251002.162335' # Remote-specific port information # - Where to download the port EXTERNAL_PORT = f'https://github.com/google/dawn/releases/download/{_VERSION}/emdawnwebgpu_pkg-{_VERSION}.zip' # - Hash to verify the download integrity -SHA512 = 'a186cf7f33266c9dfeca7d99ffac769a91b2129e34054f1e857cd82e8b033896da34cf758088bbdeeb128aa713df9953851f83ba6d677c438a929d245a789948' +SHA512 = 'ed15672c2c495a77c764929e6979f4e155bf8b9c46dee5b0f234f3208a708bc2b846d89eef345b725d03454b56d549531f48fc84ff2afe7627d14115893b0fb0' # - Path of the port inside the zip file PORT_FILE = 'emdawnwebgpu_pkg/emdawnwebgpu.port.py' @@ -168,7 +168,7 @@ # - Visible in emcc --use-port=emdawnwebgpu:help DESCRIPTION = "Emdawnwebgpu implements webgpu.h on WebGPU, replacing -sUSE_WEBGPU. **For info on usage and filing feedback, see link below.**" -URL = 'https://dawn.googlesource.com/dawn/+/faa7054b5b65c3ce3774151952a68aa7668aa20b/src/emdawnwebgpu/pkg/README.md' +URL = 'https://dawn.googlesource.com/dawn/+/01940842b667a7812d0e4ca0ef4367fbec294241/src/emdawnwebgpu/pkg/README.md' # Emscripten <4.0.10 won't notice EXTERNAL_PORT and will try to use this. @@ -176,5 +176,6 @@ def get(ports, settings, shared): raise Exception('Remote ports require Emscripten 4.0.10+.') +# (Make this look like a port so that the error message above can be hit.) def clear(ports, settings, shared): pass