Jetson TK1でGLXでOpenGLを使ってみる

前回はEGLで組んでみましたが、折角普通のLinux,OpenGLが使えるボードということで、X11とGLXで前回同様のアプリケーションを作成してみようと思います。

NVIDIAでLinux OpenGL といえば、関数エントリが共有ライブラリに準備されていることで有名です。この組み込み用ではどうであるか確認してみます。

$ nm -Do /usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1

## 一部抜粋  ###

/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00067478 T glActiveStencilFaceEXT
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005ec80 T glActiveTexture
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00064688 T glActiveTextureARB
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006b58c T glActiveVaryingNV
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005d82c T glAlphaFunc
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006ed38 T glAlphaFuncx
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:000656d4 T glAreProgramsResidentNV
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005e4d8 T glAreTexturesResident
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00064568 T glAreTexturesResidentEXT
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005e19c T glArrayElement
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006440c T glArrayElementEXT
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006aa24 T glAttachObjectARB
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:000603f8 T glAttachShader
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005b800 T glBegin
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00061498 T glBeginConditionalRender
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006b154 T glBeginConditionalRenderNV
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006b10c T glBeginConditionalRenderNVX
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00066d08 T glBeginOcclusionQueryNV

今回のボードでも前例通り各関数の実体が含まれるようです。
そこで、GLヘッダを読み込む前に、 GL_GLEXT_PROTOTYPES (1) を定義して extern宣言させた状態にしておきます。

早速プログラムを示します。

#include 
#include 
#include 
#include 

#include 
#include 
#include 

#define GL_GLEXT_PROTOTYPES  (1)
#define GLX_GLXEXT_PROTOTYPES (1)

#include 
#include 
#include 

#include 

static Display* xdisp;
static Window  window;

static GLuint shaderProgram;
GLXContext glxContext;
XVisualInfo* visInfo;


void initializeOpenGL( int screen );
void terminateOpenGL();
void mainloop();

GLuint createShaderProgram();

int main() {
  xdisp = XOpenDisplay( NULL );
  if( xdisp == NULL ) { 
    fprintf( stderr, "Cannot open display.\n" );
    return -1; 
  }

  int screen = DefaultScreen( xdisp );
 
  initializeOpenGL( screen );

  XSelectInput( xdisp, window, KeyPressMask|ButtonPressMask|UnmapNotify );
  Atom atom, atom2;
  atom = XInternAtom( xdisp, "WM_DELETE_WINDOW", False );
  XSetWMProtocols( xdisp, window, &atom, 1 );

  atom2 = XInternAtom( xdisp, "WM_PROTOCOLS", False );

  XMapWindow( xdisp, window );
  XFlush( xdisp );

  shaderProgram = createShaderProgram();

  XEvent evt;
  bool isFinish = false;
  int frameCount = 0;
  timeval t0, t1;
  gettimeofday( &t0, NULL );
  const int countSecond = 5;

  do {
    while( XPending( xdisp ) ) {
      XNextEvent( xdisp, &evt );
      switch( evt.type ) {
      case ClientMessage:
        if( evt.xclient.message_type == atom2 && evt.xclient.data.l[0] == atom ) {
          XFlush( xdisp );
          isFinish = true;
        }
        break;
      case KeyPress:
        isFinish = true;
        break;
      }
    }
    mainloop();
    frameCount++;

    gettimeofday( &t1, NULL );
    if( t1.tv_sec * 1000000 + t1.tv_usec - t0.tv_sec * 1000000 - t0.tv_usec > countSecond * 1000000 ) {
      printf( "FPS: %.2f\n", frameCount / (float)countSecond );
      gettimeofday( &t0, NULL );
      frameCount = 0;
    }


  } while( !isFinish );

  glDeleteProgram( shaderProgram );
  terminateOpenGL();

  XDestroyWindow( xdisp, window );
  XCloseDisplay( xdisp );

  return 0;
}

void initializeOpenGL( int screen ) {
  int attrib[] = {
    GLX_RGBA, 
    GLX_RED_SIZE, 8,
    GLX_GREEN_SIZE, 8,
    GLX_BLUE_SIZE, 8,
    GLX_ALPHA_SIZE, 8,
    GLX_DOUBLEBUFFER, 
    GLX_DEPTH_SIZE, 24,
    None,
  };

  visInfo = glXChooseVisual( xdisp, 0, attrib );
  if( !visInfo ) {
    fprintf( stderr, "Error: invalid visInfo\n" );
    return; 
  }

  XSetWindowAttributes wattr;
  wattr.background_pixel = 0;
  wattr.border_pixel = 0;
  wattr.colormap = XCreateColormap( xdisp, RootWindow( xdisp, screen ), visInfo->visual, AllocNone );
  wattr.override_redirect = false;
  wattr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask ;
  unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
  window = XCreateWindow( xdisp, RootWindow( xdisp, screen ), 0, 0, 640, 480, 0, visInfo->depth, InputOutput, visInfo->visual, mask, &wattr );

  glxContext = glXCreateContext( xdisp, visInfo, NULL, True );
  glXMakeCurrent( xdisp, window, glxContext );

  printf( "GL_RENDERER: %s\n", (char*)glGetString( GL_RENDERER ) ); 
  printf( "GL_VENDOR: %s\n", (char*)glGetString( GL_VENDOR ) );
  printf( "GL_VERSION: %s\n", (char*)glGetString( GL_VERSION ) );
}

void terminateOpenGL() {
  glXDestroyContext( xdisp, glxContext );
}


static GLchar srcVertexShader[] =
  "attribute vec4 position0;\n"
  "attribute vec4 color0;\n"
  "varying vec4 vsout_color0;\n"
  "uniform float  theta;\n"
  "void main() {\n"
  "  gl_Position = position0;\n"
  "  gl_Position.x = position0.x * cos(theta) - position0.y * sin(theta);\n"
  "  gl_Position.y = position0.x * sin(theta) + position0.y * cos(theta);\n"
  "  vsout_color0 = color0;\n"
  "}";
 
static GLchar srcFragmentShader[] =
  "precision mediump float;\n"
  "varying vec4 vsout_color0;\n"
  "void main() {\n"
  "  gl_FragColor = vsout_color0;\n"
  "}";
 
void checkCompiled( GLuint shader ) {
  GLint status;
  glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
  if( status != GL_TRUE ) {
    GLint length;
    glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &length );
    if( length ) {
      char* buf = (char*)malloc( length );
      glGetShaderInfoLog( shader, length, NULL, buf );
      fprintf( stderr, "CompiledLog: %s\n", buf );
      free( buf );
    }
    exit( EXIT_FAILURE );
  }
 
}
 
GLuint createShaderProgram() {
  GLuint shaderVS = glCreateShader( GL_VERTEX_SHADER );
  GLuint shaderFS = glCreateShader( GL_FRAGMENT_SHADER );
 
  GLsizei length;
  GLchar* vsSources[] = {
    srcVertexShader,
  };
  GLchar* fsSources[] = {
    srcFragmentShader,
  };
 
  glShaderSource( shaderVS, 1, (GLchar**) &vsSources, NULL );
  glCompileShader( shaderVS );
  checkCompiled( shaderVS );
 
  glShaderSource( shaderFS, 1, (GLchar**) &fsSources, NULL );
  glCompileShader( shaderFS );
  checkCompiled( shaderFS );
 
  GLuint program;
  program = glCreateProgram();
  glAttachShader( program, shaderVS );
  glAttachShader( program, shaderFS );
 
  glLinkProgram( program );
 
  return program;
}

void mainloop() {
  static unsigned int count = 0;
  static float angle = 0;

  glClearColor( 0.25f, 0.25f, 0.25f, 0.0f );
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  glUseProgram( shaderProgram );

  GLint locPos = glGetAttribLocation( shaderProgram, "position0" );
  GLint locColor = glGetAttribLocation( shaderProgram, "color0" );
  float vertices[] = {
    0.0f, 0.0f, 0.0f,   0.0f, 1.0f, 0.0f, 1.0f,
    1.0f, 0.0f, 0.0f,   1.0f, 0.0f, 1.0f, 1.0f,
    0.5f, 0.5f, 0.0f,   1.0f, 1.0f, 0.0f, 1.0f,
  };
  GLint stride = sizeof(float)*7;
  glVertexAttribPointer( locPos, 3, GL_FLOAT, false, stride, &vertices[0] );
  glVertexAttribPointer( locColor, 4, GL_FLOAT, false, stride, &vertices[3] );
  glEnableVertexAttribArray( locPos );
  glEnableVertexAttribArray( locColor );

  glUniform1f( glGetUniformLocation( shaderProgram, "theta" ), count*0.001f );
  glDrawArrays( GL_TRIANGLES, 0, 3 );

  glXSwapBuffers( xdisp, window );
  count++;
}

このプログラムを実行してみたのがこんな感じです。
Ubuntu-screenshot-glx

GL_RENDERER: GK20A/AXI
GL_VENDOR: NVIDIA Corporation
GL_VERSION: 4.4.0 NVIDIA 19.3
FPS: 1294.80
FPS: 1151.00
FPS: 1046.20
FPS: 1073.00
FPS: 1049.40
FPS: 1051.40
FPS: 987.60
FPS: 995.60
FPS: 1008.20
FPS: 1582.60

平均するとおよそ1000ちょいのFPSといったところでしょうか。前回のEGLに比べると多少パフォーマンスがよい傾向にありそうです。
VSyncをオフにしてみようと思ったのですが、 glXSwapIntervalEXT がこの環境では使用できず試してみることは出来ませんでした。コンテキストは予想通り最新の 4.4 が取得されました。

プログラムコードがglVertexAttribPointerでクライアント配列を渡している部分があったり、毎描画フレームで無駄な処理をしているところが多いので、もしかするとCPU側でバラツキの要因を持っているのかもしれません。

OpenGL プログラミング
すらりんをフォローする
すらりん日記

コメント

タイトルとURLをコピーしました