I am trying to use a single thread to render three separate TextureView's off the UI thread using canvas lock/unlock. The problem observed is the consistent flickering of each of the Texture Views being drawn, with the flicker consisting of a DIFFERENT TextureView's frame. So for example, I draw frames A,B and C in that order. Frame C will appear fine, however frames A and B will flicker with occasional instances of Frame C, and frame A will occasionally flicker with instances of Frame B.
I have read through the documentation describing Android Core Graphics, and have a fairly good understanding of how android's frame buffering system works. In a nutshell, my suspicion is that I am performing lockCanvas/unlockCanvasAndPost call's too quickly in succession, and that the framebuffer is unable to complete my request and simply draws the previous (incorrect) frame instead.
I've tried several things to resolve this issue. Attempting to use Choreographer to wait for VSYNC before continuing to call canvas helped, but as expected lowered my frame rate however the problem was still there. I've also tried an alternative render loop sans sleep command, with no difference in the observed phenomenon.
Essentially I am out of ideas on how to tackle this problem, and was hoping to get some outside input on it. Thanks in advance, code snippet is below:
Main render loop:
while (running) {
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
float delta = updateLength / ((float)OPTIMAL_TIME.get());
lastFpsTime += updateLength;
fps++;
if (lastFpsTime >= 1000000000)
{
Log.e(TAG, "(FPS Target: " + TARGET_FPS+ " ,FPS Actual: " + fps + ")");
lastFpsTime = 0;
fps = 0;
}
for (MyTextureView mtv : mItemList){
if (!mtv.isLocked()) {
mtv.doUpdate(delta);
mtv.doRender();
}
}
long sleepTime = (lastLoopTime-System.nanoTime() + OPTIMAL_TIME.get())/1000000;
sleepTime = sleepTime < 0 ? 0 : sleepTime;
try{
Thread.sleep( sleepTime );
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
MyTextureView doRender() method:
public void doRender() {
doubleBufferCanvas.drawPaint(Colors.BLACK);
doDraw(doubleBufferCanvas); //draws content onto secondary canvas
Canvas c = lockCanvas();
c.drawPaint(Colors.BLACK);
c.save();
c.drawBitmap(dbbmp, 0, 0, null);
c.restore();
unlockCanvasAndPost(c);
}
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…