Yes, but the worth of doing that is somewhat arguable. First issue is the packing, it’s not exactly free. I have a sophisticated packer implemented in meep which is incredibly fast, but it needs a lot of memory to keep current state. Essentially this is an allocator problem. Instead of 1d as in with most memory allocators we are now going 2d in texture space, and then we say “hey, that’s not hard enough” and we add layers, so it’s a 3d allocator.
Not to say that it’s impossible, it very much is possible, but the complexity I believe is not worth the trouble.
One simpler approach would be just to bin your layers, say N layers are dedicated to texture slots of resolution X by Y where X and Y are whole divisors of the layer resolution.
Of course one of the problems is that you kind of have to allocate all of that texture space ahead of time, to avoid re-allocations which would absolutely destroy your performance.
Your texture lookup gets more messy as well, now you have to carry not only slot, but also the size of the texture when trying to read it on the GPU. In my case, just a single u32 ID is enough to reconstruct UV bounds for a texture, because each slot is the same size.
But as much as it’s an interesting thought experiment, consider 2 more things:
- texture caches. Say you’re reading a texel for a texture in slot 0 and a texel for a texture in slot 99, they are probably in different layers and not even adjacent layers. Your cache utilization is going to be bad, the hardware does not expect you to access texture like that. Rather - it’s optimized for something else. The problem gets worse the bigger the overall underlying texture array.
- sampling. I implemented software sampling, but it’s almost an order of magnitude slower than hardware sampling. In fact, for I don’t even do trilinear sampling, if you add that - it would be even worse. Now, texture sampling is fast anyway, so that cost is pretty trivial in the grand scheme of things, but these samples add up.
And that’s to say nothing of data types and channel counts. For example, say you have an HDR texture, you’d be hard-pressed to put it into rgba8unorm
texture array. Or, you might have a single channel texture, like roughness or a light map for example - you’d be wasting 3/4 of the space on unused channels.
I’m all for over-engineering things in general, and I think it would be an interesting research project, but in my experience the more you fight against the hardware and the API (WebGPU and GPU architecture), the more pain you incur. And the less likely you are to beat the defaults.
That said, if you go down this route - you might enable some usecases that are simply impossible without this, such as ray tracing. There’s a lot of fun and cool stuff to be had here, but I think you really need these unique and special use cases to make it worth it.