Wayland と weston でシンプルなアプリケーションを今まで作ってきましたが、このあたりで EGL を用いた方法に変更することにしました。他の情報ソースを見てみても、共有メモリ実装と EGL を使ったものの2種類に大別されているかなと思います。例によって調べてみて手探りでやっていたりするので、間違っていることもあるかと思いますのでご注意ください。
(Wayland プログラミングな書籍やまとめサイトっていつかできあがってくるのでしょうか)。
EGL について
Wayland (のコンポジッタ)は EGL に依存のみで動くようで、このあたりが X11 と違うと言われています。 X11 + OpenGL の場合では OpenGL が X11 の Drawable に依存が発生してしまうらしいです。EGL は基礎的なレイヤーに位置するらしく、 OpenGL, OpenGL ES, OpenVG といった他の API をバインドして動かすことができるような仕組みになっています。
強引な言い方をすれば、 GLX, WGL といったプラットフォーム依存の部分を共通化してくれたレイヤ・ライブラリということになるかと思います。
EGLを用いた実装へ変更
今までのコードのうち共有メモリを作成した部分を除去して、 EGL 実装に変更します。具体的には、 initEGL 関数を追加して、 wl_egl_window_create, eglCreateWindowSurface によりウィンドウの中身を作っていく感じになります。また、今までは frame_lister のコールバック関数で内容の反映を行ってアニメーション的なことをさせていました。この部分が変更になっています。 OpenGL ES による描画を行った後、 eglSwapBuffers を呼び出してウィンドウ画面の更新を行っています。
initEGL についてはこのような実装となりました。
void WaylandCore::initEGL() { EGLint major,minor; EGLConfig* configs; EGLint attrib[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE, }; EGLint context_attrib[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, }; mEglDisplay = eglGetDisplay( (EGLNativeDisplayType)mDisplay ); if( mEglDisplay == EGL_NO_DISPLAY ) { fprintf( stderr, "Cannot create egl display.\n" ); } if( eglInitialize(mEglDisplay, &major, &minor ) != EGL_TRUE ) { fprintf( stderr, "Cannot initialize egl display.\n" ); } printf( "EGL major: %d, minor : %d\n", major, minor ); EGLint count = 0; int n = 0; eglGetConfigs( mEglDisplay, NULL, 0, &count ); configs = (EGLConfig*) malloc( count * sizeof(EGLConfig) ); eglChooseConfig( mEglDisplay, attrib, configs, count, &n ); for( int i=0;iWindow サーフェースを作っている部分のコード抜粋は以下のようになっています。
wl_surface* surface = wl_compositor_create_surface( mCompositor ); wl_shell_surface* shell_surface = wl_shell_get_shell_surface( mShell, surface ); wl_shell_surface_set_toplevel( shell_surface ); wl_shell_surface_set_title( shell_surface, title ); wl_shell_surface_add_listener( shell_surface, &shell_surf_listeners, this ); mShellSurface = shell_surface; mSurface.surface = surface; mEglWindow = wl_egl_window_create( surface, mWidth, mHeight ); mSurface.eglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglWindow, NULL );より詳細については、リポジトリにあるソースコードをご確認ください。リポジトリにあるデータには OpenGL ES 2.0 で描画するのに必要になったデータ構造やシェーダーの初期化なども含まれています。
動作状況
せっかく OpenGL が使える状態なので、モデルの描画などをいれてみました。割とコードが増えた感じではありますが、いつもの OpenGL で描画処理を行っているものと特に変更はありません。
まとめ
EGL + OpenGL ES 2.0 を用いて描画した結果、 main.cpp の中身自体は見慣れたものになってきました。
また共有メモリを使う版と比較してみても、Wayland としてのコード比率が下がったような気がします。単に EGL を見慣れているせいかもしれませんが。今回の内容については、GitHub の https://github.com/techlabxe/SimpleWindowWayland/tree/base-1.1 のタグを打ってあります。