Jetson TK1 で EGLを使ってみる

検索でライブラリは見つかるものの標準パスの位置にlibEGLやlibGLESv2らの共有オブジェクトがなかったので、下記のようにしてシンボリックリンクを張ってみました。

cd /usr/lib/arm-linux-gnueabihf
sudo ln -s tegra-egl/libEGL.so.1  libEGL.so
sudo ln -s tegra-egl/libGLESv2.so.2 libGLESv2.so

標準では EGLやGLES2のヘッダがないために、Khronos OpenGL ES Registry からダウンロードしてきます。ダウンロードしたファイルらはとりあえずプログラムと同じ場所にディレクトリ構成があうようにして配置しました。
使用したプログラムはこのようなものです。

#include 
#include 
#include 
#include 

#include 
#include 
#include 

#include "EGL/egl.h"
#include "GLES2/gl2.h"

#include 

static Display* xdisp;
static Window  window;

EGLDisplay eglDisplay;
EGLContext eglContext;
EGLSurface eglSurface;

static GLuint shaderProgram;

void initializeEGL();
void terminateEGL();
void mainloop();

GLuint createShaderProgram();

int main() {
  xdisp = XOpenDisplay( NULL );
  if( xdisp == NULL ) { return -1; }

  Window rootWin = DefaultRootWindow( xdisp );
  int screen = DefaultScreen( xdisp );
  unsigned long white = WhitePixel( xdisp, screen );
  unsigned long black = BlackPixel( xdisp, screen );
 
  window = XCreateSimpleWindow( xdisp, rootWin, 100, 100, 640, 480, 2, black, white );
  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 );

  initializeEGL();
  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 );
  terminateEGL();

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

  return 0;
}


void initializeEGL() {
  eglDisplay = eglGetDisplay( (EGLNativeDisplayType) xdisp );
  if( eglDisplay == EGL_NO_DISPLAY ) {
    fprintf( stderr, "NO EGL DISPLAY\n" );
    return;
  }
  if( !eglInitialize( eglDisplay, NULL, NULL ) ) {
    fprintf( stderr, "Unable to initialize EGL\n" );
    return;
  }

  EGLint attr[] = {
    EGL_RED_SIZE, 8, 
    EGL_GREEN_SIZE, 8, 
    EGL_BLUE_SIZE, 8, 
    EGL_ALPHA_SIZE, 8,
    EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE,
  };
  EGLConfig cfg;
  EGLint numConfigs = 0;
  if( !eglChooseConfig( eglDisplay, attr, &cfg, 1, &numConfigs )) {
    fprintf( stderr, "Failed to choose config.\n" );
    return;
  }
  eglSurface =eglCreateWindowSurface( eglDisplay, cfg, window, NULL );
  if( eglSurface == EGL_NO_SURFACE ) {
    return;
  }
  EGLint ctxAttr[] = {
    EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE,
  };
  eglContext = eglCreateContext( eglDisplay, cfg, EGL_NO_CONTEXT, ctxAttr );
  if( eglContext == EGL_NO_CONTEXT ) {
    fprintf( stderr, "Unable to create EGL context. (%d).\n", eglGetError() );
    return;
  }
  eglMakeCurrent( eglDisplay, eglSurface, eglSurface, eglContext );

  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 ) );

  printf( "EGL_VENDOR : %s\n", eglQueryString( eglDisplay, EGL_VENDOR ) );
  printf( "EGL_VERSION: %s\n", eglQueryString( eglDisplay, EGL_VERSION ) );
  printf( "EGL_CLIENT_APIS : %s\n", eglQueryString( eglDisplay, EGL_CLIENT_APIS ) );

  eglSwapInterval( eglDisplay, 0 );

}
void terminateEGL() {
  eglDestroyContext( eglDisplay, eglContext );
  eglDestroySurface( eglDisplay, eglSurface );
  eglTerminate( eglDisplay );
}


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;
  float v = sinf( count * 0.001f ) + 1;
  v *= 0.5f;

  glClearColor( 0.25f, 0.25f, v, 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,   1.0f, 0.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 );

  eglSwapBuffers( eglDisplay, eglSurface );
  count++;
}

これを動かすと、こんな感じになります。
Ubuntu-screenshot-egl

GL_RENDERER: GK20A/AXI
GL_VENDOR: NVIDIA Corporation
GL_VERSION: OpenGL ES 3.0 19.3
EGL_VENDOR : NVIDIA
EGL_VERSION: 1.4
EGL_CLIENT_APIS : OpenGL_ES OpenGL
FPS: 262.60
FPS: 177.60
FPS: 155.40
FPS: 167.00
FPS: 169.40
FPS: 257.00
FPS: 269.20
FPS: 177.00

このバージョンでは既にOpenGL ES 3.0 のコンテキストとなっているようです。
GLESv2のライブラリをリンクして、プログラム中では ES 2.0 を指定しているつもりでしたが、ちょっと奇妙な状態です。

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

コメント

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