前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >突破内存的桎梏:移动端纹理压缩应用与分析

突破内存的桎梏:移动端纹理压缩应用与分析

原创
作者头像
serena
修改2021-08-03 14:56:06
1.8K0
修改2021-08-03 14:56:06
举报
文章被收录于专栏:社区的朋友们社区的朋友们

作者:Lingtonke(柯灵杰)

导语

最近一段时间AR技术成为了时下热门,越来越多的应用开发者投身到这些技术中来。应用中出现了3D的AR场景,图形学也成为了必备的技术基础。在开发过程中,往往为了追求更好的效果而使用了更加高清的素材,使得本就内存吃紧的手机面对更加严峻的挑战,尤其是对iOS开发者而言。 为了解决这个问题,我们使用了纹理压缩技术。使用这个技术可以大幅度的降低APP的内存(共享显存)占用,从而在有限的内存限制下,使用更丰富的素材。

1 前言

最近一段时间AR技术成为了时下热门,越来越多的应用开发者投身到这些技术中来。应用中出现了3D的AR场景,图形学也成为了必备的技术基础。在开发过程中,往往为了追求更好的效果而使用了更加高清的素材,使得本就内存吃紧的手机面对更加严峻的挑战,尤其是对iOS开发者而言。

为了解决这个问题,我们使用了纹理压缩技术。使用这个技术可以大幅度的降低APP的内存(共享显存)占用,从而在有限的内存限制下,使用更丰富的素材。

2 什么是纹理压缩

常见的图片文件格式,比如PNG,JPG,BMP等,是图像为了存储信息而使用的对信息的特殊编码方式。它存储在磁盘中,或者内存中,但是并不能被GPU所识别。

这些文件格式当被读入后,还是需要经过CPU解压成bitmap,再传送到GPU端进行使用。

纹理格式是能被GPU所识别的像素格式,能被快速寻址并采样。压缩纹理,是一种GPU能直接读取并显示的格式,使得图像无需解压即可进行渲染,节约大量的内存。

3 常见的压缩纹理格式

3.1 DXT

DXT纹理压缩格式来源于S3(Silicon & Software Systems)公司提出的S3TC(S3 Texture Compression),基本思想是把4x4的像素块压缩成一个64或128位的数据块,是有损压缩方式。DXT1-DXT5是S3TC算法的五种变化,用于各种Windows设备。

压缩率:DXT1,DXT4,DXT5为4:1,DXT2、DXT3为2:1

主要支持Windows平台及Tegra系列的GPU的Android手机

支持GPU:

3.2 ETC

Ericsson Texture Compression,是由 Khronos 支持的开放标准,在移动平台中广泛采用。它是一种为感知质量设计的有损算法,其依据是人眼对亮度改变的反应要高于色度改变。类似于DXT,ETC也是把4x4的像素块压缩成一个64或128位的数据块,也是有损压缩。

Alpha

压缩率

适用

ETC1

N

6:1

OpenGLES 2.0

ETC2

Y

6:1

OpenGLES3.0

这个系列,可以说是适用机型最广的格式。

ETC1支持几乎所有市面上的Android机,所有iPhone

ETC2支持大部分高端Android机,iPhone 5S及以上

3.3 PVRTC

PowerVR Texture Compression,PVRTC格式与基于块的压缩格式,比如S3TC、ETC的不同之处是,它使用2张双线性放大的低分辨率图,根据精度和每个像素的权重,融合到一起来呈现纹理,并且2-bpp和4-bpp都支持ARGB数据。PVRTC格式压缩比较高,也是有损压缩。

Alpha

压缩率

适用

PVRTC 2BPP

Y

16:1

OpenGLES 2.0

PVRTC 4BPP

Y

8:1

OpenGLES2.0

这个系列,是iPhone支持最广的格式

只支持长宽相等且为2的幂次方的纹理

支持部分Android机(GPU:PowerVR系列),iPhone全系列机型

支持的GPU

3.4 ASTC

ASTC(Adaptive Scalable Texture Compression,自适应扩展纹理压缩),这是ARM提出的,去年被Khronos组织认可,纳入到标准中来,不过并不是强制性的

有多种压缩方式可选,具有不同的压缩率

Block footprint

Bit rate

压缩率

4x4

8.00

25%

5x4

6.40

25%

5x5

5.12

20%

6x5

4.27

20%

6x6

3.56

14%

8x5

3.20

20%

8x6

2.67

5%

10x5

2.56

20%

10x6

2.13

7%

8x8

2.00

25%

10x8

1.60

25%

10x10

1.28

20%

12x10

1.07

20%

12x12

0.89

这个系列,可以说是综合性能和使用便捷性最好的系列。

支持部分高端Android机型,iPhone6及以上机型

4 主要优缺点

在几乎不损害图片质量和显示性能的情况下,大幅度降低内存(显存)开销,纹理压缩就是这样的一个技术。

不过,任何的技术都有其适用范围和优缺点,需要仔细评估再决定。

4.1 主要优点

占用内存(显存)大幅度降低

无额外性能开销

使用方便,只需少量代码

4.2 主要缺点

硬件相关,要考虑兼容性

压缩纹理文件大小比常规PNG和JPG文件大

需要额外的制作工具,无法直接在移动端生成

5 如何使用压缩纹理

5.1 保存格式

压缩纹理是图片数据的一种编码方式,我们还缺少一个容器去承载。就像MP4文件是H264的视频的容器一样。

我们选择了使用KTX的格式。

KTX是一个为OpenGL和OpenGLES程序设计的纹理存储格式。它可以简单的辨别里面所存储的纹理格式和其他相关信息。

5.2 文件结构

代码语言:javascript
复制
Byte[12] identifier
UInt32 endianness
UInt32 glType
UInt32 glTypeSize
UInt32 glFormat
Uint32 glInternalFormat
Uint32 glBaseInternalFormat
UInt32 pixelWidth
UInt32 pixelHeight
UInt32 pixelDepth
UInt32 numberOfArrayElements
UInt32 numberOfFaces
UInt32 numberOfMipmapLevels
UInt32 bytesOfKeyValueData

for each keyValuePair that fits in bytesOfKeyValueData
    UInt32   keyAndValueByteSize
    Byte     keyAndValue[keyAndValueByteSize]
    Byte     valuePadding[3 - ((keyAndValueByteSize + 3) % 4)]
end

for each mipmap_level in numberOfMipmapLevels*
    UInt32 imageSize; 
    for each array_element in numberOfArrayElements*
       for each face in numberOfFaces
           for each z_slice in pixelDepth*
               for each row or row_of_blocks in pixelHeight*
                   for each pixel or block_of_pixels in pixelWidth
                       Byte data[format-specific-number-of-bytes]**
                   end
end
           end
           Byte cubePadding[0-3]
       end
    end
    Byte mipPadding[3 - ((imageSize + 3) % 4)]
end

5.3 使用KTX格式

代码语言:javascript
复制
typedef struct __attribute__((packed))
{
    uint8_t identifier[12];
    uint32_t endianness;
    uint32_t glType;
    uint32_t glTypeSize;
    uint32_t glFormat;
    uint32_t glInternalFormat;
    uint32_t glBaseInternalFormat;
    uint32_t width;
    uint32_t height;
    uint32_t depth;
    uint32_t arrayElementCount;
    uint32_t faceCount;
    uint32_t mipmapCount;
    uint32_t keyValueDataLength;
} KTXHeader;




KTXHeader *header = (KTXHeader *)[data bytes];

BOOL endianSwap = (header->endianness == 0x01020304);

self.width = endianSwap ? CFSwapInt32(header->width) : header->width;
self.height = endianSwap ? CFSwapInt32(header->height) : header->height;
self.internalFormat = endianSwap ? CFSwapInt32(header->glInternalFormat) : header->glInternalFormat;

uint32_t mipCount = endianSwap ? CFSwapInt32(header->mipmapCount) : header->mipmapCount;
uint32_t keyValueDataLength = endianSwap ? CFSwapInt32(header->keyValueDataLength) : header->keyValueDataLength;

const uint8_t *bytes = [data bytes] + sizeof(KTXHeader) + keyValueDataLength;
constsize_tdataLength = [data length] - (sizeof(KTXHeader) + keyValueDataLength);

NSMutableArray *levelDatas = [NSMutableArrayarrayWithCapacity:MAX(mipCount, 1)];

const uint32_t blockSize = 16;
uint32_t dataOffset = 0;
uint32_t levelWidth = self.width, levelHeight = self.height;
while (dataOffset<dataLength)
{
    uint32_t levelSize = *(uint32_t *)(bytes + dataOffset);
    dataOffset += sizeof(uint32_t);

    NSData *mipData = [NSDatadataWithBytes:bytes + dataOffsetlength:levelSize];
    [levelDatasaddObject:mipData];

    dataOffset += levelSize;

    levelWidth = MAX(levelWidth / 2, 1);
    levelHeight = MAX(levelHeight / 2, 1);
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导语
  • 1 前言
  • 2 什么是纹理压缩
  • 3 常见的压缩纹理格式
    • 3.1 DXT
      • 3.2 ETC
        • 3.3 PVRTC
          • 3.4 ASTC
          • 4 主要优缺点
            • 4.1 主要优点
              • 4.2 主要缺点
              • 5 如何使用压缩纹理
                • 5.1 保存格式
                • 5.2 文件结构
                  • 5.3 使用KTX格式
                  相关产品与服务
                  图像处理
                  图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档