先日NVIDIAのドライバをインストールした Ubuntu ですが、なんとEGLやGLES2についてのライブラリをもっているようでした。(331.20ではダメだった・・・)
$ find /usr/ 2>/dev/null | grep GLES /usr/lib32/libGLESv1_CM.so.1 /usr/lib32/libGLESv1_CM.so.331.49 /usr/lib32/libGLESv2.so.2 /usr/lib32/libGLESv2.so /usr/lib32/libGLESv2.so.331.49 /usr/lib32/libGLESv1_CM.so
これは X 上で EGL & GLES2が使えるんじゃないかと思い試してみることにしました。
まずXのヘッダやライブラリをインストールします.
$ sudo apt-get install xorg-dev
/usr/include/features.h:324:26: 致命的エラー: bits/predefs.h: そのようなファイルやディレクトリはありません
32bitビルドする際には上記のようなエラーメッセージが出てしまうので、libc6-dev-i386 パッケージをインストールして対応します。またC++の標準ライブラリについても同様にエラーが生じてしまうのでこちらは g++-multilib をインストールして対応します。
sudo apt-get install libc6-dev-i386 g++-multilib
作成したプログラムは以下のようなものです。サンプルなのですごく適当です。
まずはGLXというかウィンドウ生成部分についてです。
#include#include #include #include #include #include #include #include #include static Display* xdisp; static Window window; EGLDisplay eglDisplay; EGLContext eglContext; EGLSurface eglSurface; int main() { xdisp = XOpenDisplay( NULL ); if( xdisp == NULL ) { return -1; u } 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 ); XMapWindow( xdisp, window ); if( initializeEGL() < 0 ) { exit( EXIT_FAILURE ); } GLuint shaderProgram = createShaderProgram(); mainLoop( shaderProgram ); glDeleteProgram( shaderProgram ); eglDestroyContext( eglDisplay, eglContext ); eglDestroySurface( eglDisplay, eglSurface ); eglTerminate( eglDisplay ); XDestroyWindow( xdisp, window ); XCloseDisplay( xdisp ); return 0; }
EGLの初期化部分はこんな感じです。
int initializeEGL() {
eglDisplay = eglGetDisplay( (EGLNativeDisplayType) xdisp );
if( eglDisplay == EGL_NO_DISPLAY ) {
fprintf( stderr, "NO EGL DISPLAY\n" );
return -1;
}
if( !eglInitialize( eglDisplay, NULL, NULL ) ) {
fprintf( stderr, "Unable to initialize EGL\n" );
return -1;
}
EGLint attr[] = {
EGL_BUFFER_SIZE, 16,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES2_BIT,
EGL_NONE,
};
EGLConfig cfg;
EGLint numConfigs;
if( !eglChooseConfig( eglDisplay, attr, &cfg, 1, &numConfigs ) ) {
fprintf( stderr, "Failed to choose config.\n" );
return -1;
}
if( numConfigs != 1 ) {
fprintf( stderr, "exactly one config. (%d)\n", numConfigs );
return -1;
}
eglSurface = eglCreateWindowSurface( eglDisplay, cfg, window, NULL );
if( eglSurface == EGL_NO_SURFACE ) {
fprintf( stderr, "Unable to create surface (eglError=%d)\n", eglGetError() );
return -1;
}
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 -1;
}
eglMakeCurrent( eglDisplay, eglSurface, eglSurface, eglContext );
char* p = (char*)glGetString( GL_RENDERER );
if( p ) {
printf( "RENDERER: %s\n", p );
}
return 0;
}
メインループとなっているGLの描画部分とリソース生成部分はこんな感じ。
static GLchar srcVertexShader[] =
"attribute vec4 position0;\n"
"attribute vec2 texcoord0;\n"
"varying vec2 vsout_texcoord0;\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_texcoord0 = texcoord0;\n"
"}";
static GLchar srcFragmentShader[] =
"precision mediump float;\n"
"varying vec2 vsout_texcoord0;\n"
"void main() {\n"
" gl_FragColor = vec4( vsout_texcoord0.xy, 0, 1 );\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( GLuint shaderProgram ) {
XEvent evt;
bool isEnd = false;
while( !isEnd ) {
while( XPending( xdisp ) ) {
XNextEvent( xdisp, &evt );
switch( evt.type ) {
case KeyPress:
isEnd = true;
break;
}
}
glClearColor( 0.25f, 0.25f, 0.125f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram( shaderProgram );
GLint locPos = glGetAttribLocation( shaderProgram, "position0" );
GLint locUV0 = glGetAttribLocation( shaderProgram, "texcoord0" );
float vertices[] = {
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
};
glVertexAttribPointer( locPos, 3, GL_FLOAT, false, sizeof(float)*5, &vertices[0] );
glVertexAttribPointer( locUV0, 2, GL_FLOAT, false, sizeof(float)*5, &vertices[3] );
glEnableVertexAttribArray( locPos );
glEnableVertexAttribArray( locUV0 );
static int count = 0;
glUniform1f( glGetUniformLocation( shaderProgram, "theta" ), count*0.001f );
glDrawArrays( GL_TRIANGLES, 0, 3 );
// usleep( 1000 );
eglSwapBuffers( eglDisplay, eglSurface );
count++;
}
}
これらを動かしてみてスクリーンショットをとったのが以下の図です。
無事にEGL+GLES2で三角形が描画されました。ちゃんとGLES2用として動いているようで、シェーダーで precision 設定を忘れたらコンパイルが通りませんでした。

おまけ
このソースコードのビルドには以下のオプションを設定しています。
32bitコンパイルすることを忘れないようにしましょう。
g++ -m32 -g -I/usr/include -I./ -lX11 -lEGL -lGLESv2 -L/usr/lib/i386-linux-gnu
また、Xの転送をしている場合、eglの初期化で失敗するようです。
自分の環境ではウィンドウをWindows7上のCygwin Xサーバーへ転送させるようにして処理していたのですが、これでは初期化で失敗しました。少なくともEGL使用時にはネットワークをまたぐことはできないようです(たぶん)。
まとめ
LinuxでもNVIDIAの最新ドライバをインストールすると EGL+GLES2を使用可能なことがわかりました。
ただ検索結果を見ても気付くように 32bit のものしか対応できない感じですね。今後ARM系も 64bit 化の波が来そうですし、その頃にはあわせて提供もされてくるのかな、と思いました。
