GL_AMD_pinned_memory を試してみた

以前から気になってはいた GL_AMD_pinned_memory 拡張を試してみました。自分の環境は、APUではない通常のRADEONボードをさした環境であるので、一応動くには動くだろうと思って試してみました。ただ動いたとしても本当に効果を発揮するのは、GPU,CPUともに同じメモリを使用するAPU環境だと思います。

使い方は簡単で、通常のバッファ作成のところ(glGenBuffers周辺コード)のところを変更するだけです。

GLenum target = GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD;
glGenBuffers( 1, &vbo );
glBindBuffer( target, vbo );

void* p = malloc( sizeof(vertBox) + 0x1000 );
void* pAligned = (void*)((uintptr_t)( (char*)p + 0xFFFu )  & ~0xFFFu );
memcpy( pAligned, vertBox, sizeof(vertBox) );
glBufferData( target, sizeof(vertBox), pAligned, GL_STATIC_DRAW );

g_pAlignedBuf = pAligned;

コードを見ておおよそわかると思うのですが、説明すると以下のような感じです。

  1. バッファを作成する
  2. バッファを GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD でバインドする
  3. メインメモリ上にデータ元となるバッファを用意する。このときにアラインメントを考慮する必要がある。
  4. アライメントされたバッファにデータを詰める。
  5. アライメントされたデータを元に glBufferData で転送する

次に、毎フレーム実行される部分で、先ほどのアライメントされたバッファの中身をいじってみます。

Vertex* pVertices = (Vertex*)g_pAlignedBuf;

pVertices[2].x = 0.5f + 0.25f*cosf( cnt*0.02f );
pVertices[2].y = 0.5f + 0.25f*cosf( cnt*0.01f );
pVertices[3].x = 0.5f + 0.25f*sinf( cnt*0.005f );
pVertices[3].y = -0.5f + 0.25f*sinf( cnt*0.005f );

glEnableClientState( GL_VERTEX_ARRAY );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glVertexPointer( 3, GL_FLOAT, 0, NULL );
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );

この状態で描画を行うとこんな感じになります。

test GL_AMD_pinned_memory

OpenGLを使い慣れている人は、この動作にびっくりするはずです。
通常だと、VBOを使用して頂点データを扱いますが、これを更新するには glMapBufferやglBufferDataといった関数を用いて、更新されたデータを1度転送する必要がありました。
 しかし、この拡張を使用すると、メインメモリのバッファを書き換えただけで描画のデータも反映されている!ということに。実際のところは同一のデータを使うため拡張なので、同期というのがメインではないのですが。

当然ながら、target変数に GL_ARRAY_BUFFER を設定してデータを作成してみるとこのようには動かず、単に四角形がスタティックに描画されるだけの状態となります。

動作環境

Windows7 SP1
RADEON 6850 (Catalyst 13.4)

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

コメント

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