6

私はopengl ES2.0でAndroidアプリケーションを開発しています。このアプリケーションでは、GL surfaceViewでタッチイベントによって複数の線と円を描画していました。

opengl は GPU に依存しているため、現在 Google Nexus 7(ULP GeForce) で問題なく動作しています。

Samsung Galaxy Note 2(MALI 400MP) では、複数の線を描画しようとしていますが、前の線がクリアされ、現在の線が新しく描画されます。

Sony Xperia Neo V(Adreno 205) で新しい線を引こうとすると、下の画像のように表面がクラッシュします。ここに画像の説明を入力

すべてのデバイスで動作させることは可能ですか、それとも個々の GPU 用にコードを記述する必要がありますか?


ソースコード

MainActivity.java

//in OnCreate method of my activity, i set the glsurfaceview and renderer

final ActivityManager activityManager =
    ( ActivityManager ) getSystemService( Context.ACTIVITY_SERVICE );
final ConfigurationInfo configurationInfo =
    activityManager.getDeviceConfigurationInfo(  );
final boolean supportsEs2 = ( configurationInfo.reqGlEsVersion >= 0x20000
                  || Build.FINGERPRINT.startsWith( "generic" ) );

if( supportsEs2 ) {
    Log.i( "JO", "configurationInfo.reqGlEsVersion:"
           + configurationInfo.reqGlEsVersion + "supportsEs2:"
           + supportsEs2 );
// Request an OpenGL ES 2.0 compatible context.
    myGlsurfaceView.setEGLContextClientVersion( 2 );

    final DisplayMetrics displayMetrics = new DisplayMetrics(  );
    getWindowManager(  ).getDefaultDisplay(  ).getMetrics( displayMetrics );

// Set the renderer to our demo renderer, defined below.
    myRenderer = new MyRenderer( this, myGlsurfaceView );
    myGlsurfaceView.setRenderer( myRenderer, displayMetrics.density );
    myGlsurfaceView.setRenderMode( GLSurfaceView.RENDERMODE_CONTINUOUSLY );

    MyGLSurfaceView.java
//in this im getting the coordinates of my touch on the glSurfaceView to draw the line and //passing those points to the renderer class
        public MyGLsurfaceview( Context context ) {
        super( context );
        Log.i( "JO", "MyGLsurfaceview1" );

    }

    public MyGLsurfaceview(
    Context context,
    AttributeSet attrs )
    {
        super( context, attrs );
        con = context;
        mActivity = new MainActivity(  );
        mActivity.myGlsurfaceView = this;
        Log.i( "JO", "MyGLsurfaceview2" );
    }

    public void setRenderer(
    MyRenderer renderer,
    float density )
    {
        Log.i( "JO", "setRenderer" );
        myRenderer = renderer;
        myDensity = density;
        mGestureDetector = new GestureDetector( con, mGestureListener );
        super.setRenderer( renderer );
        setRenderMode( GLSurfaceView.RENDERMODE_CONTINUOUSLY );

    }
    @Override public boolean onTouchEvent( MotionEvent ev ) {

        boolean retVal = mGestureDetector.onTouchEvent( ev );

        if( myline ) {

            switch ( ev.getAction(  ) ) {

            case MotionEvent.ACTION_DOWN:

                isLUp = false;

                if( count == 1 ) {
                    dx = ev.getX(  );
                    dy = ev.getY(  );
                    dx = ( dx / ( getWidth(  ) / 2 ) ) - 1;
                    dy = 1 - ( dy / ( getHeight(  ) / 2 ) );

                    firstX = dx;
                    firstY = dy;
                } else if( count == 2 ) {

                    ux = ev.getX(  );
                    uy = ev.getY(  );
                    ux = ( ux / ( getWidth(  ) / 2 ) ) - 1;
                    uy = 1 - ( uy / ( getHeight(  ) / 2 ) );

                    secondX = ux;
                    secondY = uy;

                    myRenderer.dx = firstX;
                    myRenderer.dy = firstY;
                    myRenderer.ux = secondX;
                    myRenderer.uy = secondY;

                    midX = ( firstX + secondX ) / 2;
                    midY = ( firstY + secondY ) / 2;
                    Log.e( "JO",
                           "Line:firstX" + firstX +
                           "firstY" + firstY );
                    lp = new LinePoints( firstX, firstY,
                                 secondX, secondY,
                                 midX, midY );
                    lineArray.add( lp );

                    myRenderer.isNewClick = false;
                    myRenderer.isEnteredAngle = false;
                    myRenderer.myline = true;
                    myRenderer.mycircle = false;
                    myRenderer.mydashedline = false;
                    myRenderer.eraseCircle = false;
                    myRenderer.eraseLine = false;
                    myRenderer.eraseSelCir = false;
                    myRenderer.angle = angle;
                    myRenderer.length = length;
                    requestRender(  );
                    count = 0;

                }
                count++;

                break;
            case MotionEvent.ACTION_MOVE:

                isLUp = true;

                break;

            case MotionEvent.ACTION_UP:

                if( isLUp ) {

                    ux = ev.getX(  );
                    uy = ev.getY(  );
                    ux = ( ux / ( getWidth(  ) / 2 ) ) - 1;
                    uy = 1 - ( uy / ( getHeight(  ) / 2 ) );
                    Log.i( "JO", "line2:" + ux + "," + uy );

                    secondX = ux;
                    secondY = uy;
                    myRenderer.dx = firstX;
                    myRenderer.dy = firstY;
                    myRenderer.ux = secondX;
                    myRenderer.uy = secondY;

                    midX = ( firstX + secondX ) / 2;
                    midY = ( firstY + secondY ) / 2;
                    Log.e( "JO",
                           "Line:firstX" + firstX +
                           "firstY" + firstY );
                    lp = new LinePoints( firstX, firstY,
                                 secondX, secondY,
                                 midX, midY );
                    lineArray.add( lp );

                    myRenderer.isNewClick = false;
                    myRenderer.isEnteredAngle = false;
                    myRenderer.myline = true;
                    myRenderer.mycircle = false;
                    myRenderer.mydashedline = false;
                    myRenderer.mysnaptoedge = false;
                    myRenderer.mysnaptoMiddle = false;
                    myRenderer.eraseCircle = false;
                    myRenderer.eraseLine = false;
                    myRenderer.eraseSelCir = false;
                    count = 1;
                    requestRender(  );
                }

                break;

            }
        }
    }
}

MyRenderer.java

//renderer class to render the line to the glsurfaceview
Lines line;
public MyRenderer(
    MainActivity mainActivity,
    MyGLsurfaceview myGlsurfaceView )
{
    Log.i( "JO", "MyRenderer" );
    this.main = mainActivity;
    myGlsurface = myGlsurfaceView;

}

public void onDrawFrame(
    GL10 gl )
{
    line.draw( dx, dy, ux, uy );
}

@Override public void onSurfaceCreated(
    GL10 gl,
    EGLConfig config )
{
    Log.i( "JO", "onSurfaceCreated" );
// Set the background frame color
    GLES20.glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
// Create the GLText
    glText = new GLText( main.getAssets(  ) );

// Load the font from file (set size + padding), creates the texture
// NOTE: after a successful call to this the font is ready for
// rendering!
    glText.load( "Roboto-Regular.ttf", 14, 2, 2 );  // Create Font (Height: 14
// Pixels / X+Y Padding
// 2 Pixels)
// enable texture + alpha blending
    GLES20.glEnable( GLES20.GL_BLEND );
    GLES20.glBlendFunc( GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA );
}

@Override public void onSurfaceChanged(
    GL10 gl,
    int width,
    int height )
{
// Adjust the viewport based on geometry changes,
// such as screen rotation
    GLES20.glViewport( 0, 0, width, height );

    ratio = ( float ) width / height;

    width_surface = width;
    height_surface = height;

/*
* // this projection matrix is applied to object coordinates // in the
* onDrawFrame() method Matrix.frustumM(mProjMatrix, 0, -ratio, ratio,
* -1, 1, 3, 7);
*/
// Take into account device orientation
    if( width > height ) {
        Matrix.frustumM( mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 10 );
    } else {
        Matrix.frustumM( mProjMatrix, 0, -1, 1, -1 / ratio, 1 / ratio,
                 1, 10 );
    }

// Save width and height
    this.width = width; // Save Current Width
    this.height = height;   // Save Current Height

    int useForOrtho = Math.min( width, height );

// TODO: Is this wrong?
    Matrix.orthoM( mVMatrix, 0, -useForOrtho / 2, useForOrtho / 2,
               -useForOrtho / 2, useForOrtho / 2, 0.1f, 100f );
}

Line.java

//Line class to draw line

public class Lines
{

    final String vertexShaderCode = "attribute vec4 vPosition;"
        + "void main() {" + " gl_Position = vPosition;" + "}";

    final String fragmentShaderCode = "precision mediump float;"
        + "uniform vec4 vColor;" + "void main() {"
        + " gl_FragColor = vColor;" + "}";

    final FloatBuffer vertexBuffer;
    final int mProgram;
    int mPositionHandle;
    int mColorHandle;

// number of coordinates per vertex in this array
    final int COORDS_PER_VERTEX = 3;
    float lineCoords[] = new float[6];
    final int vertexCount = lineCoords.length / COORDS_PER_VERTEX;
    final int vertexStride = COORDS_PER_VERTEX * 4; // bytes per vertex
// Set color with red, green, blue and alpha (opacity) values
    float lcolor[] = { 1.0f, 1.0f, 1.0f, 1.0f };

    public Lines(
         )
    {

// initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
                                  lineCoords.
                                  length * 4 );
// use the device hardware's native byte order
        bb.order( ByteOrder.nativeOrder(  ) );

// create a floating point buffer from the ByteBuffer
        vertexBuffer = bb.asFloatBuffer(  );

// prepare shaders and OpenGL program
        int vertexShader =
            MyRenderer.loadShader( GLES20.GL_VERTEX_SHADER,
                           vertexShaderCode );
        int fragmentShader =
            MyRenderer.loadShader( GLES20.GL_FRAGMENT_SHADER,
                           fragmentShaderCode );

        mProgram = GLES20.glCreateProgram(  );  // create empty OpenGL Program
        GLES20.glAttachShader( mProgram, vertexShader );    // add the vertex shader
// to program
        GLES20.glAttachShader( mProgram, fragmentShader );  // add the fragment
// shader to program
        GLES20.glLinkProgram( mProgram );   // create OpenGL program executables
    }

    public void draw(
    float dX,
    float dY,
    float uX,
    float uY )
    {

        lineCoords[0] = dX;
        lineCoords[1] = dY;
        lineCoords[2] = 0.0f;
        lineCoords[3] = uX;
        lineCoords[4] = uY;
        lineCoords[5] = 0.0f;
        Log.i( "JO",
               "lineCoords:" + lineCoords[0] + "," + lineCoords[1] +
               "," + lineCoords[3] + "," + lineCoords[4] );

        vertexBuffer.put( lineCoords );
        vertexBuffer.position( 0 );
// Add program to OpenGL environment
        GLES20.glUseProgram( mProgram );

// get handle to vertex shader's vPosition member
        mPositionHandle =
            GLES20.glGetAttribLocation( mProgram, "vPosition" );

// Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray( mPositionHandle );

// Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer( mPositionHandle,
                          COORDS_PER_VERTEX,
                          GLES20.GL_FLOAT, false,
                          vertexStride, vertexBuffer );

// get handle to fragment shader's vColor member
        mColorHandle =
            GLES20.glGetUniformLocation( mProgram, "vColor" );

// Set color for drawing the triangle
        GLES20.glUniform4fv( mColorHandle, 1, lcolor, 0 );
        GLES20.glLineWidth( 3 );
// Draw the triangle
        GLES20.glDrawArrays( GLES20.GL_LINES, 0, vertexCount );

// Disable vertex array
        GLES20.glDisableVertexAttribArray( mPositionHandle );
    }

}
4

5 に答える 5

4

では、また行きます: ^1

OpenGL はシーン グラフではありません。OpenGL はシーンを保持せず、オブジェクトを認識したり、ジオメトリを追跡したりします。OpenGL は描画API です。キャンバスに (ウィンドウまたは PBuffer の形式で) 与え、点、線、または三角形を描画するように命令すると、OpenGL はまさにそれを行います。プリミティブ (= 点、線、三角形) が描画されると、OpenGL はそれについてまったく記憶しません。何かが変わると、全体を再描画する必要があります。

シーンを再描画する適切な手順は次のとおりです。

  1. 次の手順がウィンドウ全体で動作するように、ステンシル テストを無効にします。

  2. を使用してフレームバッファをクリアしますglClear(bits)ビットは、キャンバスのどの部分をクリアするかを指定するビットマスクです。新しいフレームをレンダリングするときは、すべてをクリアしたいのでbits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;

  3. ビューポートを設定し、適切な射影行列を構築します

  4. シーン内の各オブジェクトに対して、適切なモデルビュー マトリックスをロードし、ユニフォームを設定し、頂点配列を選択して、描画呼び出しを行います。

  5. パイプラインをフラッシュしてレンダリングを終了します。シングル バッファ ウィンドウをglFinish()使用している場合、ダブル バッファ ウィンドウ コールを使用している場合SwapBuffers。より高いレベルのフレームワークの場合、これはフレームワークによって実行される場合があります。

重要ダブル バッファー ウィンドウで描画が終了したら、描画操作を送信し続けてはなりません。バッファー スワップを実行すると、描画先のバック バッファーの内容が未定義になるためです。したがって、フレームバッファをクリアすることから始めて、新たに描画を開始する必要があります (ステップ 1 および 2)。

あなたのコードが見逃しているのは、まさにこの 2 つのステップです。また、おそらく入力イベント ハンドラー自体で、入力イベントに直接反応して OpenGL 描画呼び出しを実行している印象があります。これをしないでください!. 代わりに、入力イベントを使用して描画するプリミティブ (この場合は行) のリストに追加し、フレームワークに描画関数を呼び出させる再描画イベントを送信します。描画関数では、そのリストを繰り返し処理して目的の線を描画します。

シーン全体を再描画することは、OpenGL では標準的です!


[1] (おやおや、これを 3 問ごとに書かなければならないことにうんざりしている…)

于 2013-06-21T14:32:35.837 に答える
1

OpenGL は単なる標準です。API の実際の実装は、グラフィックス カードの製造元に任されています。そうです、OpenGL の開発は GPU に依存する場合があります。ただし、すべての実装で同じ結果が得られるはずです (舞台裏で起こることは実際には異なる場合があります)。コードが異なる GPU で異なる結果を返す場合、OpenGL 実装にバージョンの違いがある可能性があります。

これらの関数を使用して、サポートされている OpenGL バージョンを取得できます。

glGetIntegerv​(GL_MAJOR_VERSION​, *); //version 3.0+
glGetIntegerv​(GL_MINOR_VERSION​, *); //version 3.0+
glGetString​(GL_VERSION​); //all versions
于 2013-06-21T08:10:03.727 に答える
0
  1. 人々が実際に助けることができるように、実際の例を1つ提供してみませんか?

  2. あなたのコードから: 行を作成する場所がわかりません。何かのようなもの:

    @Override public void onSurfaceCreated(GL10 gl, EGLConfig config){
        ...
        mLine = new Lines();
        ...
    }
    
  3. 他の人がすでに述べたように、onDrawFrame常にバッファをクリアします。

    public void onDrawFrame(GL10 gl )
    {
        // Erase CL_COLOR_BUFFER
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    
  4. カメラを設定する:

    // Set the camera position (View matrix)
    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    //
    // Calculate the projection and view transformation
    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mViewMatrix, 0);
    
  5. 描く:

    line.draw( dx, dy, ux, uy );
    
于 2013-06-30T11:08:17.607 に答える
0

同様の質問に対する私の回答からクロスポストされましたなぜ私のopengl出力がさまざまなデバイスで異なるのですか? :

コーディング中に GPU を考慮する必要がありますか? まさか、OpenGL API はアプリケーションとハードウェアの間のレイヤーです。

これは、すべての GPU が即時レンダラーであるため、デスクトップ グラフィックスではほぼ正しいですが、モバイル グラフィックスでは当てはまりません。

Mali GPU は、タイルベースの即時モード レンダリングを使用します。このタイプのレンダリングでは、フレームバッファは 16 x 16 ピクセルのサイズのタイルに分割されます。Polygon List Builder (PLB) は、アプリケーションからの入力データをポリゴン リストに編成します。タイルごとにポリゴン リストがあります。プリミティブがタイルの一部を覆う場合、ポリゴン リスト コマンドと呼ばれるエントリがタイルのポリゴン リストに追加されます。ピクセル プロセッサは、1 つのタイルのポリゴン リストを取得し、そのタイル内のすべてのピクセルの値を計算してから、次のタイルで作業を開始します。このタイルベースのアプローチは高速なオンチップ タイル バッファーを使用するため、GPU は各タイルの最後にあるメイン メモリ内のフレーム バッファーにタイル バッファーの内容のみを書き込みます。非タイル ベースの即時モード レンダラーは、通常、より多くのフレーム バッファー アクセスを必要とします。

もう 1 つの違いは、レンダリングされたバッファーの処理です。即時レンダラーはバッファのコンテンツを「保存」し、以前に存在したものの上にレンダリングされたシーンの違いのみを効果的に描画できるようにします。これはマリで利用可能ですが、誤って使用すると望ましくない影響を引き起こす可能性があるため、デフォルトでは有効になっていません。

「EGL Preserve」の使用方法に関する Mali GLES2 SDK の例があり、ここの GLES2 SDK で正しく利用できます

Geforce ULP ベースの nexus 7 が意図したとおりに機能する理由は、即時ベースのレンダラーとしてデフォルトでバッファを保持するのに対し、Mali は保持しないためです。

Khronos EGL 仕様から:

EGL_SWAP_BEHAVIOR

eglSwapBuffers でサーフェスを送信することのカラー バッファーへの影響を指定します。EGL_BUFFER_PRESERVED の値は、カラー バッファの内容が影響を受けないことを示しますが、EGL_BUFFER_DESTROYED は、操作によってカラー バッファの内容が破棄または変更される可能性があることを示します。

EGL_SWAP_BEHAVIOR の初期値は実装によって選択されます。

Mali プラットフォームでの EGL_SWAP_BEHAVIOUR のデフォルト値は EGL_BUFFER_DESTROYED です。これは、新しいフレームをレンダリングする前にメモリから前のバッファをフェッチし、最後にそれを保存する必要があることに関連するパフォーマンス ヒットと、帯域幅の消費によるものです (これは、モバイル デバイスのバッテリ寿命にも非常に悪影響を及ぼします)。Tegra SoC のデフォルトの動作について確実にコメントすることはできませんが、デフォルトが EGL_BUFFER_PRESERVED であることは明らかです。

Khronos GLES 仕様に関する Mali の立場を明確にするために、Mali は完全に準拠しています。

于 2013-07-16T14:11:27.270 に答える