| // Copyright 2022 The IREE Authors | |
| // | |
| // Licensed under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // Helpers that prefix logs with the 'name' from DedicatedWorkerGlobalScope. | |
| // This helps with debugging thread creation. | |
| function ireeNamePrefix() { | |
| return self.name ? (self.name + ':') : '(unnamed scope)'; | |
| } | |
| function ireeLog(...args) { | |
| console.log(ireeNamePrefix(), ...args); | |
| } | |
| function ireeError(...args) { | |
| console.error(ireeNamePrefix(), ...args); | |
| } | |
| // TODO(scotttodd): configure this through the build system / scripts? | |
| // TODO(scotttodd): fix multithreading (startup silently fails on some emsdk | |
| // versions, memory growth or high initial memory also req.) | |
| // const MAIN_SCRIPT_URL = 'web-sample-static-multithreaded.js'; | |
| const MAIN_SCRIPT_URL = 'web-sample-static-sync.js'; | |
| let wasmSetupSampleFn; | |
| let wasmCleanupSampleFn; | |
| let wasmRunSampleFn; | |
| let wasmState; | |
| let initialized = false; | |
| const IMAGE_PIXEL_COUNT = 28 * 28; | |
| const imageTypedArray = new Float32Array(IMAGE_PIXEL_COUNT); | |
| let imageBuffer; | |
| var Module = { | |
| print: function(text) { | |
| ireeLog('(C/Wasm) ' + text); | |
| }, | |
| printErr: function(text) { | |
| ireeError('(C/Wasm) ' + text); | |
| }, | |
| onRuntimeInitialized: function() { | |
| ireeLog('WebAssembly module onRuntimeInitialized()'); | |
| wasmSetupSampleFn = Module.cwrap('setup_sample', 'number', []); | |
| wasmCleanupSampleFn = Module.cwrap('cleanup_sample', null, ['number']); | |
| wasmRunSampleFn = | |
| Module.cwrap('run_sample', 'number', ['number', 'number']); | |
| initializeSample(); | |
| }, | |
| mainScriptUrlOrBlob: MAIN_SCRIPT_URL, | |
| noInitialRun: true, | |
| }; | |
| function initializeSample() { | |
| wasmState = wasmSetupSampleFn(); | |
| imageBuffer = | |
| Module._malloc(IMAGE_PIXEL_COUNT * Float32Array.BYTES_PER_ELEMENT); | |
| initialized = true; | |
| postMessage({ | |
| 'messageType': 'initialized', | |
| }); | |
| } | |
| // TODO(scotttodd): call this on page suspend? | |
| function cleanupSample() { | |
| initialized = false; | |
| Module._free(imageDataBuffer); | |
| wasmCleanupSampleFn(); | |
| wasmState = null; | |
| } | |
| // https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97 | |
| // https://developers.google.com/web/updates/2018/03/emscripting-a-c-library#get_an_image_from_javascript_into_wasm | |
| function preprocessImageDataIntoHeap(rawImageData) { | |
| // rawImageData is a Uint8ClampedArray with RGBA image data | |
| // * this MNIST model takes tensor<1x28x28x1xf32> with grayscale pixels | |
| // in [0.0, 1.0] | |
| // This conversion is terrible, but this is a toy demo with a small image | |
| // Hopefully there aren't any logic / iteration order issues... | |
| for (let y = 0; y < 28; ++y) { | |
| for (let x = 0; x < 28; ++x) { | |
| const typedIndex = y * 28 + x; | |
| const rawIndex = 4 * (y * 28 + x) + 3; // Assume colorSpace srgb | |
| imageTypedArray[typedIndex] = rawImageData.data[rawIndex] / 255.0; | |
| } | |
| } | |
| // Copy into Wasm heap. | |
| // Note: we could have done the conversion in-place, but this is demo code | |
| Module.HEAPF32.set(imageTypedArray, imageBuffer >> 2); | |
| } | |
| function handlePredict(id, canvasData) { | |
| if (!initialized) return; | |
| preprocessImageDataIntoHeap(canvasData); | |
| result = wasmRunSampleFn(wasmState, imageBuffer); | |
| if (result == -1) { | |
| postMessage({ | |
| 'messageType': 'predictResult', | |
| 'id': id, | |
| 'error': 'Wasm module error, check console for details', | |
| }); | |
| } else { | |
| postMessage({ | |
| 'messageType': 'predictResult', | |
| 'id': id, | |
| 'payload': result, | |
| }); | |
| } | |
| } | |
| self.onmessage = function(messageEvent) { | |
| const {messageType, id, payload} = messageEvent.data; | |
| if (messageType == 'predict') { | |
| handlePredict(id, payload); | |
| } | |
| }; | |
| ireeLog('iree_worker importing \'' + MAIN_SCRIPT_URL + '\''); | |
| importScripts(MAIN_SCRIPT_URL); |