HOW-TO:Texture authoring
Introduction
Textures are an essential part of the Kodi UI. It is important for them to have suitable properties, or otherwise image quality and performance will suffer.
Note that the page is still under construction.
How a GPU samples textures
In general, Kodi employs bi-linear filtering of non-mipmapped textures (https://en.wikipedia.org/wiki/Texture_filtering). For one sample, the four most adjacent texels (texture elements) get fetched, which in turn will be added together based on their distance to the sample point. If a texel point is matching a sample point, it will be the sole contributor of its color. If the sampling point is right in the middle of all four texels, the result will be the exact average of all four texels.
Note that at the sampling stage, there is no concept of color/alpha channels. There are up to four channels of data, which are totally independent of each other. This might be RGBA, but it does not have to.
This has implications on how textures should be authored.
Texture Resolution
Try to optimize textures to a nominal screen resolution of 1920x1080. This would look perfect on normal FullHD TV's, while it would still be good enough for 4k.
The resolution of textures has to be appropriate to the content it conveys. We can distinguish between three different states here:
Pixel exact resolution
For a lot of elements, this would be the ideal state in terms of quality. A texel to pixel mapping of exactly 1:1 will look the sharpest, but this is screen resolution dependent.
Magnification
If the texture is smaller than the size it is displayed at, it gets magnified by interpolating linearly. This is often adequate for low-frequency textures, sporting low details.
One recent optimization of Estuary was to introduce less demanding background patterns such as https://github.com/xbmc/xbmc/blob/248d0f0c5b38f07e04d249670dfff39b6d6959b4/addons/skin.estuary/extras/backgrounds/pattern1.png. The texture itself is just 640x630 and displayed at full screen resolution, but it is still sufficient due to the linear interpolation of the GPU.
Minification
If a texture is larger than the size of the element it is displayed at, sampling performance is degraded. If the texture is significantly larger (>2x in a dimension), performance and image quality will be severely degraded, as texels of the source will be skipped. Heavy aliasing artifacts will occur.
There is no justification to rely on texture minification, except when doing a "zoom out" animation.
One bad example of that would be the Estuary codec flags (https://github.com/xbmc/xbmc/blob/248d0f0c5b38f07e04d249670dfff39b6d6959b4/addons/skin.estuary/media/flags/videoresolution/1080.png). The element is rendered at 115x52, but the textures are 270x120 in size.
1D textures
Often enough, 2D textures are used for gradients when 1D textures would suffice. This is leaving free performance gains on the table.
For example, https://github.com/xbmc/xbmc/blob/248d0f0c5b38f07e04d249670dfff39b6d6959b4/addons/skin.estuary/media/lists/panel-mediamenu.png is taking up a lot of resources unnecessarily. The texture is 450x920 (820KB) in size, but could be represented by a 450x1 (0.9KB) texture.
Proper alpha enabled textures
One big issue with skin textures is the improper usage of textures with pre-multiplied alpha (https://en.wikipedia.org/wiki/Alpha_compositing#Straight_versus_premultiplied). Textures have to be rendered with "straight" alpha to look correct. Otherwise, rendering quality will suffer, and texture optimizations (by video hardware and Kodi) won't be as effective.
If working with Gimp, make sure to export PNGs with the option "Save color values from transparent pixels".
Channel optimized textures
A lot of textures used in Kodi can be represented by just one or two texture channels. Since Kodi 22, the XBT texture processing pipeline features optimizations which make suitable textures more efficient. In older versions, the GPU driver might be able to enable some limited hardware optimizations instead.
If a PNG just has a greyscale channel, it is stored as a single channel texture. If there is an additional alpha channel, the texture is stored with dual channels. There is no alpha only version for PNGs, but when supplying a greyscale+alpha texture with a fully white (0xFF) greyscale channel, the texture packer will be able to pack the texture into a single channel.
By nature, textures with pre-multiplied alpha can't be stored in a single channel format, as the luminance channel contains information.
It is often to possible to apply texture coloring via a diffuse color. This is highly preferred, as the texture can be reduced to a single/dual channel texture in this case.
In Estuary, around 80% of all textures are single channel textures (luminance or alpha). Further 10% are dual channel textures (luminance+alpha). Remaining textures are RGB/RGBA.
Summary
If the previous points are kept in mind when authoring textures, performance and quality gains can be substantial (compared to a lot of current textures).
- The smaller a texture is (through resolution and channel optimization), the better the XBT size. The GPU needs less memory bandwidth, which may lead to better rendering and system performance. The texture is uploaded faster, resulting in less jank. In case of Estuary, the XBT shrank around 25%. The GPU resources needed shrank by an estimated 60%.
- Single and dual channel textures also help GPU compression schemes. With (often nearly lossless) GPU compression, texture sizes can be reduced further by at least 50%.
- Too large texture will reduce quality and performance.
- Textures with pre-multiplied have quality issues.