Skip to content

mitsuba-renderer/struct-jit

Repository files navigation

Struct-JIT

This small self-contained library facilitates efficient conversion from one kind of structured representation to another. The need for this frequently arises when dealing with visual information including images or 3D meshes. For example, consider the following data structures describing positions tagged with color.

struct Source { // <-- Big endian! :(
   uint8_t r, g, b; // in sRGB
   half x, y, z;
};

struct Target { // <-- Little endian!
   float x, y, z;
   float r, g, b, a; // in linear space
};

const size_t size = /* huge number */;
Source input[size];
Target output[size];

convert(input, output, size); // <-- Struct-JIT efficiently performs this step

In this example, conversion would involve endianness conversion, reordering, type conversion, dealing with gamma vs linear encoding, and even inserting extra fields with a default value (e.g. alpha channel).

While hard-coding such a conversion for a specific type of input and output is easy, things quickly become messy when the format of the input data structure Source only becomes known at runtime. This is where Struct-JIT shines: it generates efficient code to perform the desired conversion on the fly.

Features

Struct-JIT deals with

  • Reordering: input and output fields can be at arbitrary offsets.
  • Format conversion: the library can load and save various numeric representations (signed/unsigned 8-64 bit integers, half/single/double precision floats).
  • Endianness conversion: supported on both input and output end.
  • Gamma correction (sRGB curve): can be applied or removed.
  • Defaults: can substitute missing values with specified defaults.
  • Dithering: can apply dithering to avoid banding artifacts when producing output with low bit depth (e.g. 8 bit).
  • Checks: can check that certain entries have specified default values.
  • Weighting: a field can store an accumulation weight; converting to an un-weighted structure divides the remaining fields by it.
  • Alpha: can convert between premultiplied and non-premultiplied alpha.
  • Blending: an output field can be a weighted linear combination of several input fields.

The library provides C++ and Python (optional) interfaces to all functionality.

Just-in-time compilation

The above operations can be arranged in countless ways, which makes it hard to provide an efficient generic implementation of this functionality. For this reason, the implementation of this class relies on a JIT compiler that generates fast specialized conversion code for each specific conversion task. Generated kernels are cached in memory and reused. The JIT targets the two most widely architectures, specifically x86_64 (Haswell or newer, for FMA) and aarch64.

Due to the basic nature of the task, the JIT compiler admits a particularly simple and fast implementation that merely copies and pastes pre-compiled snippets to assemble the final conversion function.

Applications that repeatedly encounter the same runtime layouts can use the shared converter cache instead of constructing converters each time:

Converter &converter = make_converter(source_struct, target_struct);
converter.convert(input, output, width, height);

Cache lookups and mutation are mutex-protected. Returned converter references remain valid until clear_cache() is called, so callers should not clear the shared cache while another thread may still use a previously returned converter.

Finally, a slow software emulation mode is also available. Its main application is to validate the JIT implementation in testcases.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors