Home | History | Annotate | Download | only in graphics
      1 <html devsite>
      2   <head>
      3     <title>Surface and SurfaceHolder</title>
      4     <meta name="project_path" value="/_project.yaml" />
      5     <meta name="book_path" value="/_book.yaml" />
      6   </head>
      7   <body>
      8   <!--
      9       Copyright 2017 The Android Open Source Project
     10 
     11       Licensed under the Apache License, Version 2.0 (the "License");
     12       you may not use this file except in compliance with the License.
     13       You may obtain a copy of the License at
     14 
     15           http://www.apache.org/licenses/LICENSE-2.0
     16 
     17       Unless required by applicable law or agreed to in writing, software
     18       distributed under the License is distributed on an "AS IS" BASIS,
     19       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     20       See the License for the specific language governing permissions and
     21       limitations under the License.
     22   -->
     23 
     24 
     25 
     26 <p>The
     27 <a href="http://developer.android.com/reference/android/view/Surface.html">Surface</a>
     28 class has been part of the public API since 1.0.  Its description simply says,
     29 "Handle onto a raw buffer that is being managed by the screen compositor."  The
     30 statement was accurate when initially written but falls well short of the mark
     31 on a modern system.</p>
     32 
     33 <p>The Surface represents the producer side of a buffer queue that is often (but
     34 not always!) consumed by SurfaceFlinger.  When you render onto a Surface, the
     35 result ends up in a buffer that gets shipped to the consumer.  A Surface is not
     36 simply a raw chunk of memory you can scribble on.</p>
     37 
     38 <p>The BufferQueue for a display Surface is typically configured for
     39 triple-buffering; but buffers are allocated on demand.  So if the producer
     40 generates buffers slowly enough -- maybe it's animating at 30fps on a 60fps
     41 display -- there might only be two allocated buffers in the queue.  This helps
     42 minimize memory consumption.  You can see a summary of the buffers associated
     43 with every layer in the <code>dumpsys SurfaceFlinger</code> output.</p>
     44 
     45 <h2 id="canvas">Canvas Rendering</h2>
     46 
     47 <p>Once upon a time, all rendering was done in software, and you can still do this
     48 today.  The low-level implementation is provided by the Skia graphics library.
     49 If you want to draw a rectangle, you make a library call, and it sets bytes in a
     50 buffer appropriately.  To ensure that a buffer isn't updated by two clients at
     51 once, or written to while being displayed, you have to lock the buffer to access
     52 it.  <code>lockCanvas()</code> locks the buffer and returns a Canvas to use for drawing,
     53 and <code>unlockCanvasAndPost()</code> unlocks the buffer and sends it to the compositor.</p>
     54 
     55 <p>As time went on, and devices with general-purpose 3D engines appeared, Android
     56 reoriented itself around OpenGL ES.  However, it was important to keep the old
     57 API working, for apps as well as app framework code, so an effort was made to
     58 hardware-accelerate the Canvas API.  As you can see from the charts on the
     59 <a href="http://developer.android.com/guide/topics/graphics/hardware-accel.html">Hardware
     60 Acceleration</a>
     61 page, this was a bit of a bumpy ride.  Note in particular that while the Canvas
     62 provided to a View's <code>onDraw()</code> method may be hardware-accelerated, the Canvas
     63 obtained when an app locks a Surface directly with <code>lockCanvas()</code> never is.
     64 As of API 23, a hardware-accelerated Canvas can be obtained from a Surface using
     65 <code>lockHardwareCanvas()</code> instead.</p>
     66 
     67 <p>When you lock a Surface for Canvas access, the "CPU renderer" connects to the
     68 producer side of the BufferQueue and does not disconnect until the Surface is
     69 destroyed.  Most other producers (like GLES) can be disconnected and reconnected
     70 to a Surface, but the Canvas-based "CPU renderer" cannot.  This means you can't
     71 draw on a surface with GLES or send it frames from a video decoder if you've
     72 ever locked it for a Canvas.</p>
     73 
     74 <p>The first time the producer requests a buffer from a BufferQueue, it is
     75 allocated and initialized to zeroes.  Initialization is necessary to avoid
     76 inadvertently sharing data between processes.  When you re-use a buffer,
     77 however, the previous contents will still be present.  If you repeatedly call
     78 <code>lockCanvas()</code> and <code>unlockCanvasAndPost()</code> without
     79 drawing anything, you'll cycle between previously-rendered frames.</p>
     80 
     81 <p>The Surface lock/unlock code keeps a reference to the previously-rendered
     82 buffer.  If you specify a dirty region when locking the Surface, it will copy
     83 the non-dirty pixels from the previous buffer.  There's a fair chance the buffer
     84 will be handled by SurfaceFlinger or HWC; but since we need to only read from
     85 it, there's no need to wait for exclusive access.</p>
     86 
     87 <p>The main non-Canvas way for an application to draw directly on a Surface is
     88 through OpenGL ES.  That's described in the <a href="#eglsurface">EGLSurface and
     89 OpenGL ES</a> section.</p>
     90 
     91 <h2 id="surfaceholder">SurfaceHolder</h2>
     92 
     93 <p>Some things that work with Surfaces want a SurfaceHolder, notably SurfaceView.
     94 The original idea was that Surface represented the raw compositor-managed
     95 buffer, while SurfaceHolder was managed by the app and kept track of
     96 higher-level information like the dimensions and format.  The Java-language
     97 definition mirrors the underlying native implementation.  It's arguably no
     98 longer useful to split it this way, but it has long been part of the public API.</p>
     99 
    100 <p>Generally speaking, anything having to do with a View will involve a
    101 SurfaceHolder.  Some other APIs, such as MediaCodec, will operate on the Surface
    102 itself.  You can easily get the Surface from the SurfaceHolder, so hang on to
    103 the latter when you have it.</p>
    104 
    105 <p>APIs to get and set Surface parameters, such as the size and format, are
    106 implemented through SurfaceHolder.</p>
    107 
    108   </body>
    109 </html>
    110