bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
35.08k stars 3.45k forks source link

Improve CompressedImageSaver #14671

Open JMS55 opened 1 month ago

JMS55 commented 1 month ago

It's time to get serious about texture speed :). Streaming mips can come later, first we need a better system that actually compresses textures (on disk).


Old plan (ignore everything under this)

The current CompressedImageSaver outputs basisu files, which tend to be quite large, as they're designed for random-access decompression on the GPU, not for linear-reads like loading from disk. We should supercompress the textures by compressing the basisu with zstd. By storing that in a ktx2, we can reuse the existing ImageLoader (ktx2 zstd-supercompressed textures are an existing standard), no need for a custom loader.

We may also want to skip basisu, and just store BC7/ASTC/etc in supercompressed KTX2 files directly, to avoid the overhead, and let us support more formats. See the optional bullet points below. If so, a lot of the bullets below are invalid.

TODO

Inspirateur commented 3 weeks ago

Will this allow us to add mipmaps to a 2d image with multiple layers (for texture array) ?

JMS55 commented 3 weeks ago

Theoretically I think? Would probably need extra handling to deal with more than 1 layer. Depends how difficult that is to implement. I haven't figured out how to generate the mipmaps yet, might need to use wgpu and run some compute shaders.

JMS55 commented 3 weeks ago

After talking it over some more, I feel that basis universal is not worth it, and that we're better off using KTX2 with BC/ASTC textures already.

JMS55 commented 2 weeks ago

New thoughts:

Useful stuff:

fintelia commented 2 weeks ago

The core question around basisu is how to simultaneously support both desktop GPUs (which only support BCn) and non-Qualcomm mobile GPUs (which only support ASTC). There's a few possible approaches that I see:

  1. Encode to UASTC. This is basisu's higher quality format and takes 1 byte/pixel to store (or a bit less if you apply zstd afterwards).
  2. Create two ktx2 files with BC7 and ASTC compression respectively. Each file would be 1 byte/pixel for a total of 2 bytes/pixel (or a bit less if you apply zstd afterwards). Distribute different files depending on what the platform supports.
  3. Encode to BC7 and then transcode to ASTC at runtime (or vice versa) if the platform needs it. Only a single file with 1 byte/pixel, or a bit less with zstd. I haven't heard of anyone using this approach. The main downside is that on platforms that need transcoding you'd have slower loading and lower quality textures than either of the previous options.
JMS55 commented 2 weeks ago
  1. Is what I strongly suggest.

From what I've seen, basisu is just a lot slower, and not even worth it considering you're going to ship separate builds for mobile/desktop anyways. The only use case I see for it as web support, so I guess we could keep supporting it just for that.

DGriffin91 commented 2 weeks ago

Note the basis_universal crate doesn't support wasm: https://github.com/aclysma/basis-universal-rs/issues/10

fintelia commented 2 weeks ago

There's also https://github.com/JakubValtar/basisu_rs which does pure-Rust UASTC transcoding, and thus should be wasm compatible