blob: 152c34f93dfacbdd0751f19b7e42a520d81708f6 [file] [log] [blame]
// 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);