Downsampling a Texture

I want to downsample a texture, in my case textures from framebuffer objects, to 1/2 or 1/4 their size or even down to just 1x1. In theory, this should be easy by letting OpenGL trigger mip map generation for the texture, at least that’s the info you find everywhere on the subject. However, I could not find specific information on how to implement it and I can’t seem to get it to work :(.

What I do is this:

• bind the texture
• call glGenerateMipmap()

• bind an fbo with e.g. a 1x1 sized texture
• resize the viewport to 1x1
• create an ortho projection with a 1x1 size
• render the texture on to a (off-)screen sized quad

The fbo texture should now contain the 1x1 version of the original texture, or not? However, I always only seem to get downsampled versions without interpolation. I.e. in case of the 1x1 texture, only the fragment in the center of the original image. Or in case of the 1/4 sized version, I see flickering.

What am I doing wrong here? What did I misunderstand?

I wanted to implement the HDR/bloom/tonemapping pipeline from here: Microsoft Learn: Build skills that open doors in your career
But instead of doing the tedious task of downsampling the texture with multiple passes and custom shaders, I thought that it’s more efficient to take advantage of hardware mipmapping?

Can’t you just do :
• bind the texture
• call glGenerateMipmap()
• glGetTexImage with correct mipmap level ?

There is a workaround here about mipmap generation sometimes not working on ATI, maybe you suffer from something similar ?
http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation

Hm… but with glGetTexImage, isn’t the texture data actually downloaded from the GPU to the CPU memory? How would I copy a mip map image from one texture directly to another texture object?

// edit: ah, do I have to use pixel buffer objects for that? I thought that these things are extinct since frame buffer objects, but they still seem to have its uses? :slight_smile:
//² hm, even with PBOs, I still don’t get how I could directly copy the mip map image to another texture :confused:

No you are right, I wrongly assumed you needed the downsampled texture on CPU side.

To verify that indeed mipmaps are wrong, you can check what happens when rendering animated zooms of the texture, with different minifications, skipping extra steps.
By the way, do you actually texture with one of the MIPMAP modes on MIN filter ?

PBO is orthogonal with FBO, both are useful and current. You may confuse with windows pbuffers, which where indeed a cumbersome precursor of FBO.

Yes, the textures of the framebuffer objects are created with

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexImage2D(GL_TEXTURE_2D, 0, m_format, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

So my steps of creating a downsampled texture from the mip maps purely on the hardware are correct in theory? i.e.

• bind the texture
• call glGenerateMipmap()

• bind an fbo with e.g. a 1x1 sized texture
resize the viewport to 1x1
create an ortho projection with a 1x1 size
render the texture on to a quad from (0,0) to (1,1)

This FBO should, in theory, hold the correctly downsampled texture, with the image from the mipmap level that holds the 1x1 image of the original texture?

glGenerateMipmap() definitely does generate mip maps. If I create the textures with GL_LINEAR_MIPMAP_LINEAR and then do not execute glGenerateMipmap(), the output of the downsized texture is black.

However, with GL_LINEAR_MIPMAP_LINEAR and glGenerateMipmap() enabled, the output still looks like it’s not interpolated. I will make a proper test set up later today in my application, to show a checker texture or something like that at various sizes.

Any update on this alleged bug ?

There’s a glHint for mipmap generation (glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST)) that may help you here, but with the caveat that as with any other glHint it’s going to be implementation-dependent.

Having gone through all this pain…you are likely to find that the simple box filter that is mipmapping is going to give you horible results. If your version of Tone mapping is simple then you’ll get away with it, if not you’ll need custom shaders to ensure your downsampled textures conatin the correct information at every pixel.