KhronosGroup / KTX-Software

KTX (Khronos Texture) Library and Tools
Other
874 stars 229 forks source link

Mipmapped array textures stored incorrectly in ktx2 #562

Closed superdump closed 2 years ago

superdump commented 2 years ago

The KTX2 specification says that the mip array is supposed to be stored from highest mip (lowest resolution) to lowest mip (highest resolution): https://github.khronos.org/KTX-Specification/#_mip_level_array The level indices are supposed to be stored from the lowest mip to the highest mip: https://github.khronos.org/KTX-Specification/#_level_index And within the data for any one mip level, the structure of the data is meant to be for each layer, for each cube face, for each z slice of blocks, for each y row of blocks, for each x block: https://github.khronos.org/KTX-Specification/#levelImages

However, files output from toktk using its --layers <number> option, which seems to be for creating array textures (as in those using 2d array samplers where one has to specify a layer when sampling) stores all mips for the first layer, then all mips for the second, and so on. As such, one has to iterate for each layer, for each mip level, which seems wrong?

superdump commented 2 years ago

This also seems to be broken in the basisu tool: https://github.com/BinomialLLC/basis_universal/issues/296

superdump commented 2 years ago

I think maybe I spoke too soon. The data does seem to be laid out as mip n layer 0 ... n, mip n-1 layer 0 ... n, etc, but the GPU wants layer 0 mip 0 ... n, layer 1 mip 0 ... n, etc. So when creating the texture buffer, you have to loop over layers, then mip levels.

MarkCallow commented 2 years ago

As you noted, @superdump, the data is laid out as specified. The specification is as it is because that is the way both OpenGL and Vulkan need it. What GPU API are you using? You mentioned over in https://github.com/BinomialLLC/basis_universal/issues/296 the m1 chip. Are you using Metal? The libktx Vulkan loader loads everything successfully on an m1 via MoltenVK and does not loop over the layers. Perhaps MoltenVK has to do that.