Manually loading mipmap levels

Started by
3 comments, last by Nairou 15 years, 11 months ago
After reading TomF's article on controlling what texture mipmap levels you load based on what you actually need, I've been searching these forums and reading the DirectX reference documentation trying to figure out how you would actually pull this off, and so far I've been unsuccessful. I know you can call IDirect3D9::CreateTexture and tell it how many levels the texture will have, then manually go in and lock and edit each level, but what if you wanted to load a texture from disk at a very small mipmap, then later queue up a larger mipmap of it if necessary. So far I don't see any method of actually "adding" a level to an existing texture, especially a level larger than the size of the originally created texture. The only thing I can think of would be to call IDirect3D9::CreateTexture and specify all levels, but only fill in the lowest level, but I can't find anything that says for sure whether the unfilled levels are actually unallocated or whether they are just solid black textures. The latter case wouldn't help me at all as I am trying to avoid loading the full size texture into memory. Is there some other way to pull this off? TomF, if you're around, how did you do this?
Advertisement
Quote:Original post by Nairou
After reading TomF's article on controlling what texture mipmap levels you load based on what you actually need, I've been searching these forums and reading the DirectX reference documentation trying to figure out how you would actually pull this off, and so far I've been unsuccessful.

I know you can call IDirect3D9::CreateTexture and tell it how many levels the texture will have, then manually go in and lock and edit each level, but what if you wanted to load a texture from disk at a very small mipmap, then later queue up a larger mipmap of it if necessary. So far I don't see any method of actually "adding" a level to an existing texture, especially a level larger than the size of the originally created texture.

The only thing I can think of would be to call IDirect3D9::CreateTexture and specify all levels, but only fill in the lowest level, but I can't find anything that says for sure whether the unfilled levels are actually unallocated or whether they are just solid black textures. The latter case wouldn't help me at all as I am trying to avoid loading the full size texture into memory.

Is there some other way to pull this off? TomF, if you're around, how did you do this?
You can't add or remove specific mip levels, you can only specify how many you need at creation time. You certainly can't create a larger level, since that would be changing the size of the original texture (and making all existing mip levels one level lower).
If you don't fill a mip level, then it'll contain gibberish but still be rendered.

I really wouldn't worry too much about this sort of thing - drivers are pretty good at only pulling the mip levels needed into the GPU. In fact, I'd only look at this if you know it's a problem.
Have a look into using ::SetLOD() for this. I'm not sure how closely it fits with what Tom discusses, but you should be able to defensively create a full mip-chain in system memory and then stop the D3D memory manager from using high-detail mip levels that haven't actually had any data stored in them yet...

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

If you create your texture as big as it should be if everything is used, it defeats the whole purpose of saving memory (haven't read Tom's paper though). You need to create your texture as large as the largest mipmap you're going to stream in (ex: if you're streaming 64x64 and down of a 1024x1024 texture you create a 64x64 texture). When new mip levels stream in, you create a larger texture, "blit" the existing one into and copy the new higher level mipmaps. This can prove to be very memory intensive (create/destroy of resources) but you could have a pool of textures of various sizes and pick one that fits your need.

If you really want to create a texture as large at it will be in the end and restrict which mip levels you want to use, look into D3DSAMP_MAXMIPLEVEL...abusing this will cause texture cache trashing and hit performance.

Personnaly, my scheme is to only split textures if their total size is higher then some threshold and I only split mip 0 (since it takes 75% of all the texture's space and splitting it more wouldn't help imo). I first create a texture large enough to contain all lower mipmaps and when the higher level mip comes in, i create a larger one (or get one that fits my needs from a pool) and add the mip on top. When I don't need the higher mip anymore, I create a smaller texture and only copy the lower mip levels.

That's it!
Quote:Original post by Evil Steve
You can't add or remove specific mip levels, you can only specify how many you need at creation time.
Right, but you can create all levels and not specify data for each and every one (or "borrow" some random data from elsewhere). If I understand the issue correctly, the point is about the load-from-disk bottleneck.

Under OpenGL, you can specify a minimum and maximum MIP level, and DX surely has something equivalent, too. As long as the "garbage" levels are outside that range, it doesn't really matter what you initialised them with, or if at all.
Later, after loading some more levels (if an object came into closer view, for example), you can StretchRect (is that what glCopySubImage is called in DX?) them over the garbage levels, and increase the MIP range accordingly, so they will become available.
It is to some degree about disk load time, but more so about memory footprint. For example, the MegaTexture technology, or the idea TomF talks about where you could let the artist use 16k by 16k textures for everything, and only stream in the mipmap you actually need rather than loading the entire 16k by 16k texture into memory. Not that I plan to be careless with texture sizes, but I want that freedom of extreme detail without the memory cost.

So far its sounding like my only option is to recreate the texture entirely each time I add or remove levels. I know that textures consist of surfaces, is there a way to create surfaces separately and link them into a texture, rather than blitting them around to each newly-created texture? I suppose I need to look into texture pools for this as well...

This topic is closed to new replies.

Advertisement