PDA

View Full Version : Texture compression issues



Moz
01-31-2002, 03:10 AM
Hi all,

I've got a couple of questions about texture compression:

1. Can I dynamically create a texture (e.g. in a pbuffer or in the back buffer in a preprocessing step) then compress it on the fly and use it to replace a part of a compressed texture (w/ glCompressedTexSubImage)? And how fast would that be?
I need it to be fast and I need compression because I want to update a huge texture (1024x1024 or 2048x2048 depending on the HW) small bits at a time. And in this case, I need this texture to be double-buffered, so this would take twice the amount of memory and can't be done without compression.

2. Can normal maps be compressed or would this have too much of an impact on the normals?

Bob
01-31-2002, 04:01 AM
1: You can update both compressed and uncompressed texture with both compressed and uncompressed data. How fast this is depends on how much you update. Updating a single pixel is not likely to cost that much compared to updating a whole 1k to 2k squared image. And we can't say whether it's fast enough for you. Only you can answer that, and I suggest you try it and see how well it works.

And can you please explain what a double buffered texture is? Never heard of that one before.

2: A normal map is nothing special. It's an ordinary image to OpenGL, but YOU, as a programmer, interpretate the texels in a different way. Just remember than compressing the normal map, most normals will no longer be normalized.

Moz
01-31-2002, 05:11 AM
Thx for answering Bob.

About the no longer normalized normals in the normal map, that's exactly what I was refering to ... my question should have been: is this acceptable?

For the double buffered texture, what I mean is that I think I can't afford to update the entire 2k x 2k texture in one step. What I would like to do is update only, say a 512x512 (or even less) part of the texture at a time. Obviously, a partially updated texture can't be used, this is why I need two textures: one being displayed, the other being updated. Once the updated texture is ready, I display it and update the other one. This is what I call a double-buffered texture.

The problem here is that I'm unsure if I can update only a subregion of a compressed texture. As I understand the GL_ARB_texture_compression specification, it is not possible ... or it might be for a given compression scheme.
What I would have to do is to render a e.g 512x512 square in the backbuffer, compress it on the fly to a compressed texture object, then copy this compressed texture to a subregion of my 2k x 2k texture.
Is it possible to do this with S3TC compression?

Eric
01-31-2002, 05:21 AM
Just a comment regarding the non-normalized normals (lots of 'n' !): when you use your normal map with some filtering (say GL_LINEAR), your normals are not normalized anyway and you have to use a normalisation cube map if you want to normalize them again...

Is the error intoduced by the compression much bigger than the one introduced by the filtering ?

Regards.

Eric

Moz
01-31-2002, 06:19 AM
Originally posted by Eric:
Just a comment regarding the non-normalized normals (lots of 'n' !): when you use your normal map with some filtering (say GL_LINEAR), your normals are not normalized anyway and you have to use a normalisation cube map if you want to normalize them again...

Is the error intoduced by the compression much bigger than the one introduced by the filtering ?

Regards.

Eric

Eric,

I've just tried both: only filtering the normal map and compressing it ...
My advice: Do not compress normal maps http://www.opengl.org/discussion_boards/ubb/smile.gif
The result is terrible (I used DXT1).
On the other hand, I couldn't see a difference between GL_NEAREST and GL_LINEAR as filtering parameters for the the normal map (when uncompressed).

For the texture update thing, I think I'll use smaller uncompressed textures that I'll update entirely each frame. I made some tests and visual quality seems good enough for my application.

Eric
01-31-2002, 06:33 AM
Moz,

Thanks for the advice, that's good to know !

Regards.

Eric

ehart
01-31-2002, 07:29 AM
One of the key questions I see here is, "Will copy from a render target to a compressed texture be fast?" The answer is that it is reasonably unlikely with the common compression formats today.

-Evan

Moz
02-03-2002, 10:35 AM
Originally posted by ehart:

One of the key questions I see here is, "Will copy from a render target to a compressed texture be fast?" The answer is that it is reasonably unlikely with the common compression formats today.

-Evan

The actual key question is "can I update only a subregion of an s3tc compressed texture". After reading the extension's spec, I'm not sure at all. If that was possible, I wouldn't have to update the entire 2k x 2k texture, and I could achieve an acceptable performance.

Nutty
02-03-2002, 12:28 PM
Hey Eric!

I just tried converting my Bump map demo to use GL_NEAREST for the normal map, and although the actual lighting itself did not change, you could see pixelation occuring in the shading.

It looks much better with GL_LINEAR, although this makes me wonder weather the normal coming from a bilinear filtered normap map is of unit length?

Nutty

Eric
02-04-2002, 01:09 AM
Originally posted by Nutty:
...makes me wonder weather the normal coming from a bilinear filtered normap map is of unit length...

I bet it's not !

Unless the driver "sees" that you are actually filtering a normal map and normalizes the result (but it should be said in the specs if this was the case...).

Anyway, a normal map is usually quite smooth regarding the direction changes of the normals. Hence, interpolating linearly between two neighbours should give an "almost-normalized" vector. Note that it's not true if your normals describe a funky surface with a rapidly changing curvature !

Regards.

Eric

Moz
02-04-2002, 08:00 AM
This is all very interesting (by the way, I too found out that a filtered normal map gives better results, that's what I've noticed on my terrain engine which lighting is done using a normal map) but what about my original question 'bout updating only a small part of a compressed texture?

jwatte
02-04-2002, 08:03 AM
You can absolutely update a sub-region of an S3TC texture. It compresses blocks of 4x4 pixels, so you may have to align all your updates on 4x4 boundaries.

I've never understood what this means for MIP map levels where the size is smaller than 4x4, though. Does anyone care to clarify what is supposed to happen? My guess is that the driver will generate a 4x4 block even for lower mip map levels, and thus waste a small amount of texture memory, but it's still supposed to work?

Moz
02-04-2002, 08:32 AM
Thanks jwatte,

by the way, if I have mipmaps, how can I update them? Do I have to copy and scale down to all the mip levels?

Bob
02-04-2002, 09:14 AM
If you have mipmaps, you must scale the image and update each mipmap level. Otherwise the lower mipmap levels won't be updated, and will hold old information. That is, one scale and one SubImage() for each mipmap level.

You can, of course, use the SGIS_generate_mipmap extension, which will automatically create/update all mipmap levels. The GeForce series supports it at least, dunno about TNT series.

Moz
02-04-2002, 09:50 AM
Thanx Bob

But will SGIS_generate_mipmap work for compressed textures?

mcraighead
02-04-2002, 12:13 PM
You can use SGIS_generate_mipmap with compressed textures, and it will work with our drivers, but it will be slow enough to likely be useless.

On a related topic, SGIS_generate_mipmap will work for paletted textures, but averaging indices may not exactly be what you were looking for... http://www.opengl.org/discussion_boards/ubb/smile.gif

- Matt

Moz
02-04-2002, 01:04 PM
And would the "Scale + SubImage technique" give reasonably good performance?

schelter
02-04-2002, 02:03 PM
Originally posted by jwatte:
You can absolutely update a sub-region of an S3TC texture. It compresses blocks of 4x4 pixels, so you may have to align all your updates on 4x4 boundaries.

I've never understood what this means for MIP map levels where the size is smaller than 4x4, though. Does anyone care to clarify what is supposed to happen? My guess is that the driver will generate a 4x4 block even for lower mip map levels, and thus waste a small amount of texture memory, but it's still supposed to work?

Yes, it's still supposed to work. and yes, that's a reasonably good guess about what hardware might do. The lowest mip levels are generally intersting things in hardware, but you should never need to know that.

schelter
02-04-2002, 02:11 PM
Originally posted by Eric:

Anyway, a normal map is usually quite smooth regarding the direction changes of the normals. Hence, interpolating linearly between two neighbours should give an "almost-normalized" vector. Note that it's not true if your normals describe a funky surface with a rapidly changing curvature !


But even if the normal surface is smoothly varying, with only minimal curvature, each 4x4 block of the texture can only represent 4 discrete values, and they are linear and evenly spaced along the line in RGB565 space.

It seems unlikely that you'll be satisfied by DXT compressed normal maps.

My best advice: 1- test it yourself. 2- Don't expect every implmentation to compress equally well. You may very well want to compress normal maps (and cache them) or as a pre-process. if you depend on the driver to compress them in real time, you've no real guarantee about the resultant quality.

regards,
J

mcraighead
02-04-2002, 02:47 PM
In general, I strongly recommend that you do not generate compressed textures on the fly. Compression is a slow process. Driver compression is provided as a convenience, not something that you should really be using in a production-quality application.

- Matt

Humus
02-04-2002, 11:30 PM
It's quite easy to write a loader for .dds files, which can store textures compressed in s3tc format. There's an example on nVidias site plus a great plugin for saving compressed textures directly from photoshop (it also works in paint shop pro). If anyone's interested I also have some code for decoding s3tc textures into raw RGBA for compatibility with older cards.

Eric
02-05-2002, 12:33 AM
Originally posted by schelter:
But even if the normal surface is smoothly varying, with only minimal curvature, each 4x4 block of the texture can only represent 4 discrete values, and they are linear and evenly spaced along the line in RGB565 space.

I wasn't talking about the compressed normal maps here, just plain filtered ones (that's why Moz "refocused" the discussion http://www.opengl.org/discussion_boards/ubb/wink.gif !).

Thanks for the info anyway !

Regards.

Eric

jwatte
02-05-2002, 11:15 AM
The problem is that the quality/compression ratio of S3TC is pretty poor. I use it for many textures where it's acceptable -- however, I still want to use JPEG in 10:1 compression mode for actually storing the textures on disk, as that gives smaller files and higher quality. Smaller files are really important to me.

For transparency, that's stored as a separate bitmap; either as a grayscale JPEG (for 8 bits of transparency) or as a 1-bit PNG (for cut-out). Thus, actually loading a texture consists of:

1) Decompress colormap JPEG
2) (maybe) Decompress alpha JPEG or PNG
3) (maybe) combine them into BGRA data
4) tell driver to re-compress as S3TC

Note that I use the compression so that I can fit on a 32 MB card, and possibly to increase my texturing rate; I do NOT view hardware texture compression as a reasonable delivery format.

Yes, this is really slow, although we prefer to incrementally upload textures rather than take a big, brief frame-rate hit.

JPEG is block based. When will we see JPEG based hardware texture decompression? :-)

mcraighead
02-05-2002, 04:03 PM
Please take into account that S3TC is *not* an easy format to compress into. The tradeoff between compression quality and compression performance can be brutal. So you can expect superior results with an offline compressor.

Quake 3 gets away with this because Q3 uses such small textures. (Q3 also misuses S3TC by using it for some textures where it shouldn't have been used, such as lightmaps.)

Even though I understand the desire to get higher compression ratios for storage than S3TC can provide, I recommend you investigate alternative approaches. I'm sure you could roll your own lossless compression format that sits on top of S3TC that would accomplish your goal in a much more efficient way overall.

The fundamental design goal of schemes like S3TC is easy _decompression_.

You will be punishing yourself if your app compresses S3TC textures at runtime. A few 2Kx2K textures would probably already take a prohibitive time to load. Alternative approaches will give you both better quality and performance.

- Matt

schelter
02-05-2002, 06:56 PM
Originally posted by jwatte:
Thus, actually loading a texture consists of:

1) Decompress colormap JPEG
2) (maybe) Decompress alpha JPEG or PNG
3) (maybe) combine them into BGRA data
4) tell driver to re-compress as S3TC

Note that I use the compression so that I can fit on a 32 MB card, and possibly to increase my texturing rate; I do NOT view hardware texture compression as a reasonable delivery format.

I don't see why DXT isn't a reasonable delivery format for you. It doesn't seem like quality is your issue. DXT1 gives you 6:1 compression over RGB8. Are you really that tight for space?

I'll say it again. If you ask the driver to compress for you, you don't really know what quality or performance you will get. Or that you will actually get any compression. It is perfectly legal for a driver to completely ignore your request for load-time compression. Even when the hardware can decode compressed textures

JPEG can introduce some nasty artifacts to textured primitves. Re-compresing a JPEG to DXT doesn't seem like a good quality decision to me. YMMV

I wholeheartedly agree with Matt: Compress with your own tools, and examine the quality. Driver compression is useful during development, but don't use it when you ship.

J

Moshe Nissim
02-05-2002, 10:06 PM
While on the subject of texture compression:
Why does DXT1 decompresses with less quality than DXT5, on images without actual alpha channel? (I am talking about nVidia boards). The spec says all the DXT formats treat the RGB part in the same way.
This is not a compression issue, but a DEcompression issue.
I tested the problem like this:
I define a user-memory RGBA8 image, give it over to the driver to compress into a DXT5 texture. It displays nicely. Then I read back the compressed data using glGetcompressedTexImageARB, remove the alpha blocks (first 8 bytes out of the 16 bytes of the 4x4 pixel block), and pass this data to a RGB_DXT1 texture. I expected the visual rendering result to be of the same quality.
It is not.
Any ideas?

Humus
02-05-2002, 11:05 PM
It's a hardware issue. This problem is finally fixed with GF4 according to the review at tomshardware.

Regarding distributing of textures I've found compressed .dds files to be much more suitable than everything else (for me at least). For normal maps though I'm usually using a grayscale heightmap in png format which I convert to a normalmap at load time.

Moshe Nissim
02-06-2002, 07:16 AM
Originally posted by Humus:
It's a hardware issue. This problem is finally fixed with GF4 according to the review at tomshardware.

All the web references to this, (including Tom's) describe it as a "16 bit color problem". But all the DXTs are 16-bit for each of the (two) colors, and DXT5 is no different. But I hope he got the fact that its fixed in the GF4 right..

GPSnoopy
02-06-2002, 08:32 AM
mcraighead, tell us they've improved the DXT1 format support on the GF4, so we can finally use it when we don't need Alpha... Please tell us!!! http://www.opengl.org/discussion_boards/ubb/smile.gif

AFAIK, the GeForce DXT1 problem was due to the fact that the interpolation (= DXT decompression) results were done in 16bits with DXT1. NVIDIA said they were doing this by strictly following some DXTC spec, saying that DXT1 had to be used for 16bits.

Now, I hope mcraighead will tell us the real reasons but I doubt he will. (NVIDIA never really did) http://www.opengl.org/discussion_boards/ubb/frown.gif

I just hope that the GF4 really fixes the problem, and that it's not the drivers forcing DXT1 to DXT3.

mcraighead
02-06-2002, 10:22 AM
DXT1 quality is greatly improved on both GF4 MX and GF4 Ti.

- Matt

jwatte
02-06-2002, 06:34 PM
> Even though I understand the desire to get
> higher compression ratios for storage than
> S3TC can provide, I recommend you
> investigate alternative approaches. I'm
> sure you could roll your own lossless
> compression format that sits on top of

Perhaps, but the investigation done so far hasn't been able to beat JPEG when it comes to compression*quality factor.

> You will be punishing yourself if your app
> compresses S3TC textures at runtime. A few
> 2Kx2K textures would probably already take
> a prohibitive time to load. Alternative

Texturing over AGP is better? I don't think so. Let me set the stage:

The application may run for days.

The application will see textures that didn't even exist when it started, that need to be transmitted over a network.

The "network" is a 56 kBit modem (which means 30 kbit for all intents and purposes).

Everything the application draws, plus framebuffers, will not fit on a 32 MB card uncompressed.

As funneling in new textures is already slow, we've chosen to upload newly downloaded textures a little bit per frame, so that a 1024x1024 may take a second to fully upload. That's OK, as it probably took longer than that to arrive over the modem anyway.

Meanwhile, the frame rate stays predictable, which is more important than fast loading of new textures for this application.