Eirik Aavitsland

Compressed Textures in Qt 5.11

Published Monday May 7th, 2018
8 Comments on Compressed Textures in Qt 5.11
Posted in Embedded, OpenGL, Qt Quick, Qt Quick 2, Uncategorized | Tags: ,

As modern user interfaces become ever more graphics intensive, the demands on graphics memory to hold the textures increase. This is particularly relevant for embedded systems, where resources come at a higher premium, and can be a challenge for system performance. One of the key remedies for this is to reduce the memory requirements of the graphics assets.

OpenGL texture compression has the potential to give significant savings both in startup time and runtime performance:

  • Startup: no time required to uncompress the jpeg or png format
  • Startup: since the texture is much smaller, it requires significantly less time to upload it to GPU memory
  • Runtime: Significantly reduced strain on memory bandwidth
  • Decompression is very simple and happens in hardware, so does not pose significant drag down of performance

Compressed textures in Qt Quick 2

The Qt Quick 2 source code has for a long time included the textureprovider example. This showed how to expand Qt Quick with a custom image provider that could read simple ETC1-compressed textures from pkm format container files.

In Qt 5.10, that functionality was imported, somewhat silently, into Qt Quick itself. Hence, without further ado, one could now use a local pkm file or resource as the source of an Image element. In addition, support for ETC2 compression schemes was added.

Now in Qt 5.11, this functionality has been revamped and extended. Most importantly, support for ktx – the Khronos texture container file format – has been added. This format allows a much wider range of compression schemes, so Qt Quick is in practice only limited by what the target GPU and driver can handle.

screenshot

Using compressed texture files in a Qt Quick application requires nothing special. The key part of the qml code for the screenshot above is simply:

Grid {
    columns: 2
    Image { source: "slides.png" }
    Image { source: "slides.ktx" }
    ...
}

As always, the memory savings comes at a cost. There is a trade-off between memory and visual quality. In the screenshot above, one can see how the bottom edges of the green area have become ragged compared to the original. The different texture compression schemes can provide different results, both in memory savings and image quality.

Transparency Trick

Special consideration must be taken for textures with transparency. For performance reasons, Qt Quick expects transparent textures to have the alpha channel pre-multiplied into the color channels. For normal images, Qt Quick takes care of this itself. But for compressed textures, it must necessarily be done before the image compression is performed. Some texture compression tools have built-in ability to do this. For those that do not, one can use other image manipulation tools to pre-process the source assets. For example, using ImageMagick, the following command line will create an image copy with pre-multiplied alpha:

convert mytexture.png \( +clone -alpha Extract \) -channel RGB
        -compose Multiply -composite mytexture_pm.png

Note that the resulting mytexture_pm.png will not look right when viewed with a normal png viewer, since the png format itself does not handle pre-multiplied alpha. But after texture compression and loading into Qt Quick, it will be correct.

Fallback Fix

Now, what if one wants to run the application and the compressed texture files are not available, or not usable? Say, during development one may have only the original images available, or one may want to run on a target without OpenGL support. It is suboptimal to have a separate variant of the qml code for such cases. Naturally, there are many ways to solve this issue in Qt Quick. However, Qt 5.11 has added a little feature to the Image element that makes it particularly easy in many cases, namely automatic file extension detection. This means that if an Image element specifies a non-existing local file or resource name, Qt Quick will search for an image file with the same base name, by appending the known file extensions in turn. So, for example, if the code example above was changed to:

Image { source: "slides" }

Qt Quick will do the following:

  • First, if OpenGL is available, look for “slides.pkm” and “slides.ktx”, and load the first file found, if any.
  • Then, if nothing loaded by step 1, look for “slides.jpg”, “slides.png” etc., and load the first file found.

So, by just leaving out the file extension of the source file in the Qt Quick code, one has created a simple fallback mechanism.

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Embedded, OpenGL, Qt Quick, Qt Quick 2, Uncategorized | Tags: ,

8 comments

Shantanu Tushar says:

How do I “convert” a PNG file to KTX?

Eirik Aavitsland Eirik Aavitsland says:

Generally, search around the net for “texture compression”, there are several tools designed for different target hardware. For the standard ETC/ETC2 compression, you can use the “etcpack” utility to convert a PNG file to PKM or KTX.

Will says:

Is there any plan to add support for doing the compression to Qt? Or only the ability to use the compressed textures? If I ship a KTX file to a system where the GPU doesn’t support the compression format, can Qt decompress the texture so I can still use it?

Eirik Aavitsland Eirik Aavitsland says:

As for compression, that is (at least for now) seen as outside of Qt’s scope.
Neither is there any support for software decompression currently. It would be theoretically possible to add, but with limited value, I guess: one might as well fall back to loading the original png/jpg image files then. Since either way, there will be no savings on GPU memory.

Will says:

It makes sense that it’s out of scope. That said, it wouldn’t save on GPU memory, but it’d certainly save on storage and download time if you only need to ship one set of textures. It can also use less host memory if I can store X MB of compressed textures, and decompress them on the fly to the wonky GPU as needed. Hopefully it winds up on a wishlist somewhere in case somebody gets bored. 🙂 Being able to load one image file and use it either directly as a texture or make into a QImage to do whatever with would be a nice refinement.

Eirik Aavitsland Eirik Aavitsland says:

Will, thanks for the comment, I see your point. Such SW decompression functionality has indeed already been suggested, so your interest is duly noted!

Philip S says:

Awesome! I’ve been using DXT1 compression for a long time in QML, with a custom opengl painter item and image provider. It’s nice that Qt officially supports GPU texture compression in QML. I mostly use compression for photos since it’s lossy. How’s the lossiness for ETC/ETC2 for icons? Does it add many artifacts? I guess increasing icon’s resolution and downsampling would reduce artifacts caused by lossy compression.

Eirik Aavitsland Eirik Aavitsland says:

To me, ETC compressed textures don’t look too bad. One can open the screenshot above at full size to see the artifacts better. Increasing resolution would presumably increase visual quality, agreed, but at the cost of using more memory again, of course.

Commenting closed.

Get started today with Qt Download now