From 16e3676b3b3dbac7f02931e3902fea2a6fab1a93 Mon Sep 17 00:00:00 2001 From: Krasner Date: Mon, 22 Jun 2026 03:47:26 +0000 Subject: [PATCH] explicit gpu deallocation --- bindings/c/include/cimg2num.h | 3 +++ bindings/c/src/cimg2num.cpp | 5 +++++ bindings/js/src/wasm_wrapper.c | 2 ++ core/include/img2num.h | 3 +++ core/src/internal/image_to_svg.cpp | 7 +++++++ example-apps/console-c/main.c | 3 +++ example-apps/console-cpp/main.cpp | 3 +++ example-apps/console-js/index.js | 9 +++++++-- packages/js/src/safeWasmWrappers.js | 7 ++++++- packages/js/src/wasmClient.js | 10 +++++++++- packages/js/src/workers/wasmWorker.js | 4 ++-- 11 files changed, 50 insertions(+), 6 deletions(-) diff --git a/bindings/c/include/cimg2num.h b/bindings/c/include/cimg2num.h index ee464aff8..18b27b6b7 100644 --- a/bindings/c/include/cimg2num.h +++ b/bindings/c/include/cimg2num.h @@ -91,6 +91,9 @@ char* img2num_labels_to_svg( char* img2num_image_to_svg( const uint8_t* data, const int width, const int height, const img2num_ImageToSvgConfig* config ); + +void img2num_terminate(); + #ifdef __cplusplus } #endif diff --git a/bindings/c/src/cimg2num.cpp b/bindings/c/src/cimg2num.cpp index 8f74a8636..42787dc37 100644 --- a/bindings/c/src/cimg2num.cpp +++ b/bindings/c/src/cimg2num.cpp @@ -130,4 +130,9 @@ char* img2num_image_to_svg( return result; } + +void img2num_terminate() { + img2num::terminate(); +} + } diff --git a/bindings/js/src/wasm_wrapper.c b/bindings/js/src/wasm_wrapper.c index 3124b2bc6..e70aee7d2 100644 --- a/bindings/js/src/wasm_wrapper.c +++ b/bindings/js/src/wasm_wrapper.c @@ -58,3 +58,5 @@ EMSCRIPTEN_KEEPALIVE char* image_to_svg( return img2num_image_to_svg(data, width, height, &config); } + +EMSCRIPTEN_KEEPALIVE void terminate() { img2num_terminate(); }; diff --git a/core/include/img2num.h b/core/include/img2num.h index f1c46d9b9..00f8951fa 100644 --- a/core/include/img2num.h +++ b/core/include/img2num.h @@ -90,6 +90,9 @@ std::string image_to_svg( const uint8_t* data, const int width, const int height, const ImageToSvgConfig& config ); +/// @copydoc IMG2NUM_H_TERMINATE_DOC +void terminate(); + } // namespace img2num #endif // IMG2NUM_H diff --git a/core/src/internal/image_to_svg.cpp b/core/src/internal/image_to_svg.cpp index 78f9eb252..206463cd3 100644 --- a/core/src/internal/image_to_svg.cpp +++ b/core/src/internal/image_to_svg.cpp @@ -1,4 +1,5 @@ #include "img2num.h" +#include "internal/gpu.h" #include #include @@ -29,4 +30,10 @@ std::string image_to_svg( return svg; } + +void terminate() { + // force deallocation of GPU if hasn't happened automatically + GPU::getClassInstance().~GPU(); +} + } // namespace img2num \ No newline at end of file diff --git a/example-apps/console-c/main.c b/example-apps/console-c/main.c index fde00446c..3f13b52ff 100644 --- a/example-apps/console-c/main.c +++ b/example-apps/console-c/main.c @@ -131,6 +131,9 @@ int main(int argc, char** argv) { } stbi_image_free(image_data_original); + + img2num_terminate(); + free(img_data); free(out_data); free(out_labels); diff --git a/example-apps/console-cpp/main.cpp b/example-apps/console-cpp/main.cpp index 0029f24fb..0c3ccfd39 100644 --- a/example-apps/console-cpp/main.cpp +++ b/example-apps/console-cpp/main.cpp @@ -110,6 +110,9 @@ int main(int argc, char** argv) { } stbi_image_free(image_data_original); + + img2num::terminate(); + delete[] img_data; delete[] out_data; delete[] out_labels; diff --git a/example-apps/console-js/index.js b/example-apps/console-js/index.js index 818ff22fa..688572018 100644 --- a/example-apps/console-js/index.js +++ b/example-apps/console-js/index.js @@ -1,5 +1,5 @@ import { writeFileSync } from "fs"; -import { imageToSvg } from "img2num"; +import { imageToSvg, terminate } from "img2num"; import sharp from "sharp"; const imagePath = process.argv[2]; @@ -23,4 +23,9 @@ const { svg } = await imageToSvg({ pixels, width, height }); writeFileSync("output.svg", svg); console.log("Done! SVG saved to output.svg"); -process.exit(); + +terminate(); + +setImmediate(() => { + process.exit(0); +}); diff --git a/packages/js/src/safeWasmWrappers.js b/packages/js/src/safeWasmWrappers.js index 5c8ae5c5c..705b0757d 100644 --- a/packages/js/src/safeWasmWrappers.js +++ b/packages/js/src/safeWasmWrappers.js @@ -16,7 +16,7 @@ * Each function handles memory management and exposes a JavaScript-friendly API. */ -import { callWasm, initWasmWorker } from "./wasmClient.js"; +import { callWasm, initWasmWorker, terminateWasmWorker } from "./wasmClient.js"; // Ensure worker is ready as soon as this module is imported await initWasmWorker(); //it's an async function as of #433 @@ -240,3 +240,8 @@ export const imageToSvg = async ({ pixels, width, height, sigma_spatial = 3, sig }); return { svg: result.returnValue }; }; + +export const terminate = async () => { + await callWasm({funcName: "terminate"}); + await terminateWasmWorker(); +} \ No newline at end of file diff --git a/packages/js/src/wasmClient.js b/packages/js/src/wasmClient.js index 33264c4e5..450c7d454 100644 --- a/packages/js/src/wasmClient.js +++ b/packages/js/src/wasmClient.js @@ -160,8 +160,16 @@ export async function callWasm({ funcName, args = {}, bufferKeys = [], returnTyp * * @since 0.0.0 */ -export function terminateWasmWorker() { +export async function terminateWasmWorker() { if (!worker) return; + if (__TARGET__ === "node") { + const { initWebGPU, destroyWebGPU } = await import("./target/node/webgpu.js"); + try { + await destroyWebGPU(); + } catch (err) { + console.error(`[Img2Num node/wasmClient.js terminateWasmWorker] Error: ${err}`); + } + } worker.terminate(); // Reject any pending calls before clearing for (const [_id, cb] of callbacks) { diff --git a/packages/js/src/workers/wasmWorker.js b/packages/js/src/workers/wasmWorker.js index 1729021a5..881aa6fab 100644 --- a/packages/js/src/workers/wasmWorker.js +++ b/packages/js/src/workers/wasmWorker.js @@ -234,8 +234,8 @@ if (__TARGET__ === "node") { // (Node passes the raw payload directly, no nested event wrapper needed) parentPort.on("message", async (data) => { await handleMessage(data); - await destroyWebGPU(); - parentPort.close(); + // await destroyWebGPU(); + // parentPort.close(); }); } else { // Browser Worker setup: Standard event-unwrapping listener