先日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 化の波が来そうですし、その頃にはあわせて提供もされてくるのかな、と思いました。