Soc 离屏渲染优化 - 序

想了挺久, 我决定还是记录一些东西;

讲述一下 rk_mmp_demo 编码的一些背景, 出于何种目的, 又解决了什么问题.

背景

大概在一年半年前由于工作上的原因接触到了 OpenGL, 为此我还写了一篇笔记 OpenGL 简介.

在这个示例里, 演示了如何使用 OpenGL 实现转场特效这一实现, 比如百叶窗的 frag.glsl 就如下:

varying vec2 oUV;
uniform sampler2D TexA;
uniform sampler2D TexB;
uniform sampler2D TexL;
uniform float Progress;

void main(void)
{
    float softness = 0.03f;
    float luma = texture(TexL, oUV).x;
    float time = mix(0.0f, 1.0f + softness, Progress);

    vec4 acolor = texture(TexA, oUV);
    vec4 bcolor = texture(TexB, oUV);

    if (luma <= time - softness)
    {
        gl_FragColor = bcolor;
    }
    else if (luma >= time)
    {
        gl_FragColor = acolor;
    }
    else
    {
        float alpha = (time - luma) / softness;
        gl_FragColor = mix(acolor, bcolor, alpha);
    }
}

如果对 OpenGL 稍微熟悉的朋友应该会觉得这是一个简单的实现吧;
的确, 基于 glsl 的语法上来看这是一个简单的功能.

转场特效这个功能已经相当成熟了, 还不清楚的小伙伴也可以下载 OBS 尝试体验一下.

但是如果将它放到实际应用场景,随着而来就会带来几个不得不面对的问题.在实际的应用场景中, 转场特效一般用于场景切换, 更具体一步说则是视频源切换;

由此带来了以下几种特性:

  • 纹理需要实时全局更新, 根据视频源的帧率决定
  • 渲染方式为离屏渲染, 渲染完之后的结果一般需要进行再编码, 可能也会同步显示输出
  • 解码数据和编码数据一般是 YUV 格式, 而 GPU 处理数据通常由以 RGB 数据为主

如果是做 3D 引擎的同学可能已经看到了一些 Bad Smell.

冲突

这, 会带来什么问题? 如果将转场特效的流程用图描述, 应该像下图这样:

按照流程, 把每一步都简单地说明一下:

请添加图片描述

  • (1) 上传纹理; 将编码器输出的 YUV 数据分别上传至 YNV 纹理, 这里主要使用 glTexSubImage2D 接口

  • (2) 色彩空间转换, 写一个简单的 glsl 实现 YUVRGB

  • (3) 转场合成, 其中的一个例子如上

  • (4) 渲染, 将转场合成结果渲染到 FBO (FrameBuffer Object) 上

将 YUV 数据渲染到 FBO 这一操作并不常见, 这里简单描述一下操作过程; 具体地的操作实现可以使用 MRT 多重渲染技术

将一张 R8 纹理绑定至 GL_COLOR_ATTACHMENT0, 作为 Y 分量输出

将一张 R8G8 纹理绑定至 GL_COLOR_ATTACHMENT1, 作为 NV 分量输出

  • (5) 读取渲染结果至内存, 这里可以采用类似于 glReadPixels 的方式实现.

仔细看一下上图, 可以发现我特定将不同流程用不同的颜色标注了一下;
在不需要显示的情况下, 整条链路实际上还是以 CPU 作为 VPUGPU 的纽带,负责为二者相互传输数据.

到这里发现什么问题了吗? VPU -> CPU -> GPU 这个过程传输的并不是什么小数据, 而是 YUV 裸数据!!!
如果按照 1080P30 的规格计算, 每秒的带宽占用最少也在 746,496,000 bits/s, 这还仅仅是一路数据!

除此之外, CPUGPU 对于像素的理解也是不同的; 在 CPU 侧, RGBAuint32_t(0~255); 而在 GPU 侧, RGBA 则是 float(0.0f~1.0f)[4];

是的,当我们将纹理从 CPU 传输到 GPU 时; 我们需要将 uint8_t 除上 255 得到一个归一化的 float 给到 GPU; 起码在 ARM 上, 这一步实际是由 CPU 实现.

所以当你实际跑起来时, 会很奇怪会什么 CPU 跑得老高了并且帧率还提不上.

探索

在发现这个问题之后,我辗转研究了不少项目,尝试从中寻找解决方法;

其中比较重要的包含

在加上各位大佬的帮助,找了一种比较合理的解决方案; 但是其并没有被完整实现在某一个仓库里,故我打算花一点时间整理一下,写一下这个系列的文章.

对了, 补充一下结论; 这个流程是可以优化的, 正如这个 rk_mmp_demo 给出的示例代码; 不过如何实现在后面的文章再进行描述了.

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值