Androidバグ-google map切り替え黒画面問題


現象の説明:
Google mapを使用する場合、地図インタフェースからナビゲーションインタフェースに切り替えると、切替中に黒い画面が表示される確率が極めて高く、logを見ると、現在発生しているエラーコードもhwuiの0 x 506であることがわかります
分析:
Launcherフラワースクリーンの問題も0 x 506が現れたが、この0 x 506の問題はすでに解決されており、今回のgoogle mapのエラーコードの問題はフラワースクリーンの問題と同じ問題ではないはずだ.次に、hwuiのLayerRenderにロゴを印刷することで、fboの作成中にエラーが発生した場合、createLayerが発生した場合にエラーが発生したことがわかります.
Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
    Caches& caches = Caches::getInstance();
    GLuint fbo = caches.fboCache.get();
    if (!fbo) {
        ALOGW("Could not obtain an FBO");
        return NULL;
    }

    caches.activeTexture(0);
    Layer* layer = caches.layerCache.get(width, height);
    if (!layer) {
        ALOGW("Could not obtain a layer");
        return NULL;
    }
    ……
    GLuint previousFbo;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);

    glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
    layer->bindTexture();
	……
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
            layer->getTexture(), 0);

    glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
    return layer;
}

印刷により、現在fboにバインドされているテクスチャは無効であり、すなわち空のテクスチャであり、idのみであり、他にはないことが分かった.次に、現在のopengl traceを印刷すると、fboが作成されるとglBindTextureの操作が呼び出されず、すなわち現在のテクスチャがバインドされて使用されていないことがわかります.コードによりバインドされていないことが判明したのは,Cachesにおいてテクスチャバインドが最適化されているためである,つまり前回glBindTextureが呼び出され,テクスチャのidが一致していれば,次回glBindTextureを再呼び出す必要がなく,openglを頻繁に呼び出すインタフェースを防止し,不要なオーバーヘッドを低減できる.ただしこれでは、現在のテクスチャidが削除されていない限り、テクスチャidが無効になることはあり得ませんが、Cachesメンテナンスのidが削除されていないため、次回入るときにちょうどこのid番号と同じテクスチャが生成されるため、glBindTextureが呼び出されず、前回のテクスチャをそのまま使用することになりますが、前回は無効になります.
同時に印刷によって異常なテクスチャtargetが発見されたのはおかしい、つまりGL_TEXTURE_EXTERNAL_OESのタイプは、コードによって発見され、作成されたlayerオブジェクトがcreateTextureLayerである場合にのみ、拡張テクスチャが使用されます.次にTextureViewを見ると、TextureViewのテクスチャはGLConsumerに作成されていますが、テクスチャidの作成などはhwuiにあり、TextureViewのテクスチャが解放されると(destroySurface):
 private void destroySurface() {
        if (mLayer != null) {
            mSurface.detachFromGLContext();
            // SurfaceTexture owns the texture name and detachFromGLContext
            // should have deleted it
            mLayer.clearStorage();

            boolean shouldRelease = true;
            if (mListener != null) {
                shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface);
            }

            synchronized (mNativeWindowLock) {
                nDestroyNativeWindow();
            }

            mLayer.destroy();
            if (shouldRelease) mSurface.release();
            mSurface = null;
            mLayer = null;

            mHadSurface = true;
        }
    }
まずGLConsumerのテクスチャ内容を削除し、glDeleteTexturesを呼び出してテクスチャidを削除します.次にclearStorageを呼び出してhwuiのlayerのclearTextureを呼び出します.
void Layer::clearTexture() {
    texture.id = 0;
}
このときこちらはテクスチャのidを0にするだけで、Cachesメンテナンスのidも0にしていないので、次回テクスチャid申請を行うと、前回削除したidに申請され、Caches::bindTextureを呼び出すとバインドされていますが、前のテクスチャがバインドされていないため、fboを使用する際に異常が発生します.
シナリオの変更:
layerのclearTextureを呼び出すと、Cachesが維持しているテクスチャidも一緒にクリアされます.
void Layer::clearTexture() {
    if (texture.id) {
        texture.clearTexture();
        texture.id = 0;
    }
}

void Caches::clearTexture(GLuint texture) {
    for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
        if (mBoundTextures[i] == texture) {
            mBoundTextures[i] = 0;
        }
    }
}