diff --git a/.gitignore b/.gitignore index 06b68a8cd..2cc2749d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /build/ /data/ -/gltf/bin/ +/gltf/bin/gltfpack.wasm diff --git a/Makefile b/Makefile index 5f1553461..fdd25bf6d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ MAKEFLAGS+=-r -j +COMMA=, config=debug files=demo/pirate.obj @@ -23,11 +24,15 @@ CFLAGS=-g -Wall -Wextra -Werror -std=c89 CXXFLAGS=-g -Wall -Wextra -Wshadow -Wno-missing-field-initializers -Werror -std=c++98 LDFLAGS= -WASM_SOURCES=src/vertexcodec.cpp src/indexcodec.cpp src/vertexfilter.cpp -WASM_EXPORTS="__initialize","_sbrk" -WASM_EXPORTS+=,"_meshopt_decodeVertexBuffer","_meshopt_decodeIndexBuffer","_meshopt_decodeIndexSequence" -WASM_EXPORTS+=,"_meshopt_decodeFilterOct","_meshopt_decodeFilterQuat","_meshopt_decodeFilterExp" -WASM_FLAGS=-O3 -DNDEBUG -s EXPORTED_FUNCTIONS='[$(WASM_EXPORTS)]' -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_STACK=24576 -s TOTAL_MEMORY=65536 --no-entry +WASMCC=clang++ +WASI_SDK= + +WASM_SOURCES=src/vertexcodec.cpp src/indexcodec.cpp src/vertexfilter.cpp tools/wasmstubs.cpp +WASM_EXPORTS=meshopt_decodeVertexBuffer meshopt_decodeIndexBuffer meshopt_decodeIndexSequence meshopt_decodeFilterOct meshopt_decodeFilterQuat meshopt_decodeFilterExp sbrk __wasm_call_ctors +WASM_FLAGS=--target=wasm32-wasi --sysroot=$(WASI_SDK) +WASM_FLAGS+=$(patsubst %,-Wl$(COMMA)--export=%,$(WASM_EXPORTS)) +WASM_FLAGS+=-O3 -DNDEBUG -nostartfiles -nostdlib -Wl,--no-entry -Wl,-s +WASM_FLAGS+=-Wl,-z -Wl,stack-size=24576 -Wl,--initial-memory=65536 ifeq ($(config),iphone) IPHONESDK=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk @@ -79,23 +84,22 @@ format: gltfpack: $(GLTFPACK_OBJECTS) $(LIBRARY) $(CXX) $^ $(LDFLAGS) -o $@ -gltfpack.js: gltf/bin/gltfpack.js +gltfpack.wasm: gltf/bin/gltfpack.wasm -gltf/bin/gltfpack.js: ${LIBRARY_SOURCES} ${GLTFPACK_SOURCES} tools/meshloader.cpp - @mkdir -p gltf/bin - emcc $^ -o $@ -Os -DNDEBUG -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s NODERAWFS=1 - sed -i '1s;^;#!/usr/bin/env node\n;' $@ +gltf/bin/gltfpack.wasm: ${LIBRARY_SOURCES} ${GLTFPACK_SOURCES} tools/meshloader.cpp + @mkdir -p gltf/lib + $(WASMCC) $^ -o $@ -Os -DNDEBUG --target=wasm32-wasi --sysroot=$(WASI_SDK) build/decoder_base.wasm: $(WASM_SOURCES) @mkdir -p build - emcc $^ $(WASM_FLAGS) -o $@ + $(WASMCC) $^ $(WASM_FLAGS) -o $@ build/decoder_simd.wasm: $(WASM_SOURCES) @mkdir -p build - emcc $^ $(WASM_FLAGS) -o $@ -msimd128 -mbulk-memory + $(WASMCC) $^ $(WASM_FLAGS) -o $@ -msimd128 -mbulk-memory js/meshopt_decoder.js: build/decoder_base.wasm build/decoder_simd.wasm - sed -i "s#Built with emcc.*#Built with $$(emcc --version | head -n 1)#" $@ + sed -i "s#Built with clang.*#Built with $$($(WASMCC) --version | head -n 1)#" $@ sed -i "s#\(var wasm_base = \)\".*\";#\\1\"$$(cat build/decoder_base.wasm | python3 tools/wasmpack.py)\";#" $@ sed -i "s#\(var wasm_simd = \)\".*\";#\\1\"$$(cat build/decoder_simd.wasm | python3 tools/wasmpack.py)\";#" $@ diff --git a/gltf/bin/gltfpack.js b/gltf/bin/gltfpack.js new file mode 100644 index 000000000..70b25a935 --- /dev/null +++ b/gltf/bin/gltfpack.js @@ -0,0 +1,291 @@ +var fs = require('fs'); +var cp = require('child_process'); + +var WASI_EBADF = 8; +var WASI_EINVAL = 28; +var WASI_EIO = 29; +var WASI_ENOSYS = 52; + +var instance; + +function getHeap() { + return new DataView(instance.exports.memory.buffer); +} + +var fds = { + 0: { fd: 0 }, + 1: { fd: 1 }, + 2: { fd: 2 }, + 3: null // fake fd for directory +}; + +var args = process.argv.slice(1); +var env = Object.keys(process.env).map(function (key) { return key + '=' + process.env[key] }); + +function nextFd() { + for (var i = 0; ; ++i) { + if (fds[i] === undefined) { + return i; + } + } +} + +var wasi = { + proc_exit: function(rval) { + process.exit(rval); + }, + + fd_close: function(fd) { + if (!fds[fd]) { + return WASI_EBADF; + } + + try { + fs.closeSync(fds[fd].fd); + fds[fd] = undefined; + return 0; + } catch (err) { + fds[fd] = undefined; + return WASI_EIO; + } + }, + + fd_fdstat_get: function(fd, stat) { + if (fds[fd] === undefined) { + return WASI_EBADF; + } + + var heap = getHeap(); + heap.setUint8(stat + 0, fds[fd] === null ? 3 : 4); // directory + heap.setUint16(stat + 2, 0, true); + heap.setUint32(stat + 8, 0, true); + heap.setUint32(stat + 12, 0, true); + heap.setUint32(stat + 16, 0, true); + heap.setUint32(stat + 20, 0, true); + return 0; + }, + + path_open32: function(parent_fd, dirflags, path, path_len, oflags, fs_rights_base, fs_rights_inheriting, fdflags, opened_fd) { + if (fds[parent_fd] !== null) { + return WASI_EBADF; + } + + var heap = getHeap(); + + var path_name = Buffer.from(heap.buffer, path, path_len).toString('utf-8'); + var flags = (oflags & 1) ? 'w' : 'r'; + + try { + var real_fd = fs.openSync(path_name, flags); + var stat = fs.fstatSync(real_fd); + + var fd = nextFd(); + fds[fd] = { fd: real_fd, position: 0, size: stat.size }; + + heap.setUint32(opened_fd, fd, true); + return 0; + } catch (err) { + return WASI_EIO; + } + }, + + path_unlink_file: function(parent_fd, path, path_len) { + if (fds[parent_fd] !== null) { + return WASI_EBADF; + } + + var heap = getHeap(); + var path_name = Buffer.from(heap.buffer, path, path_len).toString('utf-8'); + + try { + fs.unlinkSync(path_name); + return 0; + } catch (err) { + return WASI_EIO; + } + }, + + args_sizes_get: function(argc, argv_buf_size) { + var heap = getHeap(); + + var buf_size = 0; + for (var i = 0; i < args.length; ++i) { + buf_size += Buffer.from(args[i], 'utf-8').length + 1; + } + + heap.setUint32(argc, args.length, true); + heap.setUint32(argv_buf_size, buf_size, true); + return 0; + }, + + args_get: function(argv, argv_buf) { + var heap = getHeap(); + var memory = new Uint8Array(heap.buffer); + + var argp = argv_buf; + + for (var i = 0; i < args.length; ++i) { + var item = Buffer.from(args[i], 'utf-8'); + + heap.setUint32(argv + i * 4, argp, true); + item.copy(memory, argp); + heap.setUint8(argp + item.length, 0); + + argp += item.length + 1; + } + + return 0; + }, + + fd_prestat_get: function(fd, buf) { + var heap = getHeap(); + + if (fd == 3) { + heap.setUint8(buf, 0); + heap.setUint32(buf + 4, 0, true); + return 0; + } else { + return WASI_EBADF; + } + }, + + fd_prestat_dir_name: function(fd, path, path_len) { + return 0; + }, + + path_remove_directory: function(parent_fd, path, path_len) { + return WASI_EINVAL; + }, + + environ_sizes_get: function(environc, environ_buf_size) { + var heap = getHeap(); + + var buf_size = 0; + for (var i = 0; i < env.length; ++i) { + buf_size += Buffer.from(env[i], 'utf-8').length + 1; + } + + heap.setUint32(environc, env.length, true); + heap.setUint32(environ_buf_size, buf_size, true); + return 0; + }, + + environ_get: function(environ, environ_buf) { + var heap = getHeap(); + var memory = new Uint8Array(heap.buffer); + + var envp = environ_buf; + + for (var i = 0; i < env.length; ++i) { + var item = Buffer.from(env[i], 'utf-8'); + + heap.setUint32(environ + i * 4, envp, true); + item.copy(memory, envp); + heap.setUint8(envp + item.length, 0); + + envp += item.length + 1; + } + + return 0; + }, + + fd_fdstat_set_flags: function(fd, flags) { + return WASI_ENOSYS; + }, + + fd_seek32: function(fd, offset, whence, newoffset) { + if (!fds[fd]) { + return WASI_EBADF; + } + + var heap = getHeap(); + + switch (whence) { + case 0: + fds[fd].position = offset; + break; + + case 1: + fds[fd].position += offset; + break; + + case 2: + fds[fd].position = fds[fd].size; + break; + + default: + return WASI_EINVAL; + } + + heap.setUint32(newoffset, fds[fd].position, true); + return 0; + }, + + fd_read: function(fd, iovs, iovs_len, nread) { + if (!fds[fd]) { + return WASI_EBADF; + } + + var heap = getHeap(); + var read = 0; + + for (var i = 0; i < iovs_len; ++i) { + var buf = heap.getUint32(iovs + 8 * i + 0, true); + var buf_len = heap.getUint32(iovs + 8 * i + 4, true); + + try { + var readi = fs.readSync(fds[fd].fd, heap, buf, buf_len, fds[fd].position); + + fds[fd].position += readi; + read += readi; + } catch (err) { + return WASI_EIO; + } + } + + heap.setUint32(nread, read, true); + return 0; + }, + + fd_write: function(fd, iovs, iovs_len, nwritten) { + var heap = getHeap(); + var written = 0; + + for (var i = 0; i < iovs_len; ++i) { + var buf = heap.getUint32(iovs + 8 * i + 0, true); + var buf_len = heap.getUint32(iovs + 8 * i + 4, true); + + try { + var writei = fs.writeSync(fds[fd].fd, heap, buf, buf_len, fds[fd].position); + + fds[fd].position += writei; + written += writei; + } catch (err) { + return WASI_EIO; + } + } + + heap.setUint32(nwritten, written, true); + return 0; + }, + + path_readlink: function(fd, path, path_len, buf, buf_len, bufused) { + if (fd !== -1) { + return WASI_ENOSYS; + } + + var heap = getHeap(); + var command = Buffer.from(heap.buffer, path, path_len).toString('utf-8'); + + var ret = cp.spawnSync(command, [], {shell:true}); + return ret.status == null ? 256 : ret.status; + }, +}; + +var wasm = fs.readFileSync(__dirname + '/gltfpack.wasm'); + +WebAssembly.instantiate(wasm, { wasi_snapshot_preview1: wasi }) +.then(function (result) { + instance = result.instance; + instance.exports._start(); +}); diff --git a/gltf/fileio.cpp b/gltf/fileio.cpp index f81f262d3..b820657f1 100644 --- a/gltf/fileio.cpp +++ b/gltf/fileio.cpp @@ -20,9 +20,13 @@ TempFile::TempFile(const char* suffix) path += "\\gltfpack-XXXXXX"; (void)_mktemp(&path[0]); path += suffix; -#elif defined(__EMSCRIPTEN__) - path = "gltfpack-XXXXXX"; - (void)mktemp(&path[0]); +#elif defined(__wasi__) + static int id = 0; + char ids[16]; + sprintf(ids, "%d", id++); + + path = "gltfpack-temp-"; + path += ids; path += suffix; #else path = "/tmp/gltfpack-XXXXXX"; diff --git a/gltf/gltfpack.cpp b/gltf/gltfpack.cpp index d4fb9b444..0169855d5 100644 --- a/gltf/gltfpack.cpp +++ b/gltf/gltfpack.cpp @@ -10,10 +10,6 @@ #include "../src/meshoptimizer.h" -#ifdef __EMSCRIPTEN__ -#include -#endif - std::string getVersion() { char result[32]; diff --git a/gltf/image.cpp b/gltf/image.cpp index ee931d642..ed1ad8118 100644 --- a/gltf/image.cpp +++ b/gltf/image.cpp @@ -5,10 +5,6 @@ #include #include -#ifdef __EMSCRIPTEN__ -#include -#endif - struct BasisSettings { int etc1s_l; @@ -108,23 +104,6 @@ static const char* mimeExtension(const char* mime_type) return ".raw"; } -#ifdef __EMSCRIPTEN__ -EM_JS(int, execute, (const char* cmd, bool ignore_stdout, bool ignore_stderr), { - var cp = require('child_process'); - var stdio = [ 'ignore', ignore_stdout ? 'ignore' : 'inherit', ignore_stderr ? 'ignore' : 'inherit' ]; - var ret = cp.spawnSync(UTF8ToString(cmd), [], {shell:true, stdio:stdio }); - return ret.status == null ? 256 : ret.status; -}); - -EM_JS(const char*, readenv, (const char* name), { - var val = process.env[UTF8ToString(name)]; - if (!val) - return 0; - var ret = _malloc(lengthBytesUTF8(val) + 1); - stringToUTF8(val, ret, lengthBytesUTF8(val) + 1); - return ret; -}); -#else static int execute(const char* cmd_, bool ignore_stdout, bool ignore_stderr) { #ifdef _WIN32 @@ -135,10 +114,12 @@ static int execute(const char* cmd_, bool ignore_stdout, bool ignore_stderr) std::string cmd = cmd_; +#ifndef __wasi__ if (ignore_stdout) (cmd += " >") += ignore; if (ignore_stderr) (cmd += " 2>") += ignore; +#endif return system(cmd.c_str()); } @@ -147,7 +128,6 @@ static const char* readenv(const char* name) { return getenv(name); } -#endif bool checkBasis(bool verbose) { diff --git a/gltf/wasistubs.cpp b/gltf/wasistubs.cpp new file mode 100644 index 000000000..e15c4bf6a --- /dev/null +++ b/gltf/wasistubs.cpp @@ -0,0 +1,52 @@ +#ifdef __wasi__ +#include +#include + +#include + +extern "C" void __cxa_throw(void* ptr, void* type, void* destructor) +{ + abort(); +} + +extern "C" void* __cxa_allocate_exception(size_t thrown_size) +{ + abort(); +} + +__wasi_errno_t __wasi_path_open32(__wasi_fd_t fd, __wasi_lookupflags_t dirflags, const char *path, size_t path_len, __wasi_oflags_t oflags, uint32_t fs_rights_base, uint32_t fs_rights_inherting, __wasi_fdflags_t fdflags, __wasi_fd_t *opened_fd) +__attribute__(( + __import_module__("wasi_snapshot_preview1"), + __import_name__("path_open32"), + __warn_unused_result__ +)); + +__wasi_errno_t __wasi_path_open(__wasi_fd_t fd, __wasi_lookupflags_t dirflags, const char *path, size_t path_len, __wasi_oflags_t oflags, __wasi_rights_t fs_rights_base, __wasi_rights_t fs_rights_inherting, __wasi_fdflags_t fdflags, __wasi_fd_t *opened_fd) +{ + return __wasi_path_open32(fd, dirflags, path, path_len, oflags, fs_rights_base, fs_rights_inherting, fdflags, opened_fd); + +} + +__wasi_errno_t __wasi_fd_seek32(__wasi_fd_t fd, int32_t offset, __wasi_whence_t whence, int32_t *newoffset) + __attribute__(( + __import_module__("wasi_snapshot_preview1"), + __import_name__("fd_seek32"), + __warn_unused_result__ +)); + +__wasi_errno_t __wasi_fd_seek(__wasi_fd_t fd, __wasi_filedelta_t offset, __wasi_whence_t whence, __wasi_filesize_t *newoffset) +{ + int32_t newoffset32 = 0; + __wasi_errno_t result = __wasi_fd_seek32(fd, int32_t(offset), whence, &newoffset32); + *newoffset = newoffset32; + return result; +} + +extern "C" int system(const char* command) +{ + // WASI doesn't provide a system() equivalent; we highjack readlink here, the reasoning being that if we run against a real WASI implementation, + // the effect is more likely to be benign. + return __wasi_path_readlink(-1, command, strlen(command), 0, 0, 0); +} + +#endif diff --git a/js/meshopt_decoder.js b/js/meshopt_decoder.js index 5b697b361..ce5c53ceb 100644 --- a/js/meshopt_decoder.js +++ b/js/meshopt_decoder.js @@ -3,10 +3,10 @@ var MeshoptDecoder = (function() { "use strict"; - // Built with emcc (Emscripten gcc/clang-like replacement) 2.0.4 (3047b77ed244ea8f3cb3ee7b18c0f89079ae6554) + // Built with clang version 11.0.0 (https://github.com/llvm/llvm-project.git 0160ad802e899c2922bc9b29564080c22eb0908c) // Built from meshoptimizer 0.14 - var wasm_base = "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"; - var wasm_simd = "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"; + var wasm_base = "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"; + var wasm_simd = "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"; // Uses bulk-memory and simd extensions var detector = new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,3,2,0,0,5,3,1,0,1,12,1,0,10,22,2,12,0,65,0,65,0,65,0,252,10,0,0,11,7,0,65,0,253,15,26,11]); @@ -28,20 +28,13 @@ var MeshoptDecoder = (function() { console.log("Warning: meshopt_decoder is using experimental SIMD support"); } - var instance, heap; - - var env = { - emscripten_notify_memory_growth: function(index) { - heap = new Uint8Array(instance.exports.memory.buffer); - } - }; + var instance; var promise = - WebAssembly.instantiate(unpack(wasm), { env }) + WebAssembly.instantiate(unpack(wasm), {}) .then(function(result) { instance = result.instance; - instance.exports._initialize(); - env.emscripten_notify_memory_growth(0); + instance.exports.__wasm_call_ctors(); }); function unpack(data) { @@ -62,6 +55,7 @@ var MeshoptDecoder = (function() { var count4 = (count + 3) & ~3; // pad for SIMD filter var tp = sbrk(count4 * size); var sp = sbrk(source.length); + var heap = new Uint8Array(instance.exports.memory.buffer); heap.set(source, sp); var res = fun(tp, count, size, sp, source.length); if (res == 0 && filter) { diff --git a/src/vertexcodec.cpp b/src/vertexcodec.cpp index 5856fe77e..784c9a13d 100644 --- a/src/vertexcodec.cpp +++ b/src/vertexcodec.cpp @@ -447,7 +447,7 @@ static const unsigned char* decodeVertexBlock(const unsigned char* data, const u static unsigned char kDecodeBytesGroupShuffle[256][8]; static unsigned char kDecodeBytesGroupCount[256]; -#ifdef EMSCRIPTEN +#ifdef __wasm__ __attribute__((cold)) // this saves 500 bytes in the output binary - we don't need to vectorize this loop! #endif static bool diff --git a/tools/wasmstubs.cpp b/tools/wasmstubs.cpp new file mode 100644 index 000000000..677a39fde --- /dev/null +++ b/tools/wasmstubs.cpp @@ -0,0 +1,98 @@ +#include +#include + +extern unsigned char __heap_base; +static intptr_t sbrkp = intptr_t(&__heap_base); + +static const int WASM_PAGE_SIZE = 64 * 1024; + +extern "C" void* sbrk(intptr_t increment) +{ + intptr_t sbrko = sbrkp; + + increment = (increment + 3) & ~3; + sbrkp += increment; + + size_t heap_size = __builtin_wasm_memory_size(0) * WASM_PAGE_SIZE; + + if (sbrkp > heap_size) + { + size_t diff = (sbrkp - heap_size + WASM_PAGE_SIZE - 1) / WASM_PAGE_SIZE; + + if (__builtin_wasm_memory_grow(0, diff) == size_t(-1)) + return (void*)-1; + } + + return (void*)sbrko; +} + +extern "C" void* memcpy(void* destination, const void* source, size_t num) +{ + char* d = (char*)destination; + const char* s = (const char*)source; + + if (((uintptr_t(d) | uintptr_t(s)) & 3) == 0) + { + while (num > 15) + { + ((uint32_t*)d)[0] = ((uint32_t*)s)[0]; + ((uint32_t*)d)[1] = ((uint32_t*)s)[1]; + ((uint32_t*)d)[2] = ((uint32_t*)s)[2]; + ((uint32_t*)d)[3] = ((uint32_t*)s)[3]; + d += 16; + s += 16; + num -= 16; + } + + while (num > 3) + { + ((uint32_t*)d)[0] = ((uint32_t*)s)[0]; + d += 4; + s += 4; + num -= 4; + } + } + + while (num > 0) + { + *d++ = *s++; + num--; + } + + return destination; +} + +extern "C" void* memset(void* ptr, int value, size_t num) +{ + uint32_t v32 = ~0u / 255 * uint8_t(value); + + char* d = (char*)ptr; + + if ((uintptr_t(d) & 3) == 0) + { + while (num > 15) + { + ((uint32_t*)d)[0] = v32; + ((uint32_t*)d)[1] = v32; + ((uint32_t*)d)[2] = v32; + ((uint32_t*)d)[3] = v32; + d += 16; + num -= 16; + } + + while (num > 3) + { + ((uint32_t*)d)[0] = v32; + d += 4; + num -= 4; + } + } + + while (num > 0) + { + *d++ = char(value); + num--; + } + + return ptr; +}