Manual mipmap loading

The general idea is that I have an image and its n precalculated mipmaps in files in disk, what I want is to create an empty texture and manualy copy the mipmaps in this texture.

What I currently do is, at first, to create an empty texture and then create the (dummy) mipmaps:

glTexImage2D(target, 0, internalFormat, width, height, 0, format, type, NULL);
glGenerateMipmap(target);

It seems that glTexSubImage can copy data from RAM to the texture’s mipmaps directly:

int level = 1;
glTexSubImage2D(target, level, 0, 0, width / 2, height / 2, format, type, imageBufferForMipmap1); // Copy data to the second mipmap

Everything works as it should but there is a problem. When I copy something to the base mipmap (level 0) the driver discards the previous mipmaps and recalculates them. For example if I copy a green texture in level 2 mipmap and then copy a red in the base level mipmap everything turns into red.

I dont know if the glTexSubImage is the right way to copy to texture’s mipmaps but how can I copy to the base level mipmap without opengl recreating the previous mipmaps?

Thanks in advance.

PS: This will be used for texture streaming (async loading)

…When I copy something to the base mipmap (level 0) the driver discards the previous mipmaps and recalculates them.

That should not happen. Are you maybe making use of SGIS_generate_mipmap? Do not enable GENERATE_MIPMAP_SGIS for your texture object.

Thanks for the reply but I dont believe that GENERATE_MIPMAP is part of opengl 3.3 core. I forgot to mention that I’m working on 3.3 core.

On GL core, unless you call explicitely glGenerateMipmap(), it should never recalculate mimap chain automatically.

That sounds like a driver problem, and as if your driver is automatically renenerating sublevels if the top level is changed. Definitely shouldn’t happen.

You might be better off just dropping your usage of glGenerateMipmap and generating your sublevels manually instead.

That seems to be exactly what Godlike is trying to do.

Godlike, you properly removed/commented the glGenerateMipmap call from your code in your manual mipmap loading attempt, right?

That seems to be exactly what Godlike is trying to do.

Godlike, you properly removed/commented the glGenerateMipmap call from your code in your manual mipmap loading attempt, right? [/QUOTE]

Nope.

  • I crate an empty texture,
  • then I create the mipmaps (glGenerateMipmap) and
  • then I copy from RAM to every mipmap individually

If I haven’t generated used glGenerateMipmap will the glTexSubImage2D fail for levels grater than zero? I will test this as well

What he’s saying is that you should be using glTexImage2D to allocate mipmaps instead of glGenerateMipmap. Just call glTexImage2D for each mipmap you have.

Yeah, this is the correct interpretation. Using a combination of glGenerateMipmap to initially specify the miplevels, then glTexSubImage2D to subsequently update individual miplevels seems to be what generates this bug, so switching to pure glTexImage2D for initial specification of all miplevels was what I had in mind.

That would likely fix the problem, but it looks like a bug with the driver.

First of all sorry for the late update, due to lack of time I’ve tested it yesterday.

I’ve tried to specify the textures for every mipmap level using glTexImage2D. I didnt create any mipmaps with glGenMipmaps() and it worked like a charm. See the simple test case for that:

int target = GL_TEXTURE_2D;
int internalFormat = GL_RGBA;
int format = GL_RGBA;
int type = GL_UNSIGNED_BYTE;

glGenTextures(1, &glId);
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, glId);
setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);

int w = 100, h = 100;
int level = 0;
while(1)
{
	uint col = rand();
	Vec<uint> buff(w * h, col);
	glTexImage2D(target, level, internalFormat, w, h, 0, format, type, &buff[0]);
	++level;
	w /= 2;
	h /= 2;
	if(w == 0 || h == 0)
	{
		break;
	}
}

The code above is correct only for square textures. For example texture 8x2 should have mipmaps level 8x2, 4x1, 2,1.

You write “8x2, 4x1, 2,1” you mean “8x2, 4x1, 2x1”??

What is the condition to stop generating mipmaps? Actually, what is the algorithm that calculates the width and height for every level?

Thanks

What is the condition to stop generating mipmaps?

When you reach 1x1.

Actually, what is the algorithm that calculates the width and height for every level?

For power-of-two textures, divide both the X and Y by 2. If that value is a fraction, round up.

Yes, I forgot 1x1.

The number of levels is computed by:


 numLevels = 1 + floor(log2(max(w, h, d)))

You can limit the number of levels with glTexParameter(GL_TEXTURE_MAX_LEVEL) when you do not want these small levels.

According to http://www.opengl.org/wiki/Texture#Mipmap_range we round up.

When using texture sizes that are not powers of two, the half-size of lower mipmaps is rounded down. So a 63x63 texture has as its next lowest mipmap level 31x31. And so on.