stiamo sviluppando live wallpaper con OpenGL ES 2.0 sul Nexus 10.Nexus 10 - rendere a renderTarget esterno funziona solo nel paesaggio
carta da parati Live utilizza 2 piccoli (128x128) framebuffer esterni per fare il rendering ping-pong tra di loro per sfocare l'immagine.
Mentre questo funziona perfettamente su qualsiasi dispositivo (anche su Motorola Milestone invecchiato) c'è un problema strano con Nexus 10. Funziona solo se il dispositivo è in orientamento orizzontale. Se il dispositivo viene ruotato in qualsiasi altra posizione (90, 180 o 270 gradi) i frame buffer hanno solo colori chiari. Ho impostato glClearColor
in rosso, quindi è chiaramente visibile che questi framebuffer sono cancellati ma non viene eseguito il rendering di alcun elemento.
L'ho provato su Tegra 2, Tegra 3, Adreno 200, Adreno 320, 2 GPU PowerVR e funziona perfettamente.
Questo sembra un qualche strano bug del driver, ma potrebbe anche essere qualche dettaglio del driver Mali. Per favore consiglio
Estratti di codice.
Init framebuffer:
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);
}
rendere a 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);
il rendering da ping-pong tra 2 FB per sfocare immagine:
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);
applicazione prova a riprodurre bug
È possibile scaricare l'APK di test qui: https://dl.dropboxusercontent.com/u/7197208/LiveWallpaperAnimTest.apk È un'applicazione di sfondo animato, installarlo e selezionare "Test" live wallpaper (ha un'icona con rose).
Come potete vedere, nell'orientamento orizzontale predefinito vedrete un effetto "bloom" attorno all'uccello che viene implementato dal rendering ping-pong tra 2 framebuffer. In qualsiasi altro orientamento del dispositivo non funziona e riempie FB con colore chiaro (rosso).
Ulteriori link
ho anche postato questo problema a Mali Developer Center e Google Code:
http://code.google.com/p/android/issues/detail?id=57391