Opengl es 为什么iMX53上的YUV420到RGB转换速度慢?

Opengl es 为什么iMX53上的YUV420到RGB转换速度慢?,opengl-es,shader,rgb,yuv,Opengl Es,Shader,Rgb,Yuv,我有一个工作链,iMX53上的GPU(AMDZ430)将YUV420P格式的解码视频帧转换成RGB565并显示出来。我唯一关心的是速度,更确切地说是缺乏速度。输入视频帧是1920x1088 YUV420P,转换时间是40ms,我根本无法让它运行得更快。我试图优化我的着色器,但运气不佳。我也尝试过2D色域,它甚至更慢(由于它的2D特性,它提供了一些不正确的颜色)。当然,我不是OpenGL ES专家 以下是我的着色器: static const char *fragment_shader_yuv_s

我有一个工作链,iMX53上的GPU(AMDZ430)将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_纹理_y/u/v包含适当的颜色分量,图像由eglCreateImageKHR(…)分配,并由glEGLImageTargetTexture2DOES(…)分配给纹理

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

(使用最简单的着色器放大和绘制简单的416x416 RGBA32图像也非常缓慢,约23ms)


有人有什么想法、经验吗?如何优化我的着色器?

乍一看,您的着色器在性能方面还不错。(为了便于参考,请查看gst插件gl文件,其中OpenGL和OpenGL ES的典型转换都是在着色器中完成的)

在不涉及平台细节的情况下,性能的缺乏完全可以归因于上传到GPU的惩罚。您是否尝试过使用虚拟片段着色器?i、 e:

void main (void)
{
   gl_FragColor = vec4 (0.0, 1.0, 0.0, 1.0);
}
上传不同分辨率的画面时?我的猜测是,即使是很小的帧,您也会遭受巨大的时间损失~10,20ms,这是因为在注入新数据之前,需要完成所有正在进行的计算并刷新管道(即,从GPU的角度来看,上传是一种同步操作)

如果代价很大,您可以尝试使用双重上传到GPU(请参阅),看看它是否改善了特定的驱动程序+硬件

最后,在着色器和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);
}
void主管道(void)
{ 
向量2 y_坐标=
vec2 u_coord=
vec2 v_coord=
浮动y_值=纹理2D(s_纹理,y_坐标)。
浮动u_值=纹理2D(s_纹理,u_坐标)。
浮动v_值=纹理2D(s_纹理,v_坐标)。
gl_FragColor=vec4(rgb_系数*vec3(y_值、u_值、v_值),1.0);
}

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

谢谢你的回答。我已经用虚拟片段着色器试用过,1920x1088的渲染时间约为17ms。相当慢。我担心内存带宽不够。。。在许多情况下,我在iMX53上看到过类似的问题。GPU根本无法从支持DMA的内存中足够快地复制数据(这台机器上没有缓冲和缓存,因此速度非常慢)。顺便说一下,我在这台机器上不使用glTexImage2D,因为速度非常慢。。。相反,纹理存储在eglCreateImageKHR图像中。那么双纹理解决方案如何:分配两个纹理,使用一个进行转换,同时以某种方式使用另一个进行上载?好的,视频帧现在直接解码为eglCreateImageKHR分配的图像,因此我根本不执行memcpy(…)或任何类似操作。GPU必须将这些字节复制到它的内存中(或者别的什么),我相信我不能保存这些字节…在检查iMX6Solo之后,我觉得iMX53中的GPU显然没有足够的能力以我需要的速度执行这项任务。iMX6Solo的Vivante GPU的速度至少快2.5倍,并且具有原生YUV纹理支持,因此无需使用自定义着色器将YUV转换为RGB。我不知道堆栈溢出礼仪是否允许这样做,但在我看来,Clay Montgomery可能是最有资格在飞思卡尔GPU上离题的人。。。