Banding when viewing UASTC KTX2 in Babylon.js' sandbox

I have a test texture (zipped and attached), produced using the toktx utility. When I drag and drop it into, I get a lovely smooth multi-channel texture which is what I want (screenshot of a single channel):

But when I load it again (drag and drop the same texture into Sandbox), I get quite extreme banding:

Any subsequent load results in the same banding, until the page is refreshed. I can reproduce this on Firefox 110, Chrome 110 and Chrome Canary 113 on macOS Ventura 13.1, but interestingly not in Safari 16.2. What is actually happening here? I.e. how is rendering this texture different on first vs subsequent loads?

I ask because I get the same extreme banding in the actual app that I’m using this texture in, and this Sandbox test case seems like it could reveal how to get to that smooth one :slight_smile:

Thank you for your help! (228.2 KB)

1 Like

I don’t reproduce it in Firefox 110, Chrome 110 and Canary 113 on my Windows 11.

Do you have some errors in the console of the browser?

Nothing in the console, unfortunately. Could be a macOS thing then? I’m running this on a MacBook Air M2. I will try a few other devices tomorrow, to see if there are some commonalities.

I tried to reproduce this on my Windows machine in Edge, Firefox or Chrome, and also did not succeed. Tried on iOS too, and no banding there either.

This still leaves a large portion of our user base, those who run Chrome/Firefox on macOS. I’ll debug further to see if I can gather more data.

I gathered some more data. The first load of that texture seems to go through the following steps:

  1. babylon.ktx2Decoder.js
  2. zstddec.wasm
  3. uastc_rgba8_unorm_v2.wasm

While the second load goes through:

  1. babylon.ktx2Decoder.js
  2. zstddec.wasm
  3. msc_basis_transcoder.wasm
  4. msc_basis_transcoder.js

This happens on both Firefox and Chrome, whereas Safari loads:

  1. babylon.ktx2Decoder.js
  2. zstddec.wasm
  3. uastc_astc.wasm

And not only does the banding appear on that second load, the image is also Y-flipped. I’ll dig a bit deeper into the KTX2 decoder. Using this playground to repro/debug:

Indeed, it is not normal for the MSC to be chosen on the second loading. This means that either the loading fails somehow and the data used by the transcoding decision tree is not the right one, or the transcoding decision tree (TDT) itself does not choose the right format for some reason. But I would lean towards the former explanation because the TDT code is quite simple and applies decisions based on the data extracted from the file.

Unfortunately, I can’t debug it myself because I don’t have a Mac…

@sebavan has a mac I think? @bghgary too

1 Like

Oh wow, setting up this to debug is no small feat! :smiley:

I’m finally in, using latest commit from Babylon.js’ master, and replacing the jsDecoderModule: "" with the localhost version, and now I can dig in a bit more.

First observation is that if I set numWorkers to 0, it will immediately produce that flipped image with banding.

More soon!

@bghgary are you aware of any issues on MAC for the decoder ?

No. Let me see if I can repro.

I can repro. This is pretty strange. I’m using Edge on Mac at the moment.

Refreshing the page makes it work again, so I’m guessing we are caching something?

For the non-worker path, it looks like the default decoder options weren’t being set (in the worker path they’re set via a setDefaultDecoderOptions message). This diff makes that path work again, at least: Comparing BabylonJS:master...jure:pass_ktx2_options · BabylonJS/Babylon.js · GitHub

Is it possible that we run out of workers? No, doesn’t look like it.

Update: Oooh I think know what it is!
On second run, that isDirty is no longer true, so those options do not get set here, but the worker gets created from scratch every time:

Update 2: Yes, that’s exactly what happens in the Playground repro.

1 Like

@Evgeni_Popov Do you have time to investigate?

I’ve fixed this and verified the fix on a couple of browsers, but would really like some comments, if anyone’s keen: Always pass default KTX2 decoder options by jure · Pull Request #13568 · BabylonJS/Babylon.js · GitHub