In some cases we can't quantize the floating point data because the
range of the data is unknown. While it's possible to use
meshopt_quantizeFloat to reduce the precision and gain some compression
back, this is often insufficient and suboptimal.
For inputs that represent a vector in 3D space, such as a position or
scale, a good alternative is to use a shared-exponent encoding - it's a
reasonable assumption that we are content with the same (absolute)
precision in all three components.
To be able to encode in shared exp, we use a modified floating point
like format, where we store a 24-bit signed integer mantissa (without
implicit 1) and a 8-bit exponent. This is less precise than a floating
point number - we lose 1 bit - but we gain an ability to individually
select the exponent and mantissa at any level of desired mantissa
precision. Additionally this moves exponent into a single byte, and
stores the mantissa as a two-complement integer - both of these are much
friendlier for vertex codec than a basic float encoding.
While ideally the shared exponent would be stored just once, this
complicates the SIMD decoding and is actually redundant if the output of
the filter is compressed with vertex encoder *and* a general purpose LZ,
because the stream of exponent bytes will be exactly the same between
all three components.
The resulting decoder runs at ~13 GB/s using WASM SIMD and ~2.5 GB/s
using scalar WASM.
Since both filters can now handle variable bitrate it no longer makes as
much sense to split them. This change consolidates the two
implementations and uses a single templated scalar implementation as
well. This makes gltfpack code a bit simpler as well.
This change switches to using -msimd128 compile flags instead of
-munimplmemented-simd128.
The reason for the switch is that in general, compiling with
-munimplemented-simd128 is asking for trouble, as it may generate
instructions that Chrome doesn't understand yet.
We've been carefully avoiding the issues so far, but at this point
-msimd128 supports all but one (swizzle) instruction that we need.
This change explicitly marks the function chain in vertex codec as using
unimplemented-simd128 (you need to mark the chain to enable inlining),
which generates more or less the same code.
The benefit is that codecbench-simd.js can now be ran in Chrome/v8!
Also switch to emscripten_get_now to get more precise timer than
clock().
make codecbench.wasm now builds a standalone .wasm executable. This
change also disables memory growth to make sure that we have the minimum
number of imports.
This code can be used to benchmark native vs .js implementations of
vertex codec (and, in the future, vertex filters).
Note: right now the SIMD variant of the JS benchmark doesn't run because
compiler generates some instructions that Chrome doesn't support...