1

私は単純なアンドロイドゲームに取り組んでいます。マルチスレッドでエンジンを最適化したいと思うようになりました。私はOpenGL ES、Android 2.2で作業しています

現在、UpdateGame() と RenderScene() はシングル スレッドで実行され、onDrawFrame(GL10 gl) で実行されます。

Position、Rotation、Scale、および Color メンバーを持つ RenderObject クラスがあります。ゲームを開始するとすべての RenderObjects が作成され、RenderObject 配列に格納されます。

UpdateGame() 関数では、RenderObject 配列の RenderObjects を調べて、新しい位置、回転、スケール、および色を更新します。

RenderScene() 関数では、RenderObject 配列の RenderObjects を調べ、新しい位置、回転、スケール、および色でレンダリングします。

これはシングルスレッドで問題なく動作します。

そこで、UpdateGame() のスレッドを作成してみました。

だから私の考えは次のとおりです。

更新スレッド:................................レンダリング スレッド:

フレーム 0 を更新

Update Frame 1................Render Frame 0....Update と Render は並行して動作します。

フレーム 2 の更新................................フレーム 1 のレンダリング

フレーム 3 を更新する.................フレーム 2 をレンダリングする

しかし、最初に RenderObject クラスを変更して、RenderPosition、RenderRotation、RenderScale、および RenderColor メンバーを持つようにしました。

これらのメンバーは、前のフレームをレンダリングする直前にコピーされます。並列更新スレッドが新しい位置、回転、スケール、色を変更できるようにします。

Runnable pRunnable;
Thread pThread;
public int renderframe = 0;
piblic int updateframe = 0;

public void onSurfaceCreated(GL10 gl, EGLConfig config) 
{
    // I create a new thread in this function        
    pRunnable = new Runnable(){
         public void run(){
             while(true)
             {
                 while( renderframe < updateframe )
                 {
                     // WAITING for render to finish so that data does not get corrupterd
                 }
                 // 
                 // I update RenderObject Position, Rotation, Scale, Color members here
                 UpdateGame();
                 updateframe++;
             }  
         }
    };

    pThread = new Thread(pRunnable);
    pThread.start();
}

public void onDrawFrame(GL10 gl) 
{
    while( renderframe == updateframe )
    {
         // Wait for update to finish
    }

    for(int a=0;a<MAX_RENDER_OBJECTS;a++)
    {
        RenderObject ro = aRenderObjects[a];
        // I do this in a function
        ro.RenderPosition[0] = ro.Position[0];
        ro.RenderPosition[1] = ro.Position[1];
        ro.RenderPosition[2] = ro.Position[2];
        ro.RenderPosition[3] = ro.Position[3];
        // I do the same for Rotation, Scale, Color

    }

    renderframe++;

    // When rendering scene I use RenderPosition, RenderRotation members when calling OpenGL API
    RenderScene(); 

}

しかし、ゲームを実行すると。グラフィックが正しくありません。データが同期されていないように見えます。

Update スレッドと Render スレッドの間で RenderObject データを適切に同期する方法に関する提案。

ありがとうございました。

4

1 に答える 1

0

このスタイルは一般的に非効率的 (2 つのスレッドが同時に動作するのをブロックするスピン待機ループ) であり、危険 (Android がこれをどのように実装しているかはわかりませんが、Java メモリ モデルは、あるスレッドからのデータが別のスレッドに見えることを保証しません) のようです。同期ブロックを経由せずに)。

私の提案は次のとおりです。メイン スレッドはレンダリング スレッドです (GL コンテキストはスレッド ローカルであるため、別のスレッドから使​​用することはできません (ただし、別のスレッドで別のコンテキストを作成してデータ共有を実行することはできます))。更新スレッド。その後、メイン スレッドはループに入り、反復ごとにミューテックスを待機します。更新スレッドは、ゲーム ロジックを更新し、描画する必要があるすべてのもの (描画コマンドのリストなど) を表す新しいオブジェクトを作成します。次に、このオブジェクトがキューに入れられ、メイン スレッドが (notify() で) 起動されます。次に、メイン スレッドが描画データを取得して描画します。

更新ループがレンダリング ループよりもはるかに高速な場合に備えて、おそらく古いデータ セットを破棄したいと思うでしょうが、この一般的な考え方から始める必要があります。

于 2012-07-28T13:28:26.237 に答える