5

Nexus 10 で OpenGL ES 2.0 を使用したライブ壁紙を開発しています。

ライブ壁紙は、2 つの小さな (128x128) 外部フレーム バッファーを使用して、それらの間でピンポン レンダリングを行い、画像をぼかします。

これはどのデバイスでも (古い Motorola Milestone でも) 完全に機能しますが、Nexus 10 には奇妙な問題があります。これは、デバイスが横向きの場合にのみ機能します。デバイスが他の位置 (90、180、または 270 度) に回転している場合、フレーム バッファーにはクリア カラーしかありません。赤に設定glClearColorしたので、これらのフレーム バッファはクリアされているが、何もレンダリングされていないことがはっきりとわかります。

Tegra 2、Tegra 3、Adreno 200、Adreno 320、2 つの PowerVR GPU でテストしたところ、問題なく動作しました。

これは奇妙なドライバーのバグのように見えますが、Mali ドライバーに特有のものである可能性もあります。ご意見をお聞かせください。

コードの抜粋。

初期フレームバッファ:

private void initBloomStuff() {
    mBloomTextureID = loadTexture("textures/empty128.png");
    mBloomVertTextureID = loadTexture("textures/empty128.png");

    mBloomFBHeight = 128;
    mBloomFBWidth = 128;

    float blurSize = 1.0f;

    // Texel offset for blur filter kernel
    m_fTexelOffset = 1.0f / mBloomFBWidth / blurSize;

    ByteBuffer tmpFB, tmpRB;
    IntBuffer handle, renderbuffers;
    int result;

    tmpFB = ByteBuffer.allocateDirect(4);
    tmpFB.order(ByteOrder.nativeOrder());
    handle = tmpFB.asIntBuffer();
    GLES20.glGenFramebuffers(1, handle);
    framebufferHandle = handle.get(0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBloomTextureID);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebufferHandle);
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, mBloomTextureID, 0);

    checkGlError("FB 1");
    tmpRB = ByteBuffer.allocateDirect(4);
    renderbuffers = tmpRB.asIntBuffer();
    GLES20.glGenRenderbuffers(1, renderbuffers);
    checkGlError("FB 1 - glGenRenderbuffers");
    depthbufferHandle = renderbuffers.get(0);
    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthbufferHandle);
    checkGlError("FB 1 - glBindRenderbuffer");
    GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, mBloomFBWidth, mBloomFBHeight);
    checkGlError("FB 1 - glRenderbufferStorage");
    GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthbufferHandle);
    checkGlError("FB 1 - glFramebufferRenderbuffer");

    result = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
    if (result != GLES20.GL_FRAMEBUFFER_COMPLETE) {
        Log.d(TAG, "Error creating framebufer 1: " + result);
    } else {
        Log.d(TAG, "Created framebufer 1: " + result);
    }

    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, 0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

    tmpFB = ByteBuffer.allocateDirect(4);
    tmpFB.order(ByteOrder.nativeOrder());
    handle = tmpFB.asIntBuffer();
    GLES20.glGenFramebuffers(1, handle);
    framebufferVertHandle = handle.get(0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBloomVertTextureID);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebufferVertHandle);
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, mBloomVertTextureID, 0);

    checkGlError("FB 2");
    tmpRB = ByteBuffer.allocateDirect(4);
    renderbuffers = tmpRB.asIntBuffer();
    GLES20.glGenRenderbuffers(1, renderbuffers);
    checkGlError("FB 2 - glGenRenderbuffers");
    depthbufferVertHandle = renderbuffers.get(0);
    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthbufferVertHandle);
    checkGlError("FB 2 - glBindRenderbuffer");
    GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, mBloomFBWidth, mBloomFBHeight);
    checkGlError("FB 2 - glRenderbufferStorage");
    GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthbufferVertHandle);
    checkGlError("FB 2 - glFramebufferRenderbuffer");

    result = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
    if (result != GLES20.GL_FRAMEBUFFER_COMPLETE) {
        Log.d(TAG, "Error creating framebufer 2: " + result);
    } else {
        Log.d(TAG, "Created framebufer 2: " + result);
    }

    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, 0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

    mTriangleVerticesVignette = ByteBuffer.allocateDirect(mQuadTriangles.length * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
    mTriangleVerticesVignette.put(mQuadTriangles).position(0);
}

FB にレンダリング:

    GLES20.glUseProgram(mProgram);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mStemTextureID);
    drawBird();
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mSphereTextureID);
    drawSphere();

    GLES20.glViewport(0, 0, mBloomFBWidth, mBloomFBHeight);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebufferHandle);
    // GLES20.glBindRenderbuffer(GLES20.GL_FRAMEBUFFER, depthbufferHandle);

    GLES20.glClearColor(1.0f, 0.5f, 0.5f, 1.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mStemTextureID);
    drawBird();
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mSphereTextureID);
    drawSphere();

    GLES20.glViewport(0, 0, screenWidth, screenHeight);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    // GLES20.glBindRenderbuffer(GLES20.GL_FRAMEBUFFER, 0); 

2 つの FB 間でピンポン レンダリングしてイメージをぼかす:

    GLES20.glUseProgram(mBloomProgram);
    GLES20.glUniform1i(mBloom_sTexture, 0);
    GLES20.glUniform1f(mBloom_bloomFactor, 0.8f);

    GLES20.glActiveTexture(GL10.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBloomTextureID);
    GLES20.glViewport(0, 0, mBloomFBWidth, mBloomFBHeight);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebufferVertHandle);
    GLES20.glUniform1f(mBloom_TexelOffsetX, m_fTexelOffset);
    GLES20.glUniform1f(mBloom_TexelOffsetY, 0.0f);
    GLES20.glActiveTexture(GL10.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBloomTextureID);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    drawBloom();
    GLES20.glViewport(0, 0, screenWidth, screenHeight);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

    GLES20.glActiveTexture(GL10.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBloomVertTextureID);
    GLES20.glViewport(0, 0, mBloomFBWidth, mBloomFBHeight);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebufferHandle);
    GLES20.glUniform1f(mBloom_TexelOffsetX, 0.0f);
    GLES20.glUniform1f(mBloom_TexelOffsetY, m_fTexelOffset);
    GLES20.glActiveTexture(GL10.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBloomVertTextureID);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    drawBloom();
    GLES20.glViewport(0, 0, screenWidth, screenHeight);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

    GLES20.glActiveTexture(GL10.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBloomTextureID);
    GLES20.glViewport(0, 0, mBloomFBWidth, mBloomFBHeight);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebufferVertHandle);
    GLES20.glUniform1f(mBloom_TexelOffsetX, m_fTexelOffset / 2);
    GLES20.glUniform1f(mBloom_TexelOffsetY, m_fTexelOffset / 2);
    GLES20.glActiveTexture(GL10.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBloomTextureID);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    drawBloom();
    GLES20.glViewport(0, 0, screenWidth, screenHeight);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); 

アプリケーションをテストしてバグを再現する

ここからテスト APK をダウンロードできます

ご覧のとおり、デフォルトの横向きでは、2 つのフレームバッファ間のピンポン レンダリングによって実装された鳥の周りに「ブルーム」効果が見られます。他のデバイスの向きでは機能せず、FB がクリア カラー (赤) で塗りつぶされます。

追加のリンク

また、この問題をMali Developer CenterGoogle Codeに投稿しました。

http://forums.arm.com/index.php?/topic/16894-nexus-10-render-to-external-rendertarget-works-only-in-landscape/

http://code.google.com/p/android/issues/detail?id=57391

4

1 に答える 1

1

Mali ドライバー サポート チームは、これがドライバーのバグであることを確認しており、次のドライバー バージョンで修正する予定です。glViewport一時的な回避策として、 afterを呼び出すことを提案していますglBindFramebuffer。この回避策は機能します-呼び出し順序を変更した後、正しいレンダリングを実現することができました。

固定ドライバーが利用可能になり次第、Nexus 10 用の固定 OpenGL ES ドライバーを含めるように ARM に連絡するよう Google に提案しました。これがより早く行われることを希望する人がいる場合は、Android バグ トラッカーで問題にスターを付けることができます: http://code.google.com/p/android/issues/detail?id=57391

この問題を提出した Mali Developer Center フォーラムへのリンク: http://forums.arm.com/index.php?/topic/16894-nexus-10-render-to-external-rendertarget-works-only-in -風景/

このドライバーのバグは ARM によって検証および確認されているため、この SO の質問に投票する代わりに、Android の問題 #57391にスターを付けてください。これにより、Google が問題に注意を払い、ファームウェア アップデートをリリースして、Nexus 10 を改善できることを願っています。これが、この質問に報奨金を割り当てた理由です。

編集。このバグは、Android 4.4 で最終的に修正されました。

于 2013-07-13T12:58:43.360 に答える