|  | // 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); |