Understanding Canvas and Surface Concepts

Understanding Canvas and Surface concepts

Here are some definitions:

  • A Surface is an object holding pixels that are being composited to the screen. Every window you see on the screen (a dialog, your full-screen activity, the status bar) has its own surface that it draws in to, and Surface Flinger renders these to the final display in their correct Z-order. A surface typically has more than one buffer (usually two) to do double-buffered rendering: the application can be drawing its next UI state while the surface flinger is compositing the screen using the last buffer, without needing to wait for the application to finish drawing.

  • A window is basically like you think of a window on the desktop. It has a single Surface in which the contents of the window is rendered. An application interacts with the Window Manager to create windows; the Window Manager creates a Surface for each window and gives it to the application for drawing. The application can draw whatever it wants in the Surface; to the Window Manager it is just an opaque rectangle.

  • A View is an interactive UI element inside of a window. A window has a single view hierarchy attached to it, which provides all of the behavior of the window. Whenever the window needs to be redrawn (such as because a view has invalidated itself), this is done into the window's Surface. The Surface is locked, which returns a Canvas that can be used to draw into it. A draw traversal is done down the hierarchy, handing the Canvas down for each view to draw its part of the UI. Once done, the Surface is unlocked and posted so that the just drawn buffer is swapped to the foreground to then be composited to the screen by Surface Flinger.

  • A SurfaceView is a special implementation of View that also creates its own dedicated Surface for the application to directly draw into (outside of the normal view hierarchy, which otherwise must share the single Surface for the window). The way this works is simpler than you may expect -- all SurfaceView does is ask the window manager to create a new window, telling it to Z-order that window either immediately behind or in front of the SurfaceView's window, and positioning it to match where the SurfaceView appears in the containing window. If the surface is being placed behind the main window (in Z order), SurfaceView also fills its part of the main window with transparency so that the surface can be seen.

  • A Bitmap is just an interface to some pixel data. The pixels may be allocated by Bitmap itself when you are directly creating one, or it may be pointing to pixels it doesn't own such as what internally happens to hook a Canvas up to a Surface for drawing. (A Bitmap is created and pointed to the current drawing buffer of the Surface.)

Also please keep in mind that, as this implies, a SurfaceView is a pretty heavy-weight object. If you have multiple SurfaceViews in a particular UI, stop and think about whether this is really needed. If you have more than two, you almost certainly have too many.

Relationship between Surface and Canvas: Android

A surface is a buffer. A Canvas holds the drawing.

Views are not attached to the Canvas
nor the Surface. The window is tied to
a Surface and the ViewRoot asks the
Surface for a Canvas that is then used
by the Views to draw onto.

For a detailled anwser, you can read this whole discussion, really interesting.

Does every view have its own canvas/bitmap to draw on?

As per the documentation http://developer.android.com/guide/topics/graphics/2d-graphics.html#draw-with-canvas:

When you're writing an application in which you would like to perform specialized drawing and/or control the animation of graphics, you should do so by drawing through a Canvas. A Canvas works for you as a pretense, or interface, to the actual surface upon which your graphics will be drawn — it holds all of your "draw" calls. Via the Canvas, your drawing is actually performed upon an underlying Bitmap, which is placed into the window.

In the onDraw(Canvas canvas), you are given a canvas object. This canvas has an underlying bitmap. All views are not given the same canvas. Canvas is just a layer above the common bitmap (which is pixels on the screen). canvas offers you to manipulate the bitmap as much as you want. So every view has a canvas, but not it's own bitmap.

So no, as far as memory is concerned, three view doesn't mean memory is tripled, because there is just one bitmap. You could however create your own bitmap, if you do so, then you will be jogging up the memory. If you create 3 bitmaps with size of the screen, your memory will be tripled.

Surface Flinger,SurfaceView,Surface,SurfaceHolder and Bitmap is Android

A Canvas is a basic context for doing drawing with the graphics API. You can create your own Canvas wrapping a Bitmap for doing off-screen drawing, and of course the UI framework will pass Canvases to widgets for them to draw themselves into. All these widgets are subclasses of View. Or, if they can contain other widgets, then they subclass from ViewGroup (which is a subclass of View).

If you want to do high-frame-rate animations, then you need to subclass from SurfaceView (or its subclass GLSurfaceView, if you want to do on-screen OpenGL-ES rendering). Each SurfaceView has a SurfaceHolder, which has lockCanvas methods that you can call at any time to get a Canvas into which to draw an updated display and post back for the user to see immediately via unlockCanvasAndPost.

For more info, see 2D graphics concepts and Custom widget tips

EGL_BAD_ALLOC after switching SurfaceView Surface from canvas to OpenGL

This is the expected behaviour, as stated on the official documentation

When you lock a Surface for Canvas access, the "CPU renderer" connects to the producer side of the BufferQueue and does not disconnect until the Surface is destroyed. Most other producers (like GLES) can be disconnected and reconnected to a Surface, but the Canvas-based "CPU renderer" cannot. This means you can't draw on a surface with GLES or send it frames from a video decoder if you've ever locked it for a Canvas.

https://source.android.com/devices/graphics/arch-sh.html#canvas

So the only way is to use the workaround I posted in my question

------------------ EDIT: -----------------

I've found another way to do it: if you need to draw using a Canvas, you have to create an EGL/OpenGL context, and a Canvas from a Bitmap(that you have to create of the same size of your surface,
So you can draw to this canvas, load the bitmap as opengl texture and draw it from OpenGL



Related Topics



Leave a reply



Submit