Eearslya / fastgltf

A blazing fast C++17 glTF library powered by SIMD.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

fastgltf

A superfast SIMD powered glTF 2.0 parser written in C++17 with minimal dependencies. Unlike other glTF parsers, it does not automatically load textures and external buffers to allow the user to optimise to their liking. It does, however, load embedded data and also decodes base64 encoded buffers using high speed SIMD algorithms.

By utilising simdjson, this library can take advantage of SSE4, AVX2, AVX512, and ARM Neon.

Features

fastgltf supports glTF 2.0:

  • glTF JSON files
  • GLB binary files
  • Scenes, nodes, meshes
  • Accessors, buffer views, buffers
  • Materials, textures, images, samplers
  • Animations
  • Skins
  • Cameras
  • Morph targets, sparse accessors
  • Extra data

fastgltf supports a number of glTF extensions:

  • EXT_meshopt_compression
  • EXT_texture_webp
  • KHR_lights_punctual
  • KHR_materials_clearcoat
  • KHR_materials_emissive_strength
  • KHR_materials_ior
  • KHR_materials_iridescence
  • KHR_materials_sheen
  • KHR_materials_specular
  • KHR_materials_transmission
  • KHR_materials_unlit
  • KHR_materials_volume
  • KHR_texture_basisu
  • KHR_texture_transform
  • KHR_mesh_quantization
  • MSFT_texture_dds

fastgltf brings many utilities:

  • SIMD powered base64 buffer decoder
  • Can decompose transform matrices, so you only ever have translation, rotation, and scale.
  • Allows writing directly to mapped GPU buffers for direct uploads, reducing copies.

Usage

fastgltf is built using C++17 and only depends on simdjson, which is downloaded automatically in the CMake script (can be disabled with FASTGLTF_DOWNLOAD_SIMDJSON=OFF). The library is tested on GCC 9, GCC 10, Clang 12, and MSVC 14 (Visual Studio 2022) using CI. The project uses a simple CMake 3.11 script, and can be simply used by adding fastgltf as a subdirectory. Also, fastgltf is available from vcpkg.

Tests and examples are also available and can be built by enabling the respective options, FASTGLTF_ENABLE_TESTS and FASTGLTF_ENABLE_EXAMPLES. fastgltf will then require a few extra dependencies for the test framework, and OpenGL tools, which have to be downloaded by running fetch_test_deps.py.

#include <fastgltf_parser.hpp>
#include <fastgltf_types.hpp>

void load(std::filesystem::path path) {
    // Creates a Parser instance. Optimally, you should reuse this across loads, but don't use it
    // across threads. To enable extensions you have to pass them into the parser's constructor.
    fastgltf::Parser parser;

    // The GltfDataBuffer class is designed for re-usability of the same JSON string. It contains
    // utility functions to load data from a std::filesystem::path, copy from an existing buffer,
    // or re-use an already existing allocation. Note that it has to outlive the process of every
    // parsing function you call.
    fastgltf::GltfDataBuffer data;
    data.loadFromFile(path);

    // This loads the glTF file into the gltf object and parses the JSON. For GLB files, use
    // fastgltf::Parser::loadBinaryGLTF instead.
    auto gltf = parser.loadGLTF(&data, path.parent_path(), fastgltf::Options::None);
    if (parser.getError() != fastgltf::Error::None) {
        // File doesn't exist, couldn't be read, or is not a valid JSON document.
    }

    // With this call to parse you let fastgltf serialize the whole JSON document into the
    // glTF data structures. If desired, you can pass OR'd category enums that will exclude
    // certain glTF aspects from being loaded.
    if (gltf->parse() != fastgltf::Error::None) {
        // Most likely the asset does not follow the glTF spec. Though perhaps fastgltf doesn't
        // handle something correctly, so please let me know.
    }
    
    // Optionally, you can now also call the glTF::validate method. This will more strictly
    // enforce the glTF spec and is not needed most of the time, though I would certainly
    // recommend it in a development environment or when debugging to avoid mishaps.

    // You obtain the asset with this call. This can only be done once, and all successive
    // calls will return a nullptr. The parser and glTF object can be destroyed safely after
    // this call.
    std::unique_ptr<fastgltf::Asset> asset = gltf->getParsedAsset();
}

All the nodes, meshes, buffers, textures, ... can now be accessed through the fastgltf::Asset type. References in between objects are done with a single size_t, which is used to index into the various vectors in the asset. fastgltf heavily utilizes standard containers like std::variant and std::optional to enforce safety for the user.

Performance

In the following chapter I'll show some graphs on how fastgltf compares to the two most used glTF libraries, cgltf and tinygltf. I've disabled loading of images and buffers to only compare the JSON parsing and serialization of the glTF data. I create these graphs using a spreadsheet that you can find here. These numbers were benchmarked using Catch2's benchmark tool on a Ryzen 5800X (with AVX2) with 32GB of RAM using Clang 16, as Clang showed a significant performance improvement over MSVC in every test. I would recommend every Windows developer to use Clang. Visual Studio offers ClangCL as one of the downloadable options.

First of I compared the performance with embedded buffers that are encoded with base64. This uses the 2CylinderEngine asset which contains a 1.7MB embedded buffer. fastgltf includes an optimised base64 decoding algorithm that can take advantage of AVX2, SSE4, and ARM Neon. With this asset, fastgltf is 20.56 times faster than tinygltf using RapidJSON and 6.5 times faster than cgltf.

Amazon's Bistro (converted to glTF 2.0 using Blender) is another excellent test subject, as it's a 148k line long JSON. This shows the raw serialization speed of all the parsers. For this benchmark I used the MinimiseJsonBeforeParsing option that lets fastgltf minimise the JSON before parsing (note that the time it takes to minimise is measured here too). In this case fastgltf is 2.1 times faster than tinygltf and 5.6 times faster than cgltf.

Acknowledgments

The major speedup comes from the awesome simdjson JSON library which can use a multitude of different SIMD intrinsics to increase JSON decoding speed. The library really shows off at massive JSON files, by parsing around 8GB/s.

The SIMD-based base64 decoding algorithms come from Wojciech Muła, which can usually nearly triple the decoding speed with AVX2.

Thanks to https://github.com/komrad36/CRC for some insight into optimising the CRC32-C algorithm and using the SSE4 CRC instructions.

License

The fastgltf library is licensed under the MIT License.


Libraries embedded in fastgltf:

Libraries used in examples and tests:

  • Catch2: Licensed under BSL-1.0.
  • glad: Licensed under MIT.
  • glfw: Licensed under Zlib.
  • glm: Licensed under MIT.

About

A blazing fast C++17 glTF library powered by SIMD.

License:MIT License


Languages

Language:C++ 96.1%Language:CMake 3.2%Language:Python 0.6%