2012年3月25日日曜日

Khronos EGL and Apple EAGL

Open GL の「ESの」詳しいドキュメントがあったので、2ページ目補足ページを読みがてらのメモ。
元ネタ:Khronos EGL and Apple EAGL


話題は EGL と、Apple によって実装された EGL の API である EAGL である。OpenGL のアプリケーションがどのようにデバイスの描画に関わっているのかを解説する。

Objective-C および iOS にフォーカスしてます。他のデバイスでも同じように書けますが。


At a glance



実際にスクリーンに対して描画処理を担当するのは OpenGL ではなく、Khronos group が作った EGL API である。EGL はデバイスメーカーによって作りが違うので注意。


Setup EGL API


まず最初に「どこに内容を描画するか」を EGL に教える。
eglGetDisplay メソッド。EGLDisplay data type を返す。デフォルトのスクリーンならば EGL_DEFAULT_DISPLAY を引数で与える。

次は eglInitialize メソッドで初期化。


その次にいろいろ設定(色フォーマット、色、サイズ、透過などなど)をするわけだが、eglGetConfigseglChooseConfigs などの多数の便利メソッドが提供されているのでこれらを使えば良い。

最後にスクリーンの表に描画するのか、裏(オフスクリーン面)に描画するのかを指定する。しかしオフスクリーン面に書きたいのなら、OpenGL の API が提供するフレームバッファーに描画したほうが速い。

以上はプラットフォームごとの性質。ここからは OpenGL とのつながりを見ていく。


EGL Context


ここまでで EGL は描画機器への接続は完了したが、OpenGL との設定をしなければいけない。EGL は2つのフレームバッファを持っていて、OpenGL の描画を適正化している。

EGL にどこに「僕らが描画したい OpenGL のバッファ」があるかということを教えてやる。具体的には EGL Context をつくって、それを「現在の context」として設定すればOK。context は複数作成可能。設定してしまえば OpenGL で使っている subsequentな(?)フレームバッファが EGL context によって利用される。これらの設定は eglCreateContext() および eglmakeCurrent() のメソッドで行う。

ねえねえ、混乱してる?大丈夫さ。

ここで重要なのは「EGL context」が OpenGL とのつながりだ、ということを理解しておけばOK。


Rendering with EGL Context


設定が完了したのであとはバッファーを切り替えればOK。切替え?

EGLの1面が画像を表示しているとき、もう1面は裏で待機していて新しいレンダリングがされる。次の切替えタイミングでこの裏面が表に出て、表示される。それまで表だった面は裏になり初期化sれる(元ネタサイトの画像参照のこと)。

この手法はアプリケーションのパフォーマンスを向上させる。なぜなら描画コマンドの発行のたびに本当の画面が描画されるわけではないし、デバイスに直接よりもバッファに書きこむほうが速い。面の切り換えは eglSwapBuffers() メソッドで行われる。

手順のまとめ
  1. EGL API をメーカーから提供されるディスプレイと surface で初期化
  2. 僕らが決めた設定をセット
  3. context をつくって、それを現在の context として設定
  4. EGL に画面を切替えさせる


EAGL – The Apple’s EGL API


もっとも重要なことは「Apple は直接的な描画を許していない」ということ。Frame Buffer と Render Buffer を通しての作業ということになる。

なぜ?Cocoa Frameword は全く別種の言語であり、ルールが超厳しい。そして Apple は EGL の API  も Cocoa のルールに従うように修正した。

EAGL を使い、color render buffer を作って、これに出力を書き込む。そしてこのバッファを Apple 謹製の CAEAGLLayer と呼ばれるレイヤーに描画する。それから、context にこのバッファを発行するように頼む必要がある* 。実際にはこの命令はバッファーの切替えのようなものである。
(* 原文:ask the context to present that color render buffer.)


Setup EAGL API


まずは IUIView のサブクラスとして作り、 Core Animation layer を切り替える。具体的には以下のようなコードを書く。これは EGL API の初期化と同義。
+ (Class) layerClass
{
    return [CAEAGLLayer class];
}

次は各種設定
- (id) initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {
        // Assign a variable to be our CAEAGLLayer temporary.
        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[self layer];
 
        // Construct a dictionary with our configurations.
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:NO],
                             kEAGLDrawablePropertyRetainedBacking,
                             kEAGLColorFormatRGB565,
                             kEAGLDrawablePropertyColorFormat,
                             nil];
 
        // Set the properties to CAEALLayer.
        [eaglLayer setOpaque:YES];
        [eaglLayer setDrawableProperties:dict];
 
        // Other initializations...
    }
 
    return self;
}


EAGL Context


次のステップもまた、Apple が EGL API を Cocoa Framework に適正化してしまったよ。あらまあ。EAGL API は2つのobjective-C のクラスを提供する。すなわち、EAGLContext と EGLContext である。

EGL からはいろいろ変わってしまったが、手順は簡単。OpenGL のバージョンを指定して EAGLContext を初期化すればOK。EGLDisplay やら EGLContext などの処理はやらなくて良い。
@interface CustomView : UIView
{
    EAGLContext *_context;
}
 
@end
 
@implementation CustomView
...
 
- (id) initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {
        // Other initializations...
 
        // Create a EAGLContext using the OpenGL ES 2.x.
        _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
 
        // Make our new context, the current context.
        [EAGLContext setCurrentContext:_context];
    }
 
    return self;
}

...
@end


Rendering with EAGL Context


本当はここで Frame Buffer をつくる段階なのだが、ここでは省略する。つぎのパート(2ページ目)で説明するので。

レンダリングは簡単。
[_context presentRenderbuffer:GL_RENDERBUFFER];
でもって描画面の切替えが行われる。

GL_RENDERBUFFER は定数で、内部でだけ使われる。このメソッドは描画準備が完了した段階で呼ばれるべきメソッドである。

以上でおおよそ完了。OOP が好きなら UIView のサブクラスを作るなりすること。


Conclusion


いろいろ書いてきたけど覚えておいて欲しいのは
「メーカーの EGL の説明をちゃんと聞いてね」
ということ。ここまで見てきたように、メーカーによって EGL の実装はかなり異なります。


以上。



たしかに今まで iPhone のサンプルコードを見たり、OpenGL のコードと照らし合わせたりしてきましたが、やっと違いがわかりました。たいていのサイトだと「OpenGL はプラットフォームを移動しても変わらないので良い!」としか書いてませんからね。

0 件のコメント:

コメントを投稿