简介
纹理是 3D 图形应用程序中主要的内存带宽用户。 它被视为嵌入式系统中的影响性能和功效的主要瓶颈,因此务必要尽可能减少纹理的使用。
ARM 始终建议使用纹理压缩,这可大大改善应用程序性能。 Mali GPU 纹理压缩工具允许开发人员使用其标准的未压缩纹理,并以最少的工作生成压缩版本。 不过,还可应用其他技巧来进一步改善系统的效率。 其中一个是纹理映射。
纹理映射
纹理映射是纹理所附带的一组纹理预计算版本,目的是减少纹理带宽,同时通过降低锯齿效应来改善视觉输出。 请思考以下示例:
上述示例中有两个小车,在不使用纹理映射的应用程序中,前景中的小车和背景中的小车同时使用一个纹理。 示例中还可看到,小车 A 靠近镜头,因此需要一个比较大的合适纹理才能保持细节和质量。 其结果是在需要渲染小车 B 时,将会采样同样“大”的纹理来为比较小的对象生成像素,但又不需要同样级别的细节或质量(较小的纹理就已足够)。
此处的问题是,与较大的小车相比,为较小的小车采样的纹理可能以更为稀疏的方式来对待。也就是说,所需的采样很可能不在 GPU 缓存中,所以要从外部内存中完全读取,因而可能会从缓存中清空其他有用数据。
纹理映射基本上能解决此问题,它为给定的纹理存储多个大小的图像(纹理映射级别)。 GPU 接着根据离镜头的距离,选择适当大小的纹理来进行采样。 通过使用较小的图像,下一像素的采样数据很有可能位于 GPU 缓存之中,从而大大提高缓存利用率,减少从外部内存中获取的次数。
纹理映射可以在运行时使用 OpenGL ES API 生成,或者通过离线预计算纹理贴图并在运行时加载,利用小图像更好地进行重新采样以获得更佳的总体输出图像质量,也可与其他纹理一起使用 ETC 纹理压缩来进一步降低纹理的空间/带宽需求。
使用纹理映射
可以使用 Mali GPU 纹理压缩工具离线生成纹理映射。用户指南中详细阐述了如何使用该工具生成包含各种纹理映射级别的一系列 ETC 压缩图像文件。 本示例说明如何使用 OpenGL ES SDK 中的简单框架在配备 Mali GPU 的设备上加载和使用纹理映射。
加载
如果通过 Mali GPU 纹理压缩工具离线生成纹理映射,使用简单框架中提供的帮助器功能加载包含压缩后纹理映射级别的 .pkm 文件:
GLuint textureID = 0; Texture::loadCompressedMipmaps("my_buggy_mip_", ".pkm", &textureID);
或者在运行时生成纹理映射:
glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); //Load texture data unsigned char *textureData; Texture::loadData("texture.pkm", &textureData); //Read ETC header ETCHeader loadedETCHeader = ETCHeader(textureData); glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_ETC1_RGB8_OES, loadedETCHeader.getWidth(), loadedETCHeader.getHeight(), 0, loadedETCHeader.getPaddedWidth() * loadedETCHeader.getPaddedHeight() >> 1, textureData + 16)); free(textureData); //Generate the mipmaps glGenerateMipmap(GL_TEXTURE_2D);
搞定! 应用程序的其余部分相同。 纹理映射将自动得到使用,不必修改任何着色器代码。
本示例的完整源代码列表在 OpenGL ES SDK for Linux on ARM 和 OpenGL ES 2.0 SDK for Android 中提供,其名称为“ETCMipmaps”。