PDA

View Full Version : How to anti-alias images shown as 2D textures?



Igor Levicki
01-07-2010, 09:00 AM
I am writing an image viewer application. It is pretty simple, and it uses OpenGL to display photos (as a 2D texture), enabling very fast zoom/pan without tearing.

I wanted to improve zoom quality (particulary zoom out or downsampling) so I enabled multisample. With 8x MSAA (which is maximum I can get for some reason on ATI HD 5850 with Catalyst 9.12) there is some improvement, but it is very subtle.

What would be a recommended way of letting OpenGL downsample the 2D texture containing the image with highest quality?

Would super-sampling help? If so, how to enable it?

If not, what else apart from writing a shader or downsampling on a CPU?

mfort
01-07-2010, 09:36 AM
Look for Mipmaping. Antialiasing does not help in downsampling.

Igor Levicki
01-07-2010, 03:27 PM
Funyy, by reading this:

http://www.opengl.org/registry/specs/ARB/multisample.txt

Especially the part:

This extension provides a mechanism to antialias all GL primitives: points, lines, polygons, bitmaps, and images.

I was under impression that it would work on textures as well being that the textures are images.

Sure, I can Google how to setup mipmapping, but how to select the best filtering method for downsampling (and upsampling?), and how to turn off "performance" optimizations that hurt image quality on ATI and NVIDIA cards? Will mipmapping work for NPOT textures?

zed
01-07-2010, 04:14 PM
>>Would super-sampling help? If so, how to enable it?

you need to draw into a texture larger than the window eg 4x larger (use FBO or something)

and then draw that texture to window

as mfort saiz MSAA only really helps on polygon edges, for photos youre not gonna see much benefit

look into mipmapping and perhaps also negative mipmap bias
http://www.opengl.org/registry/specs/EXT/texture_lod_bias.txt

Igor Levicki
01-07-2010, 04:18 PM
I am trying to keep it as simple as possible.

From what I just read on gluBuild2DMipmaps() it does not work with non-power of two textures (it scales the original to the nearest power of two before generating mipmaps) so that doesn't work for me.

Any other way to generate NPOT mipmaps in OpenGL?

Generating them on CPU would slow down the time it takes to display the photo initially.

How to use cubic (or better) filters instead of box?

Zeno
01-07-2010, 04:34 PM
Don't use glu to make mipmaps. If you're not pre-calculating them use this:

glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);

Spec here: http://www.opengl.org/registry/specs/SGIS/generate_mipmap.txt

Cubic filters can be programmed in a shader. There's an article on it here: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter20.html

Dark Photon
01-07-2010, 07:11 PM
Would super-sampling help? If so, how to enable it?
you need to draw into a texture larger than the window eg 4x larger (use FBO or something) ... and then draw that texture to window
Super-sampling (SSAA) might help. Multisampling (MSAA) would not.

Besides the technique zed mentions, some vendors offer SSAA GL modes you can draw to. This would be a quick way to test for gain without having to code up FBO render and downsample.

For instance, on NVidia GTX285 on Linux with latest drivers:


> nvidia-settings --query=fsaa --verbose
...
Valid 'FSAA' Values
value - description
0 - Off
1 - 2x (2xMS)
5 - 4x (4xMS)
7 - 8x (4xMS, 4xCS)
8 - 16x (4xMS, 12xCS)
9 - 8x (4xSS, 2xMS)
10 - 8x (8xMS)
12 - 16x (8xMS, 8xCS)

So 9 is supersampling. You can nail this on with nvidia-settings or setting the _GL_FSAA_MODE env var to 9 before running the app.

But try zed's other suggestions.

Also, are you always displaying these images with the texel axes aligned to the pixel axes (that is, no rotating of images clockwise or counterclockwise on the screen, and no "tipping" images into or out of the screen?) If not, crank up your anisotropic filtering.

Igor Levicki
01-08-2010, 08:20 AM
Mipmaps require some coding so it will take me some time to try that.

No, I am not rotating or tipping the image, or otherwise I would need anisotropic filtering as well.

Regarding super-sampling, that was exactly my thought -- quick and dirty solution to the problem.

However, I am at a loss how to enable it on ATI HD 5850?

1. Their OpenGL documentation is dated 2005 so no help there.

2. If I enable multisample, the highest value for WGL_SAMPLES_ARB I can use is 8 or wglChoosePixelFormatARB() returns zero formats, and 8 coincides with 8x MSAA.

3. In Catalyst Control Center there are the following options:

- Antialiasing level: can be set to 2x, 4x, 8x
- Filter: can be set to box, narrow tent, wide tent, edge-detect

When you set 8x and box it says 8 samples.
When you set 8x and narrow tent it says 12 samples.
When you set 8x and wide tent it says 16 samples.
When you set 8x and edge-detect it says 24 samples.

So, I presume that setting WGL_SAMPLES_ARB to 8 and somehow selecting filter to be edge-detect might enable supersampling but I don't have a clue if that is true and if so, how to do it?

EDIT:
That feature is something ATI calls Custom Filter AA (CFAA).
Basically, you enable it from Catalyst Control Center and then it works for all applications. Now I have additional questions:

1. Is there a way to enable edge-detect filter programmatically from OpenGL?

2. Since there is the possibility for using custom AA filters available, I would like to know how do I supply my custom filter in OpenGL?

Alfonse Reinheart
01-08-2010, 01:22 PM
You could generate mipmaps for the texture by calling glGenerateMipmaps(EXT if you're using EXT_FBO) on the texture.

ZbuffeR
01-08-2010, 01:25 PM
Mipmaps require some coding so it will take me some time to try that.

As said Zeno above:
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
Or alphonse :
glGenerateMipmaps();

poof auto mipmaps. Not that hard, really.

Igor Levicki
01-08-2010, 04:29 PM
1. Do those mipmaps work for non-power-of-two textures?
2. What downsampling algorithm is used to generate them?
3. Can I change the algorithm to get the better quality?

Alfonse Reinheart
01-08-2010, 04:32 PM
Do those mipmaps work for non-power-of-two textures?

Unless you're using old ATI hardware, yes. All NPOT does is remove the power-of-two restriction.


What downsampling algorithm is used to generate them?

Whatever the implementation wants. It's a convenience function.


Can I change the algorithm to get the better quality?

No. You can implement it yourself if you want.

Igor Levicki
01-11-2010, 04:22 PM
Whatever the implementation wants. It's a convenience function.

What do you mean by "implementation"?


No. You can implement it yourself if you want.

You mean like in "replace the algorithm that mipmap generating function uses by calling some other obscure OpenGL function and passing a function pointer" or like in "implement it on a CPU without using OpenGL function at all"?

Alfonse Reinheart
01-11-2010, 04:31 PM
What do you mean by "implementation"?

The OpenGL implementation.

OpenGL is just a specification, a document. It is implemented by NVIDIA, ATI, Apple, and others. Your code runs on a particular implementation of OpenGL usually written by the makers of your GPU.

The OpenGL specification allows certain features to be "implementation-defined". This means that the results are allowed to vary from implementation to implementation, though usually within certain expectations.


You mean like in "replace the algorithm that mipmap generating function uses by calling some other obscure OpenGL function and passing a function pointer" or like in "implement it on a CPU without using OpenGL function at all"?

Actually I meant, "Write a shader to scale the image down and render this to the lower mip level of the texture." You could do it on the CPU if you want, but I don't really see the need to.

Igor Levicki
01-14-2010, 03:31 PM
Ok thanks everyone for the help.

Seeing how I want to control quality of downsampling and OpenGL doesn't provide such control, and given that it is hard to make GLSL work on ATI I will have to reconsider whole approach and perhaps reimplement this viewer in DirectX to see if it is going to be easier make it work the way I want.

ZbuffeR
01-14-2010, 04:10 PM
Huh, I am curious to learn about how "control quality of downsampling" can be easier on Direct3D ...

Alfonse Reinheart
01-14-2010, 05:20 PM
given that it is hard to make GLSL work on ATI

You're doing downsampling. It's texture accessing and some basic vector math. That stuff works even on ATI drivers.


Huh, I am curious to learn about how "control quality of downsampling" can be easier on Direct3D

Does D3D even provide automatic mipmap generation?

Igor Levicki
01-15-2010, 12:43 PM
You're doing downsampling. It's texture accessing and some basic vector math. That stuff works even on ATI drivers.

I certainly hope so.


Does D3D even provide automatic mipmap generation?

Does this answer your question?
http://msdn.microsoft.com/en-us/library/ee415161%28VS.85%29.aspx

Igor Levicki
02-23-2010, 12:33 PM
I have to bring this topic back from the dead:

People suggested me to use:



glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);


But the problem is that I am using GL_TEXTURE_RECTANGLE_ARB because I need my textures to be non-power-of-two.

Furthermore, this is not enough to implement mipmapping, one has to call glGenerateMipmap() (http://www.khronos.org/opengles/sdk/docs/man/glGenerateMipmap.xml), but that function:

1. Doesn't work with GL_TEXTURE_RECTANGLE_ARB.
2. Requires that width and height are powers of two.

Now, either I have some fundamental misunderstanding of all this, or the OpenGL API has a serious problem, and I somehow believe it's the later.

What good are non-power-of-two textures if you can't use them throughout the API? Who in their right mind decided that those do not need filtering?

ZbuffeR
02-23-2010, 12:58 PM
non-power-of-two textures is very different from texture rectangle.
http://www.opengl.org/wiki/NPOT_Textures
Rectangle can't have mipmaps, NPOT can.


Furthermore, this is not enough to implement mipmapping
Wrong, only one is needed. GL_GENERATE_MIPMAP_SGIS and glGenerateMipmap are different : the first tells GL to generate mipmaps whenever texture data changes and is deprecated in GL 3+ ; the second triggers mipmap generation once, at the moment it is called, and is the preferred modern approach (useful when doing multiple passes of rendering to a texture, only generate mipmaps when needed, instead of doing it at each pass)

Jedimaster
02-23-2010, 09:49 PM
glGenerateMipmaps() is limited for texture formats.

You may render the texture into FBO with MSAA support by HW.

Igor Levicki
02-24-2010, 05:20 AM
You may render the texture into FBO with MSAA support by HW.

Damn, this is getting complicated...

Could you please elaborate a bit on how to setup FBO? I already have window creation code and MSAA code but I am not sure whether I need to change something there or not.

Another thing I need to know is how to select SSAA mode (ATI) and how to change filter type (Box, Narrow Tent, Wide Tent, Edge Detect) programmatically from my application? Is it possible at all?

EDIT:

In case I want to use glGenerateMipmaps(), what is the proper way to specify hint (nicest/fastest)?

Igor Levicki
03-07-2010, 12:33 PM
Just in case that someone asks the same question:

TEXTURE_2D target can be non-power-of-two, therefore, you can use mipmaps with NPOT textures.

Intel's OpenGL driver doesn't export glGenerateMipmaps() so the filtering won't work on Intel graphics if implemented using that API.