glPopMatrix () выкрикивает «неподдерживаемый формат текстуры в setup_hardware_state» - PullRequest
6 голосов
/ 19 января 2012

Я пытаюсь оптимизировать частный видеопроигрыватель для Linux с целью повышения производительности, поскольку воспроизведение файлов MP4 сильно загружает процессор , поскольку видеокадры кодируются в YV12 и OpenGL не предоставляет собственный способ отображения этого формата. Прямо сейчас есть код, который выполняется на ЦПУ для преобразования YV12 в RGB перед отправкой изображения в графический процессор для отображения, и это потребляет 100% процессорной обработки.

В настоящее время я изучаю как декодировать кадры YV12 без необходимости писать шейдер для преобразования YV12 -> RGB. Насколько я понимаю, один из способов сделать это - через GL_MESA_ycbcr_texture , который, по-видимому, поддерживается моей системой (сообщает glxinfo).

В этой коробке Fedora у меня есть видеоустройство ATI Technologies Inc RV610 [Radeon HD 2400 PRO] , которое является достойной видеокартой. Затем я скачал тест yuvrect и внес несколько изменений, чтобы заменить GL_TEXTURE_RECTANGLE_NV для текстуры, поддерживаемой этой картой: GL_TEXTURE_RECTANGLE_ARB.

Однако, когда я запускаю это модифицированное приложение, оно выдает:

The MESA driver reports *unsupported texture format in setup_hardware_state*

Я заметил, что эта ошибка появляется при выполнении glPopMatrix(); из обратного вызова Display(). Теперь это не похоже на ошибку в моем приложении , потому что я запускал точно такой же код на другом компьютере Fedora (той же системы), на котором установлена ​​другая видеокарта: Intel Corporation Sandy Bridge Integrated Graphics Контроллер (рев 09) , и он прекрасно работает.

Единственное видимое различие между двумя двоичными файлами - это библиотеки, с которыми они связаны. На (проблемной) карте 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)

Между тем, на карте Intel вы можете видеть, что она связана с 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.c , readtex.h и girl.rgb и скомпилируйте его: g++ yuvrect.cpp -o yuvrect -lGL -lGLU -lglut -lGLEW

#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <GL/glew.h>
#include <GL/glut.h>

#include "readtex.c"   /* I know, this is a hack. */

#define TEXTURE_FILE "girl.rgb"

static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
static GLint ImgWidth, ImgHeight;
static GLushort *ImageYUV = NULL;


static void DrawObject(void)
{
   glBegin(GL_QUADS);

   glTexCoord2f(0, 0);
   glVertex2f(-1.0, -1.0);

   glTexCoord2f(ImgWidth, 0);
   glVertex2f(1.0, -1.0);

   glTexCoord2f(ImgWidth, ImgHeight);
   glVertex2f(1.0, 1.0);

   glTexCoord2f(0, ImgHeight);
   glVertex2f(-1.0, 1.0);

   glEnd();
}


static void Display( void )
{
   glClear( GL_COLOR_BUFFER_BIT );

   glPushMatrix();
      glRotatef(Xrot, 1.0, 0.0, 0.0);
      glRotatef(Yrot, 0.0, 1.0, 0.0);
      glRotatef(Zrot, 0.0, 0.0, 1.0);
      DrawObject();
   glPopMatrix(); // <--- error message comes from this call

   glutSwapBuffers();
}


static void Reshape( int width, int height )
{
   glViewport( 0, 0, width, height );
   glMatrixMode( GL_PROJECTION );
   glLoadIdentity();
   glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
   glMatrixMode( GL_MODELVIEW );
   glLoadIdentity();
   glTranslatef( 0.0, 0.0, -15.0 );
}


static void Key( unsigned char key, int x, int y )
{
   (void) x;
   (void) y;
   switch (key) {
      case 27:
         exit(0);
         break;
   }
   glutPostRedisplay();
}


static void SpecialKey( int key, int x, int y )
{
   float step = 3.0;
   (void) x;
   (void) y;

   switch (key) {
      case GLUT_KEY_UP:
         Xrot += step;
         break;
      case GLUT_KEY_DOWN:
         Xrot -= step;
         break;
      case GLUT_KEY_LEFT:
         Yrot += step;
         break;
      case GLUT_KEY_RIGHT:
         Yrot -= step;
         break;
   }
   glutPostRedisplay();
}        

static void Init( int argc, char *argv[] )
{
   GLuint texObj = 100;
   const char *file;

   printf("Checking GL_ARB_texture_rectangle\n");
   if (!glutExtensionSupported("GL_ARB_texture_rectangle")) {
      printf("Sorry, GL_NV_texture_rectangle is required\n");
      exit(0);
   }

   printf("Checking GL_MESA_ycbcr_texture\n");
   if (!glutExtensionSupported("GL_MESA_ycbcr_texture")) {
      printf("Sorry, GL_MESA_ycbcr_texture is required\n");
      exit(0);
   }

   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texObj);
#ifdef LINEAR_FILTER
   /* linear filtering looks much nicer but is much slower for Mesa */
   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#else
   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#endif

   if (argc > 1)
      file = argv[1];
   else
      file = TEXTURE_FILE;

   ImageYUV = LoadYUVImage(file, &ImgWidth, &ImgHeight);
   if (!ImageYUV) {
      printf("Couldn't read %s\n", TEXTURE_FILE);
      exit(0);
   }

   printf("Image: %dx%d\n", ImgWidth, ImgHeight);

   printf("Calling glTexImage2D\n");
   glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,
                GL_YCBCR_MESA, ImgWidth, ImgHeight, 0,
                GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, ImageYUV);
   printf("Called glTexImage2D\n");
   assert(glGetError() == GL_NO_ERROR);
   printf("* Assert #1\n");

   glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,
                   0, 0, ImgWidth, ImgHeight,
                   GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, ImageYUV);

   assert(glGetError() == GL_NO_ERROR);
   printf("* Assert #2\n");

   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

   glEnable(GL_TEXTURE_RECTANGLE_ARB);

   glShadeModel(GL_FLAT);
   glClearColor(0.3, 0.3, 0.4, 1.0);

   if (argc > 1 && strcmp(argv[1], "-info")==0) {
      printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
      printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
      printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
      printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
   }
}


int main( int argc, char *argv[] )
{
   glutInit( &argc, argv );
   glutInitWindowSize( 300, 300 );
   glutInitWindowPosition( 0, 0 );
   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
   glutCreateWindow(argv[0] );
   glewInit();

   Init( argc, argv );

   glutReshapeFunc( Reshape );
   glutKeyboardFunc( Key );
   glutSpecialFunc( SpecialKey );
   glutDisplayFunc( Display );

   glutMainLoop();
   return 0;
}

Любые советы, чтобы решить эту проблему, ребята?

1 Ответ

5 голосов
/ 20 января 2012

это, скорее всего, может быть связано с ошибкой драйвера или чем-то еще. Я не помогу тебе с этим. Однако не стоит уклоняться от шейдеров. Используя шейдеры, вы можете забыть о 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);"
    "}";
...