Spark 1.4

I’m excited to announce the release of Spark 1.4.

Spark is a set of real-time GPU texture codecs that produce results competitive with offline encoders while running thousands of times faster, on every GPU from budget phones to high-end PCs and consoles.

The highlight of this release is HDR. Spark 1.4 adds two new HDR codecs: BC6H for desktop and consoles and ASTC HDR for mobile, and both deliver quality that matches or exceeds the best offline encoders at real-time speeds.

Real-time HDR compression opens up a new range of applications:

  • Light probes and reflection maps that are re-rendered as the scene changes and compressed on the fly.
  • Dynamic lightmaps for time-of-day cycles and destructible environments.
  • Dynamic skies or any other HDR render target whose contents can be cached across frames.
  • HDR images decoded at runtime, from EXR, AVIF or JPEG/R, without the need for an offline pipeline.

What’s new in Spark 1.4:

This release also includes a new Getting Started guide and Performance Guidelines, many new examples, improved regression testing, bug fixes, and many other small quality and performance improvements.

It’s exciting to see Spark gaining momentum and shipping in a wide range of games and applications. Check out our front page for the latest additions to our client list.

HDR Codecs

Until now, Spark handled HDR content through our RGBM codecs, which pack an HDR range into an LDR format. RGBM works everywhere, but it requires a decode in the shader and its range is limited. The two new codecs target the native HDR formats instead: the compressed texture is sampled directly and decodes to 16-bit floats, so there’s no color transform and no shader changes on the sampling side.

BC6H

Our previous codecs deliberately target a subset of their format: the modes and partitions that give the best quality per cycle within a real-time budget. The new BC6H codec breaks from that strategy. It is our first codec that can target the entire format: all 14 modes and all 32 partition shapes.

Which subset of the format the codec targets is configured at compile time, and we provide four presets. At the lowest level, the codec saturates memory bandwidth just like our other real-time codecs. At the highest level, it produces results that challenge the best offline encoders while running orders of magnitude faster.

This chart shows the SSIMULACRA2 score of each encoder against its throughput on a M4 MacBook Pro, over a set of 27 HDR light probes, lightmaps and photographs. Larger scores are better. Spark at its highest quality level scores above every other encoder, and nearly as high as OodleTex, while running 400× faster.

Compared to the existing real-time BC6H encoders, the picture is even clearer:

What I find most remarkable is that these results are achieved with a single candidate encoding. There’s no error evaluation and no comparison between multiple candidate encodings: the codec chooses a mode and a partition up front and never looks back. This is what enables these codecs to run well on the GPU.

Compared with Krzysztof Narkowicz’s codec, Spark delivers comparable performance while avoiding some of its worst-case artifacts, as the following image comparisons show.

sevilla03
88.262
lightsaber
88.262

ASTC HDR

One of the surprises of this release is the new ASTC HDR codec. I did not plan to include it, but the initial results were so promising that I could not stop myself. This first version is intentionally simple: it uses all the HDR endpoint encoding modes, but a single partition and a single weight and endpoint bit distribution.

With these constraints I did not expect great results, but it turns out that the algorithms I developed for BC6H also work exceptionally well with ASTC, and even this first version matches or exceeds the perceptual quality of the existing offline encoders.

At its highest quality level, Spark scores above Arm’s astcenc at its most exhaustive setting and above every UASTC HDR preset except the slowest, while encoding on the GPU thousands of times faster than these CPU encoders on the same machine. The medium quality level matches astcenc’s at the default setting.

The existing ASTC HDR encoders minimize the mean squared error in the linearized logarithmic space of the format. As a result, they often spend bits on features that are not perceptually noticeable while under-allocating elsewhere, and that results in errors that are visible with the naked eye. Spark is optimized for perceptual metrics instead:

matas
86.620
matas
86.620
matas
86.620
matas
86.620

As far as I know this is the only real-time ASTC HDR encoder publicly available, so there’s nothing else to compare it against on mobile. Here are the three quality levels on a Pixel 8 (Mali-G715):

A 1024×512 light probe compresses in 0.5 ms at the highest quality level, and 0.17 ms at the lowest.

Like all of our codecs, I’ve taken special care to ensure the code is fully vectorized for 16-bit arithmetic, and that the resulting code also performs well on Adreno. Even though Adreno does not support packed math instructions, in practice the vectorized variants result in less register shuffling, increased occupancy, and a reduced instruction footprint, so the same shader works well on every mobile GPU.

Some mobile devices support both ASTC HDR and BC6H. Our BC6H codec was developed with PC and consoles in mind, but at the lower quality levels it also runs great on mobile. The following chart shows both codecs on an Adreno 740:

BC1 Ultra

BC1 is the oldest block compression format we support and the one most encoders have had the most time to mature, so I did not expect much headroom. The new Ultra quality level proved me wrong. Modern techniques combined with perceptual quality optimizations result in higher quality than the existing offline encoders, and it still runs orders of magnitude faster than them.

Three things make the difference: the use of the 3-color mode for blocks with near-black texels, a novel endpoint quantization procedure that takes into account the residual quadric of the least squares solver, and a greedy endpoint refinement.

At this quality level it is very difficult to see any difference. The results are nearly indistinguishable from the offline codecs.

BC7 NRM

Our existing BC7 codecs are optimized for color images, but BC7 textures are often used to store other material attributes. One of the most common arrangements is to pack two components of the normal in the RG channels and roughness and metalness in the BA channels.

Our color codecs were doing a reasonable job on this kind of data, but it was clear we could do better by tailoring the coding choices to it. Our new codec is optimized for the output of typical shading models, with special attention to smooth normals on glossy surfaces, where a small error in the normal becomes artifacts in the specular highlight.

This codec has mostly been tuned with client assets that I’m not able to share publicly, but at least I can share some numerical results. The chart below measures the quality of the reconstructed normals with SSIM, which correlates much better with the appearance of the shaded surface than the raw error.

ASTC 5×5

Targeting large block sizes in GPU encoders is difficult due to the high register pressure. Spark 1.2 introduced our first streaming codec with support for ASTC 6×6 blocks. This codec processes one texel at a time, so it does not need to keep all the block colors in registers at the same time. This release refines that strategy and extends it to the 5×5 block size, offering a compression ratio in between the 4×4 and 6×6 codecs and giving developers a finer-grained quality and size tradeoff.

ASTC 4x4, 5x5 and 6x6
ASTC 4×4
ASTC 4x4, 5x5 and 6x6
ASTC 4×4
ASTC 4x4, 5x5 and 6x6
ASTC 4×4

Larger blocks reduce bandwidth, but not necessarily the memory footprint. See our previous investigation for the details: The True Size of ASTC Textures.

Broader Compatibility

We continue expanding compatibility in both directions: to new devices as they come to market, such as the Pixel 10 and 11, and to legacy devices, such as Vulkan 1.0 hardware, that we had previously thought non-viable.

PowerVR Series D

I’m excited to see PowerVR making a comeback in Android phones with the Series D GPUs in the Pixel 10. I’m happy to report that Spark runs great on this new hardware, and that some outstanding issues from previous devices appear to be fixed and no longer require cumbersome workarounds. Series D is also the first PowerVR generation with ASTC HDR support, so the new codec runs there too.

Vulkan 1.0

This release adds support for many Vulkan 1.0 devices that I had previously written off as non-viable. This includes many early Arm devices, such as the Galaxy S8, as well as some Adrenos, such as the Adreno 618 in the Pixel 3a. In the past, bugs unrelated to the codecs themselves had prevented my examples, demos and benchmarks from running on these devices, and I had assumed Vulkan 1.0 was simply too unstable to be practical. On closer inspection, it turned out to be possible to work around these issues and prove that the codecs run fine on these devices.

Improved GLES mediump support

Improving mediump support on GLES mostly came down to tracking down and fixing bugs in the spirv-opt and spirv-cross toolchains, and those fixes have been contributed upstream (SPIRV-Tools #6690 , SPIRV-Cross #2633).

PlayStation® 5

The PlayStation® 5 codecs have been through extensive testing and a round of optimizations, and the SDK now includes a PS5 example and integration guidelines with performance results for every codec.

Final Words

Earlier this year I released Spark for Unity, which brings the codecs to the Unity engine, and spark.js brings them to WebGL and WebGPU. Both will pick up the new codecs in a follow-up release, and the Android and iOS demos will be updated shortly.

If you want the longer story behind this work, I recently appeared on the Wookash Podcast, where we talked about texture compression, Spark, and much more.

If you’d like to try the new codecs in your own engine, or for licensing inquiries and anything else, reach out at spark@ludicon.com.

Leave a Comment

Your email address will not be published. Required fields are marked *