glPopMatrix()在setup_hardware_state中大喊“不支持的纹理格式”

时间:2012-01-19 14:15:10

标签: c linux opengl textures yuv

我正在尝试在Linux的私有视频播放器中进行一些优化,旨在提高性能,因为播放MP4文件在CPU上很重,因为视频帧是用YV12编码的并且OpenGL不提供显示此格式的本机方式。现在有一个代码在CPU上运行,在图像发送到GPU进行显示之前将YV12转换为RGB,这会消耗100%的CPU处理。

我目前正在调查如何解码YV12帧而无需编写着色器来执行YV12 - > RGB转换。据我所知,一种方法是通过 GL_MESA_ycbcr_texture ,显然由我的系统支持(由glxinfo报告)。

在这款Fedora Box中我有一台 ATI Technologies Inc RV610视频设备[Radeon HD 2400 PRO] ,这是一款不错的视频卡。然后,我下载了yuvrect测试并进行了一些更改,以替换此卡支持的纹理GL_TEXTURE_RECTANGLE_NVGL_TEXTURE_RECTANGLE_ARB

然而,当我执行这个修改过的应用程序时,它会输出:

The MESA driver reports *unsupported texture format in setup_hardware_state*

我注意到从glPopMatrix();回调执行Display()时出现此错误。现在,这似乎不是我的应用程序中的错误,因为我在另一个具有不同视频卡的Fedora盒(同一系统)上运行了完全相同的代码: Intel Corporation Sandy Bridge Integrated图形控制器(rev 09),它可以很好地工作。

2个二进制文件之间唯一可见的区别是它们与之链接的库。在(有问题的)ATI卡上 ldd 报告:

linux-gate.so.1 =>  (0x00da3000)
libGL.so.1 => /usr/lib/libGL.so.1 (0x077bd000)
libGLU.so.1 => /usr/lib/libGLU.so.1 (0x0783b000)
libglut.so.3 => /usr/lib/libglut.so.3 (0x005a9000)
libGLEW.so.1.5 => /usr/lib/libGLEW.so.1.5 (0x00aa3000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x057e2000)
libm.so.6 => /lib/libm.so.6 (0x004e4000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x0053f000)
libc.so.6 => /lib/libc.so.6 (0x00358000)
libX11.so.6 => /usr/lib/libX11.so.6 (0x0071b000)
libXext.so.6 => /usr/lib/libXext.so.6 (0x009c5000)
libXdamage.so.1 => /usr/lib/libXdamage.so.1 (0x00af7000)
libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0x00b76000)
libXxf86vm.so.1 => /usr/lib/libXxf86vm.so.1 (0x0014e000)
libdrm.so.2 => /usr/lib/libdrm.so.2 (0x00101000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00510000)
libdl.so.2 => /lib/libdl.so.2 (0x0052d000)
libXi.so.6 => /usr/lib/libXi.so.6 (0x00110000)
/lib/ld-linux.so.2 (0x00337000)
libxcb.so.1 => /usr/lib/libxcb.so.1 (0x00859000)
librt.so.1 => /lib/librt.so.1 (0x00534000)
libXau.so.6 => /usr/lib/libXau.so.6 (0x00854000)

与此同时,在英特尔卡上,您可以看到它与libv4l和其他一些库链接,而ATI则没有!我想知道这与我面临的问题有什么关系:

linux-gate.so.1 =>  (0x008d6000)
/usr/lib/libv4l/v4l1compat.so (0x00345000)
libGL.so.1 => /usr/lib/libGL.so.1 (0x4fb85000)
libGLU.so.1 => /usr/lib/libGLU.so.1 (0x4fc10000)
libglut.so.3 => /usr/lib/libglut.so.3 (0x005a9000)
libGLEW.so.1.5 => /usr/lib/libGLEW.so.1.5 (0x4fc82000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x42ca7000)
libm.so.6 => /lib/libm.so.6 (0x41fbc000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x42017000)
libc.so.6 => /lib/libc.so.6 (0x41e30000)
libv4l1.so.0 => /usr/lib/libv4l1.so.0 (0x00110000)
libX11.so.6 => /usr/lib/libX11.so.6 (0x421f8000)
libXext.so.6 => /usr/lib/libXext.so.6 (0x424c0000)
libXdamage.so.1 => /usr/lib/libXdamage.so.1 (0x42c0e000)
libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0x42d98000)
libXxf86vm.so.1 => /usr/lib/libXxf86vm.so.1 (0x432a2000)
libdrm.so.2 => /usr/lib/libdrm.so.2 (0x4247b000)
libpthread.so.0 => /lib/libpthread.so.0 (0x41fe8000)
libdl.so.2 => /lib/libdl.so.2 (0x42005000)
libXi.so.6 => /usr/lib/libXi.so.6 (0x42748000)
/lib/ld-linux.so.2 (0x41e0f000)
libv4l2.so.0 => /usr/lib/libv4l2.so.0 (0x4217c000)
libxcb.so.1 => /usr/lib/libxcb.so.1 (0x42337000)
librt.so.1 => /lib/librt.so.1 (0x4200c000)
libv4lconvert.so.0 => /usr/lib/libv4lconvert.so.0 (0x42357000)
libXau.so.6 => /usr/lib/libXau.so.6 (0x421f3000)
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x43317000)

如果您想运行以下示例,则需要readtex.creadtex.hgirl.rgb,并使用以下代码进行编译:{{1​​}}

g++ yuvrect.cpp -o yuvrect -lGL -lGLU -lglut -lGLEW

解决这个问题的任何提示,伙计们?

1 个答案:

答案 0 :(得分:5)

这很可能会被解决为驱动程序错误或其他问题。我不会帮你的。然而,回避着色器是不值得的。使用着色器,您可以忘记GL_MESA_ycbcr_texture并使您的应用更兼容。

我们将使用普通的旧GL_LUMINANCE_ALPHA格式,因此图像加载变为:

glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,
            GL_LUMINANCE_ALPHA, ImgWidth, ImgHeight, 0,
            GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, ImageYUV);

glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,
               0, 0, ImgWidth, ImgHeight,
               GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, ImageYUV);

然后关于着色器:

static const char *p_s_vertex_shader =
    "varying vec2 t;"
    "void main()"
    "{"
    "    t = gl_MultiTexCoord0.xy;"
    "    gl_Position = ftransform();"
    "}";
static const char *p_s_fragment_shader =
    "#extension GL_ARB_texture_rectangle : enable\n"
    "varying vec2 t;"
    "uniform sampler2DRect tex;"
    "void main()"
    "{"
    "    vec2 tcEven = vec2(floor(t.x * .5) * 2.0, t.y);"
    "    vec2 tcOdd = vec2(tcEven.x + 1.0, t.y);"
    "    float Cb = texture2DRect(tex, tcEven).x - .5;"
    "    float Cr = texture2DRect(tex, tcOdd).x - .5;"
    "    float y = texture2DRect(tex, t).w;" // redundant texture read optimized away by texture cache
    "    float r = y + 1.28033 * Cr;"
    "    float g = y - .21482 * Cb - .38059 * Cr;"
    "    float b = y + 2.12798 * Cb;"
    "    gl_FragColor = vec4(r, g, b, 1.0);"
    "}";
int v = glCreateShader(GL_VERTEX_SHADER);
int f = glCreateShader(GL_FRAGMENT_SHADER);
int p = glCreateProgram();
glShaderSource(v, 1, &p_s_vertex_shader, 0);
glShaderSource(f, 1, &p_s_fragment_shader, 0);
glCompileShader(v);
//CheckShader(v);
glCompileShader(f);
//CheckShader(f);
glAttachShader(p, v);
glAttachShader(p, f);
glLinkProgram(p);
glUseProgram(p);
glUniform1i(glGetUniformLocation(p, "tex"), 0);

这是在纹理之后,在Init()的末尾。就是这样,就像一个魅力。对于调试,最好也包括CheckShader()(它在着色器中报告编译错误):

bool CheckShader(int n_shader_object)
{
    int n_tmp;
    glGetShaderiv(n_shader_object, GL_COMPILE_STATUS, &n_tmp);
    bool b_compiled = n_tmp == GL_TRUE;
    int n_log_length;
    glGetShaderiv(n_shader_object, GL_INFO_LOG_LENGTH, &n_log_length);
    // query status ...

    if(n_log_length > 1) {
        char *p_s_temp_info_log;
        if(!(p_s_temp_info_log = (char*)malloc(n_log_length)))
            return false;
        int n_tmp;
        glGetShaderInfoLog(n_shader_object, n_log_length, &n_tmp,
            p_s_temp_info_log);
        assert(n_tmp <= n_log_length);

        fprintf(stderr, "%s\n", p_s_temp_info_log);
        free(p_s_temp_info_log);
    }
    // get/concat info-log

    return b_compiled;
}

着色器版本可能比硬件优化版本慢一点,但我想说没什么可担心的。

如果您决定尝试使用该代码,并且遇到任何问题,请告诉我......

编辑:实际上在ATi上运行此操作时遇到了问题,最后发现传输变量“t”时出错,换句话说这不起作用:

static const char *p_s_vertex_shader =
    "varying vec2 t;"
    "void main()"
    "{"
    "    t = gl_MultiTexCoord0.xy;"
    "    gl_Position = ftransform();"
    "}";
static const char *p_s_fragment_shader =
    "#extension GL_ARB_texture_rectangle : enable\n"
    "varying vec2 t;"
    "uniform sampler2DRect tex;"
    "void main()"
    "{"
    "    gl_FragColor = texture2DRect(tex, t);"
    "}";

为了轻松解决这个问题,可以删除顶点着色器并让固定管道写入纹理坐标。所以这也适用于ATi:

static const char *p_s_vertex_shader = null; // no vertex shader
static const char *p_s_fragment_shader =
    "#extension GL_ARB_texture_rectangle : enable\n"
    "uniform sampler2DRect tex;"
    "void main()"
    "{"
    "    vec2 t = gl_TexCoord[0];" // use fixed pipeline output 
    "    gl_FragColor = texture2DRect(tex, t);"
    "}";