分类: LINUX
2009-01-04 17:39:04
In Android, every window is implemented with an underlaying Surface
object. A Surface is an object that gets composited onto the
framebuffer by SurfaceFlinger, the sytem-wide screen composer.
Each Surface is double-buffered, it has a back buffer which is where
drawing takes place and a front buffer which is used for composition.
When "unlockCanvas()" is called, the back buffer is "posted", which
means it's being displayed and becomes available again.
However, the *implementation* of this mechanism is done by swapping
the front and back buffers. The back buffer becomes the front buffer
and vice-versa.
This mechanism ensures that there is a minimal amount of buffer
copying (a post operation doesn't move any pixels around) and that
there is always a buffer for SurfaceFlinger to use for composition.
This last feature is very important because it ensures that the screen
never flickers and never shows any artifacts *and* that
SurfaceFlinger never has to wait for a Surface to be ready (its front
buffer is always ready by definition), this means that a badly written
application cannot slowdown or interfere with other application's
windows.
As a side note, it is worth noting that the main screen itself (the
frame buffer) is double-buffered as well and uses the same posting
mechanism than any regular surface.
It should appear now that because of this posting mechanism,
incremental updates are not supported; and this is /the/ key point.
Back to your question now:
> 2. Android's Surface does not behaves like regular "double-buffer"
> system, which means: draw everything in back buffer and then flip the
> back buffer into the front buffer.
> What Android Surface does seems to be: draw in buffer A and flip it on
> the screen, then in next cycle, draw buffer B and flip it on the
> screen. As the result, the content visible on the screen comes from
> buffer A, B, A, B, A, .... I'm using buffer "A" and "B" here instead
> of "front" and "back" because I think they have equal role in
> rendering cycle.
> 3. The Surface buffer's alternate work style causes problem when I'm
> doing partial update (repaint only a portion of the Surface) for the
> performance purpose. Because one "lockCanvas-drawCanvas-unlockCanvas"
> cycle only update one buffer, the other one remains untouched, then
> when next "lockCanvas-drawCanvas-unlockCanvas" comes, it shows you an
> old content on the screen so that the flicker happens.
There is fact an API on the underlaying Surface object that allows to
update only a portion of the back buffer (but even then, every pixel
of that portion need to be redrawn). It is implemented by copying back
the former back buffer (now in the front) to the new back buffer
(formerly in the front). Unfortunately, this API is not exposed to
SurfaceView at the moment. I'm hoping to have this feature added
eventually.
- create a bitmap
- attach a canvas to it
- do the rendering into that canvas
- lockCanvas
- draw your bitmap into the backbuffer
- unlockAndPost
Note that this method involves an extra copy of the whole buffer size,
but it is in fact not slower than what it would have been if the
posting mechanism worked as you expected/suggested.