2011-08-29 11 views
14

TL、まったく描画を行っていない場合でも、DRAndroidのEGL/OpenGL ESのフレームレート吃音

は、Androidデバイス上でのOpenGL ESのレンダリングスレッドで60Hzの更新率を維持することは不可能と思われます。不思議なスパイクは頻繁に盛り上がります(コードの下に表示されています)。カスタムレンダリングスレッドを使用したさらに複雑な例のタイミングでは、eglSwapBuffers()が頻繁に17ms-32msを超えて発生する原因となることが一貫して示されています。助けて?

詳細

我々のプロジェクトのレンダリングの要件が円滑他の画面の片側から速度の固定、高い速度で水平スクロール画面整列要素であるので、これは特に破滅的です。つまり、プラットフォームゲームです。 60Hzから頻繁に低下すると、時間ベースの動きの有無にかかわらず、目立つポッピングとぶら下がりが発生します。 30Hzでのレンダリングは、スクロール速度の高速化のために選択肢にはなりません。スクロール速度は設計の非交渉可能な部分です。

私たちのプロジェクトは、互換性を最大限に高めるためにJavaベースであり、OpenGL ES 2.0を使用しています。 API 7-8デバイスでのOpenGL ES 2.0レンダリング用のNDKと、API 7デバイスでのETC1サポートのみに絞り込みます。以下に示すテストコードとその両方で、ログ印刷と自動スレッド以外の割り当て/ GCイベントは制御できませんでした。

在庫のAndroidクラスを使用し、NDKを使用しない1つのファイルで問題を再現しました。下記のコードは、Eclipseで作成された新しいAndroidプロジェクトに貼り付けることができ、APIレベル8以上を選択している限り、すぐに使えるはずです。

試験のGPUとOSのバージョンの範囲でさまざまなデバイス上で再生された:

  • ギャラクシータブ10.1(アンドロイド3.1)
  • ネクサスS(アンドロイド2.3.4)
  • ギャラクシーS II(アンドロイド2.3.3)
  • XPERIAは(アンドロイド2.3.2)を再生
  • ドロイド信じられない(アンドロイド2.2)
  • ギャラクシーS(アンドロイド2.1アップデート1)(DR

    Spike: 0.017554 
    Spike: 0.017767 
    Spike: 0.018017 
    Spike: 0.016855 
    Spike: 0.016759 
    Spike: 0.016669 
    Spike: 0.024925 
    Spike: 0.017083999 
    Spike: 0.032984 
    Spike: 0.026052998 
    Spike: 0.017372 
    

    私はしばらくの間、これを追いかけてきたし、約レンガを直撃している:レベル7までのAPIの要件)

実行時間の1秒の下から集められたサンプル出力を()opping壁。修正が利用できない場合は、少なくともこれがなぜ起こるかについての説明と、同様の要件を持つプロジェクトでこれがどのように克服されたかについてのアドバイスを大いにいただければ幸いです。

サンプルコード

package com.test.spikeglsurfview; 

import javax.microedition.khronos.egl.EGLConfig; 
import javax.microedition.khronos.opengles.GL10; 

import android.app.Activity; 
import android.opengl.GLSurfaceView; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.Window; 
import android.view.WindowManager; 
import android.widget.LinearLayout; 

/** 
* A simple Activity that demonstrates frequent frame rate dips from 60Hz, 
* even when doing no rendering at all. 
* 
* This class targets API level 8 and is meant to be drop-in compatible with a 
* fresh auto-generated Android project in Eclipse. 
* 
* This example uses stock Android classes whenever possible. 
* 
* @author Bill Roeske 
*/ 
public class SpikeActivity extends Activity 
{ 
    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 

     // Make the activity fill the screen. 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
           WindowManager.LayoutParams.FLAG_FULLSCREEN); 

     // Get a reference to the default layout. 
     final LayoutInflater factory = getLayoutInflater(); 
     final LinearLayout layout = (LinearLayout)factory.inflate(R.layout.main, null); 

     // Clear the layout to remove the default "Hello World" TextView. 
     layout.removeAllViews(); 

     // Create a GLSurfaceView and add it to the layout. 
     GLSurfaceView glView = new GLSurfaceView(getApplicationContext()); 
     layout.addView(glView); 

     // Configure the GLSurfaceView for OpenGL ES 2.0 rendering with the test renderer. 
     glView.setEGLContextClientVersion(2); 
     glView.setRenderer(new SpikeRenderer()); 

     // Apply the modified layout to this activity's UI. 
     setContentView(layout); 
    } 
} 

class SpikeRenderer implements GLSurfaceView.Renderer 
{ 
    @Override 
    public void onDrawFrame(GL10 gl) 
    { 
     // Update base time values. 
     final long timeCurrentNS = System.nanoTime(); 
     final long timeDeltaNS = timeCurrentNS - timePreviousNS; 
     timePreviousNS = timeCurrentNS; 

     // Determine time since last frame in seconds. 
     final float timeDeltaS = timeDeltaNS * 1.0e-9f; 

     // Print a notice if rendering falls behind 60Hz. 
     if(timeDeltaS > (1.0f/60.0f)) 
     { 
      Log.d("SpikeTest", "Spike: " + timeDeltaS); 
     } 

     /*// Clear the screen. 
     gl.glClear(GLES20.GL_COLOR_BUFFER_BIT);*/ 
    } 

    @Override 
    public void onSurfaceChanged(GL10 gl, int width, int height) 
    { 
    } 

    @Override 
    public void onSurfaceCreated(GL10 gl, EGLConfig config) 
    { 
     // Set clear color to purple. 
     gl.glClearColor(0.5f, 0.0f, 0.5f, 1.0f); 
    } 

    private long timePreviousNS = System.nanoTime(); 
} 
+0

時計logcat出力あなたはJavaでそれを構築している場合、それは事実の寿命です。 Androidの新しいバージョンでは同時のGCがありますが、ときどき完全なGCと付随する一時停止を避けることは困難です。あなたは40fpsに満足し、同時GCを目指すべきです。 –

答えて

0

あなたはフレームレートを自分で結合されていません。だからCPUに縛られている。

これは、CPUが何もしていないときは速く、それ以外のときは遅くなることを意味します。

あなたの携帯電話では他のものが実行されているため、ゲームからCPU時間がかかることがあります。ガベージコレクタは、これまでと同じようにあなたのゲームを凍結させませんでしたが、別のスレッドで実行されます。 Javaの欠点だけではありません。

私の提案:一定のビットレートが必要な場合は、フレームレートを低い値にバインドしてください。 ヒント:スリープは必要な待機時間を超える可能性があるため、Thread.sleep()とビジー待機(whileループ)の組み合わせを使用してください。

3

これが答えであるかどうかわかりませんが、描画するものがない場合でも、eglSwapBuffers()の呼び出しは少なくとも16ミリ秒間ブロックすることに注意してください。

ゲームロジックを別のスレッドで実行すると、時間がかかります。

オープンソースプラットフォームゲームRelica Islandのブログ記事をご覧ください。ゲームロジックは重いですが、著者のパイプライン/ダブルバッファソリューションのためにフレームレートはスムーズです。 GCメッセージの

http://replicaisland.blogspot.com/2009/10/rendering-with-two-threads.html

関連する問題