为什么在iMX53上YUV420到RGB转换速度慢?

时间:2014-03-03 14:33:49

标签: opengl-es shader rgb yuv

我有一个工作链,其中iMX53上的GPU(AMD Z430)采用YUV420P格式的解码视频帧,转换为RGB565并显示它。我唯一关心的是速度,更确切地说是缺乏速度。输入视频帧为1920x1088 YUV420P,转换时间为40ms,我只是不能让它运行得更快。我试图优化我的着色器,没有运气。我也尝试过2D色域,它甚至更慢(并且由于它的2D性质,它提供了一些不正确的颜色)。当然,我不是OpenGL ES专家。

以下是我的着色器:

static const char *fragment_shader_yuv_src =
    "const lowp mat3 rgb_coeff = mat3(1, 1, 1, 0, -0.344, 1.772, 1.402, -0.714, 0);\n"
    "varying lowp vec2 v_texcoord;\n"
    "uniform lowp sampler2D s_texture_y;\n"
    "uniform lowp sampler2D s_texture_u;\n"
    "uniform lowp sampler2D s_texture_v;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    lowp vec3 yuv = vec3(texture2D(s_texture_y, v_texcoord).r, texture2D(s_texture_u, v_texcoord).r - 0.5, texture2D(s_texture_v, v_texcoord).r - 0.5);\n"
    "    gl_FragColor = vec4(rgb_coeff * yuv, 1.0);\n"
    "}\n";

static const char *vertex_shader_yuv_src =
    "attribute lowp vec4 position; \n"
    "attribute lowp vec2 texcoord; \n"
    "varying lowp vec2 v_texcoord; \n"
    "                              \n"
    "void main()                   \n"
    "{                             \n"
    "    gl_Position = position;   \n"
    "    v_texcoord = texcoord.xy; \n"
    "}                             \n";

s_texture_y / u / v包含适当的颜色分量,图像由eglCreateImageKHR(...)分配,并由glEGLImageTargetTexture2DOES(...)分配给纹理。

正如我上面提到的,它有效但速度慢。我无法确定这是GPU的最高性能还是我在着色器中做了一些非常错误的事情...

(用最简单的着色器升级和绘制一个简单的416x416 RGBA32图像也非常慢,~23ms)

任何人有任何想法,经验?我该如何优化着色器?

1 个答案:

答案 0 :(得分:2)

乍一看,你的着色器在性能方面看起来并不太糟糕。 (有关参考,请查看gst-plugins-gl的glupload.c文件,其中典型的转换在着色器中完成,包括OpenGL和OpenGL ES。)

缺乏性能,没有进入平台细节,可能完全是由于上传到GPU的代价。您是否尝试使用虚拟片段着色器?即:

void main (void)
{
   gl_FragColor = vec4 (0.0, 1.0, 0.0, 1.0);
}

以不同的分辨率上传你的相框?我的猜测是,即使对于微小的帧,你也会产生大约10,20ms的大时间损失,这是因为所有正在进行的计算都需要完成并且管道在注入新数据之前刷新(即上传是一个从GPU的角度看同步操作)。

如果罚款很大,您可以尝试使用双上传到GPU(请参阅this post),看看它是否能改善您的特定驱动程序+硬件。

最后,在你的着色器和glupload.c中,使用3种不同的纹理,每个通道一个,以及使用从CPU代码传递的制服不会有助于提高性能。您可以尝试两件事:一,用三个通道YUV背靠背上传一组数据,然后将输出像素到yuv坐标逻辑带入着色器本身,如下所示:

void main (void)
{ 
   vec2 y_coord = <calculate the position to find the Y component for this pixel>
   vec2 u_coord = <calculate the position to find the U component for this pixel>
   vec2 v_coord = <calculate the position to find the V component for this pixel>
   float y_value = texture2D(s_texture, y_coord).<appropriate channel>
   float u_value = texture2D(s_texture, u_coord).<appropriate channel>
   float v_value = texture2D(s_texture, v_coord).<appropriate channel>
   gl_FragColor = vec4 (rgb_coeff * vec3(y_value, u_value, v_value), 1.0);
}

如果上传不是瓶颈,我可以尝试进一步开发这个着色器......