2
votes

Whenever I want to use mipmaps in opengl, i need to upload the highest resolution bitmap as mipmap level 0, and then upload lower resolutions bitmaps at higher mipmap levels.

I would have liked to be able to add higher resolution mipmaps as well as lower resolution mipmaps. Presently the only hardware way I know is to start a new mipmap-ed texture and reupload all previously uploaded bitmaps.

Any other hardware way to do this?

edit:
It appears GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL do not change the fact that opengl will allocate memory for all texture mipmap levels at texture creation, therefore it can't be used in this case since it's impossible to know which textures will need higher resolution mipmaps and which won't, so it would lead to extreme memory waste.

It looks that the only way to do this in hardware would be to re-create a new texture with the newly generated higher resolution mipmap at mipmap level 0, and then copy all previous lower resolution mipmaps at lower mipmap levels.

As far as I know, the only ways would be either to keep all previously generated mipmap levels in memory in case I need to reupload them (would rather not waste this much memory), regenerate all mipmap levels (won't do, way too slow), copy the previous textures mipmap levels to system memory using gltexsubimage2d and then uploading them to the new texture (that's gotta be slow), or copying them straight from the previous texture to the new texture.

So, is there a way to copy a texture's selected mipmap to a different texture's mipmap, something like "glcopytexture(texture_id_1,texture_mipmap_1,texture_id_2,texture_mipmap_2);"

edit2:
It seems there is a somewhat recent extension (extension ~2009 became core in ~2012) that does this exactly (https://www.opengl.org/wiki/Texture_Storage#Texture_copy) but one of the requirements of this contract is support of computers up to 10 years old.

1
it usually means that the driver needs to reallocate the entire texture as it didn't account for the higher res when creating the low res mipmapratchet freak
At this point it looks likely that this previous comment might be the only hardware answer that doesn't waste texture memory. I'm adding a follow-up question to my initial question with found information.Marladu
@Marladu: Actually, with really modern GPUs, there are other possibilities, especially GL_ARB_sparse_texture. This is of course not what you want for 10 year old systems.derhass
Hi and thanks for your comment. I tried to read the article you linked but honestly not only is it not applicable to my current contract, but mostly it's too much at the edge of what I'm able to understand, I don't think I would be able to work with it without clear directives and what I could find wasn't enough for my current abilities. If this is really related to this question and you have the time and inclination, maybe you could add a very short primer to this ARB/EXT for everyone's benefit?Marladu

1 Answers

1
votes

There is no requirement to upload the complete mipmap chain in order to use a texture. You can control the range of levels that are used by setting GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL.

You do have to decide what the size of the base level is [1] when you initially create the texture. But you can defer loading the data for the lowest levels, or never load them at all.

For example, say you want a texture that will at most be size 1024x1024 at full resolution, but you know that you don't need levels 0 and 1 because the object it is used for is far from the camera. You can create the texture starting at level 2 with:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 2);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);

Then, if you later decide that you need the texture all the way to level 0 now:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);

I don't think setting GL_TEXTURE_MIN_LOD is necessary, but it can't hurt. In both code sequences, you can of course provide your own mipmaps one by one instead of calling glGenerateMipmap().

The main caveat is that you need to be able to specify data of levels larger than 0. So you either need to generate your own mipmaps at runtime, or have pre-baked resources that include mipmaps.

Also, the implementation might decide to allocate the full texture up to level 0 even if you don't specify data for those levels. So you may or may not save memory this way. The only thing you can count on is that it accelerates the initial texture upload.

[1] This is not strictly true, because there are multiple valid sizes for the base level for a given size of a higher level. For example, if level 2 is size 16, level 1 can be size 32 or 33, and level 0 can be 64, 65, 66, or 67.