This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Nexus 10 - render to external rendertarget works only in landscape

Note: This was originally posted on 8th July 2013 at http://forums.arm.com

We're developing live wallpaper with OpenGL ES 2.0 on Nexus 10.

Live wallpaper uses 2 small (128x128) external framebuffers to make ping-pong rendering between them to blur image.

While this works perfectly fine on any device (even on aged Motorola Milestone) there is a strange issue with Nexus 10. This works only if device is in landscape orientation. If device is rotated in any other position (90, 180 or 270 degrees) framebuffers has only clear color. I've set `glClearColor` to red so it is clearly visible that these framebuffers are cleared but nothing is rendered into them.

I've tested it on Tegra 2, Tegra 3, Adreno 200, Adreno 320, 2 PowerVR GPUs and it works just fine.

This looks like some weird driver bug, but might also be some specifics of Mali driver. Please advice.

Code excerpts.

Init framebuffers:

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);
}


Render to 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);


Ping-pong rendering between 2 FBs to blur image:

  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);



You can download test APK here: https://dl.dropboxus...perAnimTest.apk
It is a live wallpaper app, install it and select 'Test' live wallpaper (has an icon with rose).

As you can see, default landscape orientation you will see some 'bloom' effect around bird which is implemented by ping-pong rendering between 2 framebuffers. In any other device orientation it doesn't work and fills FB with clear color (red).

I've also posted this question on stackoverflow: http://stackoverflow...ly-in-landscape and filed a bug on Google Code: http://code.google.com/p/android/issues/detail?id=57391
Parents
  • Note: This was originally posted on 12th July 2013 at http://forums.arm.com

    We have identified the issue and will have a fix in our next driver release; how soon this gets picked up by device manufacturers downstream is somewhat out of our control unfortunately.
    We have a workaround  from the application side for existing devices, which is to call glViewport after glBindFramebuffer.

    Hope that helps and thanks again for reporting.

    Iso
Reply
  • Note: This was originally posted on 12th July 2013 at http://forums.arm.com

    We have identified the issue and will have a fix in our next driver release; how soon this gets picked up by device manufacturers downstream is somewhat out of our control unfortunately.
    We have a workaround  from the application side for existing devices, which is to call glViewport after glBindFramebuffer.

    Hope that helps and thanks again for reporting.

    Iso
Children
No data