文章

从 GPU 申请的 texture 也需要 “bzero” 吗

从 GPU 申请的 texture 也需要 “bzero” 吗

在使用 Intel Iris Pro 集成显卡的 Mac 笔记本上,大概率复现切换字幕后,字幕叠加的问题:

/assets/images/202603/20260305094851.jpg

清理 dirty 区域的问题?

这是 Ass 字幕上传纹理的逻辑,复用一个纹理,然后根据字幕内容局部替换纹理数据,避免每次都申请一个比较大的纹理。

1
2
3
4
5
6
7
8
9
static SDL_TextureOverlay * subtitle_ass_upload_texture(SDL_TextureOverlay *texture, FFSubtitleBufferPacket *packet)
{
    texture->clearDirtyRect(texture);
    for (int i = 0; i < packet->len; i++) {
        FFSubtitleBuffer *buffer = packet->e[i];
        texture->replaceRegion(texture, buffer->rect, buffer->data);
    }
    return SDL_TextureOverlay_Retain(texture);
}

看到这个 bug 首先让我想到的是 dirtyRect 计算逻辑有误,经过打印日志对比确定下次渲染时,清理的就是上次替换的区域,不存在计算错误,并且仅在 clearDirtyRect 函数里重置 dirtyRect,所以问题应该不在这。

Monkey Debug

发现硬字幕切到软字幕比软字幕间切换更加容易复现,硬字幕的源和软字幕不是一个,切换时会重建播放器,由于播放时不是从 0 开始播的,有历史记录,所以开始排查是不是由于在seek到历史记录前已经先过来一部分字幕了,是不是底层给过来的 FFSubtitleBuffer 不对呢,又经过好长时间的定位,排除了,因为即使字幕解码线程给过来了,但是还有比对时间戳的逻辑。

期间还尝试在切换软字幕后,先释放这个重用的纹理,这样每次都是新创建的,这样总行了吧,我起初不愿意这样做,想着清理 dirtyRect 区域是最优的,但是即使这样做还是不行!

分析现象

事情发展到此,已经到了下班时间了,无奈加班继续攻克,我仔细看了案发现场,从两个重叠字幕内容中发现了蛛丝马迹,底下那个不应该出现的,我一直清屏清不掉的内容,看起来是上次显示过的。

脑子里灵光一现,GPU 是不是像 malloc 一样,不负责 bzero 呢?马上问了 AI,得到的答案是 “你必须主动处理它的初始数据”。我的天哪,系统为了性能考虑,通常会从一个内部的内存池(Memory Pool)中分配显存,碰巧的是由于视频分辨率不变,所以我这申请字幕纹理的宽高也都没变过,直接从内存池捞一个上来给我了呗。

总结

在显卡性能低的设备上会出现申请的纹理是 dirty 的情况,Intel 的独立显卡和 M 系列芯片没有遇到这个问题。不管怎么样保险起见都清理下。

之前从来没往这方面考虑是因为之前申请的纹理没有做局部替换,都是全部替换的,即使是 dirty 的也无所谓!

本文由作者按照 CC BY 4.0 进行授权