Merge "Docs: Adding system-level graphics documentation."
diff --git a/src/devices/devices_toc.cs b/src/devices/devices_toc.cs
index 3b74d81..9d721e8 100644
--- a/src/devices/devices_toc.cs
+++ b/src/devices/devices_toc.cs
@@ -81,7 +81,16 @@
           <li><a href="<?cs var:toroot ?>devices/tech/storage/config-example.html">Typical Configuration Examples</a></li>
-      <li><a href="<?cs var:toroot ?>devices/graphics.html">Graphics</a></li>
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>devices/graphics.html">
+            <span class="en">Graphics</span>
+          </a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>devices/graphics/architecture.html">System-Level Architecture</a></li>
+        </ul>
+      </li>
       <li class="nav-section">
         <div class="nav-section-header">
           <a href="<?cs var:toroot ?>devices/tech/input/index.html">
diff --git a/src/devices/graphics/architecture.jd b/src/devices/graphics/architecture.jd
new file mode 100644
index 0000000..6842dd7
--- /dev/null
+++ b/src/devices/graphics/architecture.jd
@@ -0,0 +1,1222 @@
+    Copyright 2014 The Android Open Source Project
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>In this document</h2>
+    <ol id="auto-toc">
+    </ol>
+  </div>
+<p><em>What every developer should know about Surface, SurfaceHolder, EGLSurface,
+SurfaceView, GLSurfaceView, SurfaceTexture, TextureView, and SurfaceFlinger</em>
+<p>This document describes the essential elements of Android's "system-level"
+  graphics architecture, and how it is used by the application framework and
+  multimedia system.  The focus is on how buffers of graphical data move through
+  the system.  If you've ever wondered why SurfaceView and TextureView behave the
+  way they do, or how Surface and EGLSurface interact, you've come to the right
+<p>Some familiarity with Android devices and application development is assumed.
+You don't need detailed knowledge of the app framework, and very few API calls
+will be mentioned, but the material herein doesn't overlap much with other
+public documentation.  The goal here is to provide a sense for the significant
+events involved in rendering a frame for output, so that you can make informed
+choices when designing an application.  To achieve this, we work from the bottom
+up, describing how the UI classes work rather than how they can be used.</p>
+<p>Early sections contain background material used in later sections, so it's a
+good idea to read straight through rather than skipping to a section that sounds
+interesting.  We start with an explanation of Android's graphics buffers,
+describe the composition and display mechanism, and then proceed to the
+higher-level mechanisms that supply the compositor with data.</p>
+<p>This document is chiefly concerned with the system as it exists in Android 4.4
+("KitKat").  Earlier versions of the system worked differently, and future
+versions will likely be different as well.  Version-specific features are called
+out in a few places.</p>
+<p>At various points I will refer to source code from the AOSP sources or from
+Grafika.  Grafika is a Google open-source project for testing; it can be found at
+It's more "quick hack" than solid example code, but it will suffice.</p>
+<h2 id="BufferQueue">BufferQueue and gralloc</h2>
+<p>To understand how Android's graphics system works, we have to start behind the
+scenes.  At the heart of everything graphical in Android is a class called
+BufferQueue.  Its role is simple enough: connect something that generates
+buffers of graphical data (the "producer") to something that accepts the data
+for display or further processing (the "consumer").  The producer and consumer
+can live in different processes.  Nearly everything that moves buffers of
+graphical data through the system relies on BufferQueue.</p>
+<p>The basic usage is straightforward.  The producer requests a free buffer
+(<code>dequeueBuffer()</code>), specifying a set of characteristics including width,
+height, pixel format, and usage flags.  The producer populates the buffer and
+returns it to the queue (<code>queueBuffer()</code>).  Some time later, the consumer
+acquires the buffer (<code>acquireBuffer()</code>) and makes use of the buffer contents.
+When the consumer is done, it returns the buffer to the queue
+<p>Most recent Android devices support the "sync framework".  This allows the
+system to do some nifty thing when combined with hardware components that can
+manipulate graphics data asynchronously.  For example, a producer can submit a
+series of OpenGL ES drawing commands and then enqueue the output buffer before
+rendering completes.  The buffer is accompanied by a fence that signals when the
+contents are ready.  A second fence accompanies the buffer when it is returned
+to the free list, so that the consumer can release the buffer while the contents
+are still in use.  This approach improves latency and throughput as the buffers
+move through the system.</p>
+<p>Some characteristics of the queue, such as the maximum number of buffers it can
+hold, are determined jointly by the producer and the consumer.</p>
+<p>The BufferQueue is responsible for allocating buffers as it needs them.  Buffers
+are retained unless the characteristics change; for example, if the producer
+starts requesting buffers with a different size, the old buffers will be freed
+and new buffers will be allocated on demand.</p>
+<p>The data structure is currently always created and "owned" by the consumer.  In
+Android 4.3 only the producer side was "binderized", i.e. the producer could be
+in a remote process but the consumer had to live in the process where the queue
+was created.  This evolved a bit in 4.4, moving toward a more general
+<p>Buffer contents are never copied by BufferQueue.  Moving that much data around
+would be very inefficient.  Instead, buffers are always passed by handle.</p>
+<h3 id="gralloc_HAL">gralloc HAL</h3>
+<p>The actual buffer allocations are performed through a memory allocator called
+"gralloc", which is implemented through a vendor-specific HAL interface (see
+The <code>alloc()</code> function takes the arguments you'd expect -- width,
+height, pixel format -- as well as a set of usage flags.  Those flags merit
+closer attention.</p>
+<p>The gralloc allocator is not just another way to allocate memory on the native
+heap.  In some situations, the allocated memory may not be cache-coherent, or
+could be totally inaccessible from user space.  The nature of the allocation is
+determined by the usage flags, which include attributes like:</p>
+<li>how often the memory will be accessed from software (CPU)</li>
+<li>how often the memory will be accessed from hardware (GPU)</li>
+<li>whether the memory will be used as an OpenGL ES ("GLES") texture</li>
+<li>whether the memory will be used by a video encoder</li>
+<p>For example, if your format specifies RGBA 8888 pixels, and you indicate
+the buffer will be accessed from software -- meaning your application will touch
+pixels directly -- then the allocator needs to create a buffer with 4 bytes per
+pixel in R-G-B-A order.  If instead you say the buffer will only be
+accessed from hardware and as a GLES texture, the allocator can do anything the
+GLES driver wants -- BGRA ordering, non-linear "swizzled" layouts, alternative
+color formats, etc.  Allowing the hardware to use its preferred format can
+improve performance.</p>
+<p>Some values cannot be combined on certain platforms.  For example, the "video
+encoder" flag may require YUV pixels, so adding "software access" and specifying
+RGBA 8888 would fail.</p>
+<p>The handle returned by the gralloc allocator can be passed between processes
+through Binder.</p>
+<h2 id="SurfaceFlinger">SurfaceFlinger and Hardware Composer</h2>
+<p>Having buffers of graphical data is wonderful, but life is even better when you
+get to see them on your device's screen.  That's where SurfaceFlinger and the
+Hardware Composer HAL come in.</p>
+<p>SurfaceFlinger's role is to accept buffers of data from multiple sources,
+composite them, and send them to the display.  Once upon a time this was done
+with software blitting to a hardware framebuffer (e.g.
+<code>/dev/graphics/fb0</code>), but those days are long gone.</p>
+<p>When an app comes to the foreground, the WindowManager service asks
+SurfaceFlinger for a drawing surface.  SurfaceFlinger creates a "layer" - the
+primary component of which is a BufferQueue - for which SurfaceFlinger acts as
+the consumer.  A Binder object for the producer side is passed through the
+WindowManager to the app, which can then start sending frames directly to
+SurfaceFlinger.  (Note: The WindowManager uses the term "window" instead of
+"layer" for this and uses "layer" to mean something else.  We're going to use the
+SurfaceFlinger terminology.  It can be argued that SurfaceFlinger should really
+be called LayerFlinger.)</p>
+<p>For most apps, there will be three layers on screen at any time: the "status
+bar" at the top of the screen, the "navigation bar" at the bottom or side, and
+the application's UI.  Some apps will have more or less, e.g. the default home app has a
+separate layer for the wallpaper, while a full-screen game might hide the status
+bar.  Each layer can be updated independently.  The status and navigation bars
+are rendered by a system process, while the app layers are rendered by the app,
+with no coordination between the two.</p>
+<p>Device displays refresh at a certain rate, typically 60 frames per second on
+phones and tablets.  If the display contents are updated mid-refresh, "tearing"
+will be visible; so it's important to update the contents only between cycles.
+The system receives a signal from the display when it's safe to update the
+contents.  For historical reasons we'll call this the VSYNC signal.</p>
+<p>The refresh rate may vary over time, e.g. some mobile devices will range from 58
+to 62fps depending on current conditions.  For an HDMI-attached television, this
+could theoretically dip to 24 or 48Hz to match a video.  Because we can update
+the screen only once per refresh cycle, submitting buffers for display at
+200fps would be a waste of effort as most of the frames would never be seen.
+Instead of taking action whenever an app submits a buffer, SurfaceFlinger wakes
+up when the display is ready for something new.</p>
+<p>When the VSYNC signal arrives, SurfaceFlinger walks through its list of layers
+looking for new buffers.  If it finds a new one, it acquires it; if not, it
+continues to use the previously-acquired buffer.  SurfaceFlinger always wants to
+have something to display, so it will hang on to one buffer.  If no buffers have
+ever been submitted on a layer, the layer is ignored.</p>
+<p>Once SurfaceFlinger has collected all of the buffers for visible layers, it
+asks the Hardware Composer how composition should be performed.</p>
+<h3 id="hwcomposer">Hardware Composer</h3>
+<p>The Hardware Composer HAL ("HWC") was first introduced in Android 3.0
+("Honeycomb") and has evolved steadily over the years.  Its primary purpose is
+to determine the most efficient way to composite buffers with the available
+hardware.  As a HAL, its implementation is device-specific and usually
+implemented by the display hardware OEM.</p>
+<p>The value of this approach is easy to recognize when you consider "overlay
+planes."  The purpose of overlay planes is to composite multiple buffers
+together, but in the display hardware rather than the GPU.  For example, suppose
+you have a typical Android phone in portrait orientation, with the status bar on
+top and navigation bar at the bottom, and app content everywhere else.  The contents
+for each layer are in separate buffers.  You could handle composition by
+rendering the app content into a scratch buffer, then rendering the status bar
+over it, then rendering the navigation bar on top of that, and finally passing the
+scratch buffer to the display hardware.  Or, you could pass all three buffers to
+the display hardware, and tell it to read data from different buffers for
+different parts of the screen.  The latter approach can be significantly more
+<p>As you might expect, the capabilities of different display processors vary
+significantly.  The number of overlays, whether layers can be rotated or
+blended, and restrictions on positioning and overlap can be difficult to express
+through an API.  So, the HWC works like this:</p>
+<li>SurfaceFlinger provides the HWC with a full list of layers, and asks, "how do
+you want to handle this?"</li>
+<li>The HWC responds by marking each layer as "overlay" or "GLES composition."</li>
+<li>SurfaceFlinger takes care of any GLES composition, passing the output buffer
+to HWC, and lets HWC handle the rest.</li>
+<p>Since the decision-making code can be custom tailored by the hardware vendor,
+it's possible to get the best performance out of every device.</p>
+<p>Overlay planes may be less efficient than GL composition when nothing on the
+screen is changing.  This is particularly true when the overlay contents have
+transparent pixels, and overlapping layers are being blended together.  In such
+cases, the HWC can choose to request GLES composition for some or all layers
+and retain the composited buffer.  If SurfaceFlinger comes back again asking to
+composite the same set of buffers, the HWC can just continue to show the
+previously-composited scratch buffer.  This can improve the battery life of an
+idle device.</p>
+<p>Devices shipping with Android 4.4 ("KitKat") typically support four overlay
+planes.  Attempting to composite more layers than there are overlays will cause
+the system to use GLES composition for some of them; so the number of layers
+used by an application can have a measurable impact on power consumption and
+<p>You can see exactly what SurfaceFlinger is up to with the command <code>adb shell
+dumpsys SurfaceFlinger</code>.  The output is verbose.  The part most relevant to our
+current discussion is the HWC summary that appears near the bottom of the
+    type    |          source crop              |           frame           name
+        HWC | [    0.0,    0.0,  320.0,  240.0] | [   48,  411, 1032, 1149] SurfaceView
+        HWC | [    0.0,   75.0, 1080.0, 1776.0] | [    0,   75, 1080, 1776]
+        HWC | [    0.0,    0.0, 1080.0,   75.0] | [    0,    0, 1080,   75] StatusBar
+        HWC | [    0.0,    0.0, 1080.0,  144.0] | [    0, 1776, 1080, 1920] NavigationBar
+  FB TARGET | [    0.0,    0.0, 1080.0, 1920.0] | [    0,    0, 1080, 1920] HWC_FRAMEBUFFER_TARGET
+<p>This tells you what layers are on screen, whether they're being handled with
+overlays ("HWC") or OpenGL ES composition ("GLES"), and gives you a bunch of
+other facts you probably won't care about ("handle" and "hints" and "flags" and
+other stuff that we've trimmed out of the snippet above).  The "source crop" and
+"frame" values will be examined more closely later on.</p>
+<p>The FB_TARGET layer is where GLES composition output goes.  Since all layers
+shown above are using overlays, FB_TARGET isn’t being used for this frame. The
+layer's name is indicative of its original role: On a device with
+<code>/dev/graphics/fb0</code> and no overlays, all composition would be done
+with GLES, and the output would be written to the framebuffer.  On recent devices there
+generally is no simple framebuffer, so the FB_TARGET layer is a scratch buffer.
+(Note: This is why screen grabbers written for old versions of Android no
+longer work: They're trying to read from The Framebuffer, but there is no such
+<p>The overlay planes have another important role: they're the only way to display
+DRM content.  DRM-protected buffers cannot be accessed by SurfaceFlinger or the
+GLES driver, which means that your video will disappear if HWC switches to GLES
+<h3 id="triple-buffering">The Need for Triple-Buffering</h3>
+<p>To avoid tearing on the display, the system needs to be double-buffered: the
+front buffer is displayed while the back buffer is being prepared.  At VSYNC, if
+the back buffer is ready, you quickly switch them.  This works reasonably well
+in a system where you're drawing directly into the framebuffer, but there's a
+hitch in the flow when a composition step is added.  Because of the way
+SurfaceFlinger is triggered, our double-buffered pipeline will have a bubble.</p>
+<p>Suppose frame N is being displayed, and frame N+1 has been acquired by
+SurfaceFlinger for display on the next VSYNC.  (Assume frame N is composited
+with an overlay, so we can't alter the buffer contents until the display is done
+with it.)  When VSYNC arrives, HWC flips the buffers.  While the app is starting
+to render frame N+2 into the buffer that used to hold frame N, SurfaceFlinger is
+scanning the layer list, looking for updates.  SurfaceFlinger won't find any new
+buffers, so it prepares to show frame N+1 again after the next VSYNC.  A little
+while later, the app finishes rendering frame N+2 and queues it for
+SurfaceFlinger, but it's too late.  This has effectively cut our maximum frame
+rate in half.</p>
+<p>We can fix this with triple-buffering.  Just before VSYNC, frame N is being
+displayed, frame N+1 has been composited (or scheduled for an overlay) and is
+ready to be displayed, and frame N+2 is queued up and ready to be acquired by
+SurfaceFlinger.  When the screen flips, the buffers rotate through the stages
+with no bubble.  The app has just less than a full VSYNC period (16.7ms at 60fps) to
+do its rendering and queue the buffer. And SurfaceFlinger / HWC has a full VSYNC
+period to figure out the composition before the next flip.  The downside is
+that it takes at least two VSYNC periods for anything that the app does to
+appear on the screen.  As the latency increases, the device feels less
+responsive to touch input.</p>
+<img src="images/surfaceflinger_bufferqueue.png" alt="SurfaceFlinger with BufferQueue" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> SurfaceFlinger + BufferQueue
+<p>The diagram above depicts the flow of SurfaceFlinger and BufferQueue. During
+<li>red buffer fills up, then slides into BufferQueue</li>
+<li>after red buffer leaves app, blue buffer slides in, replacing it</li>
+<li>green buffer and systemUI* shadow-slide into HWC (showing that SurfaceFlinger
+still has the buffers, but now HWC has prepared them for display via overlay on
+the next VSYNC).</li>
+<p>The blue buffer is referenced by both the display and the BufferQueue.  The
+app is not allowed to render to it until the associated sync fence signals.</p>
+<p>On VSYNC, all of these happen at once:</p>
+<li>red buffer leaps into SurfaceFlinger, replacing green buffer</li>
+<li>green buffer leaps into Display, replacing blue buffer, and a dotted-line
+green twin appears in the BufferQueue</li>
+<li>the blue buffer’s fence is signaled, and the blue buffer in App empties**</li>
+<li>display rect changes from &lt;blue + SystemUI&gt; to &lt;green +
+<p><strong>*</strong> - The System UI process is providing the status and nav
+bars, which for our purposes here aren’t changing, so SurfaceFlinger keeps using
+the previously-acquired buffer.  In practice there would be two separate
+buffers, one for the status bar at the top, one for the navigation bar at the
+bottom, and they would be sized to fit their contents.  Each would arrive on its
+own BufferQueue.</p>
+<p><strong>**</strong> - The buffer doesn’t actually “empty”; if you submit it
+without drawing on it you’ll get that same blue again.  The emptying is the
+result of clearing the buffer contents, which the app should do before it starts
+<p>We can reduce the latency by noting layer composition should not require a
+full VSYNC period.  If composition is performed by overlays, it takes essentially
+zero CPU and GPU time. But we can't count on that, so we need to allow a little
+time.  If the app starts rendering halfway between VSYNC signals, and
+SurfaceFlinger defers the HWC setup until a few milliseconds before the signal
+is due to arrive, we can cut the latency from 2 frames to perhaps 1.5.  In
+theory you could render and composite in a single period, allowing a return to
+double-buffering; but getting it down that far is difficult on current devices.
+Minor fluctuations in rendering and composition time, and switching from
+overlays to GLES composition, can cause us to miss a swap deadline and repeat
+the previous frame.</p>
+<p>SurfaceFlinger's buffer handling demonstrates the fence-based buffer
+management mentioned earlier.  If we're animating at full speed, we need to
+have an acquired buffer for the display ("front") and an acquired buffer for
+the next flip ("back").  If we're showing the buffer on an overlay, the
+contents are being accessed directly by the display and must not be touched.
+But if you look at an active layer's BufferQueue state in the <code>dumpsys
+SurfaceFlinger</code> output, you'll see one acquired buffer, one queued buffer, and
+one free buffer.  That's because, when SurfaceFlinger acquires the new "back"
+buffer, it releases the current "front" buffer to the queue.  The "front"
+buffer is still in use by the display, so anything that dequeues it must wait
+for the fence to signal before drawing on it.  So long as everybody follows
+the fencing rules, all of the queue-management IPC requests can happen in
+parallel with the display.</p>
+<h3 id="virtual-displays">Virtual Displays</h3>
+<p>SurfaceFlinger supports a "primary" display, i.e. what's built into your phone
+or tablet, and an "external" display, such as a television connected through
+HDMI.  It also supports a number of "virtual" displays, which make composited
+output available within the system.  Virtual displays can be used to record the
+screen or send it over a network.</p>
+<p>Virtual displays may share the same set of layers as the main display
+(the "layer stack") or have its own set.  There is no VSYNC for a virtual
+display, so the VSYNC for the primary display is used to trigger composition for
+all displays.</p>
+<p>In the past, virtual displays were always composited with GLES.  The Hardware
+Composer managed composition for only the primary display.  In Android 4.4, the
+Hardware Composer gained the ability to participate in virtual display
+<p>As you might expect, the frames generated for a virtual display are written to a
+<h3 id="screenrecord">Case study: screenrecord</h3>
+<p>Now that we've established some background on BufferQueue and SurfaceFlinger,
+it's useful to examine a practical use case.</p>
+<p>The <a href="">screenrecord
+introduced in Android 4.4, allows you to record everything that appears on the
+screen as an .mp4 file on disk.  To implement this, we have to receive composited
+frames from SurfaceFlinger, write them to the video encoder, and then write the
+encoded video data to a file.  The video codecs are managed by a separate
+process - called "mediaserver" - so we have to move large graphics buffers around
+the system.  To make it more challenging, we're trying to record 60fps video at
+full resolution.  The key to making this work efficiently is BufferQueue.</p>
+<p>The MediaCodec class allows an app to provide data as raw bytes in buffers, or
+through a Surface.  We'll discuss Surface in more detail later, but for now just
+think of it as a wrapper around the producer end of a BufferQueue.  When
+screenrecord requests access to a video encoder, mediaserver creates a
+BufferQueue and connects itself to the consumer side, and then passes the
+producer side back to screenrecord as a Surface.</p>
+<p>The screenrecord command then asks SurfaceFlinger to create a virtual display
+that mirrors the main display (i.e. it has all of the same layers), and directs
+it to send output to the Surface that came from mediaserver.  Note that, in this
+case, SurfaceFlinger is the producer of buffers rather than the consumer.</p>
+<p>Once the configuration is complete, screenrecord can just sit and wait for
+encoded data to appear.  As apps draw, their buffers travel to SurfaceFlinger,
+which composites them into a single buffer that gets sent directly to the video
+encoder in mediaserver.  The full frames are never even seen by the screenrecord
+process.  Internally, mediaserver has its own way of moving buffers around that
+also passes data by handle, minimizing overhead.</p>
+<h3 id="simulate-secondary">Case study: Simulate Secondary Displays</h3>
+<p>The WindowManager can ask SurfaceFlinger to create a visible layer for which
+SurfaceFlinger will act as the BufferQueue consumer.  It's also possible to ask
+SurfaceFlinger to create a virtual display, for which SurfaceFlinger will act as
+the BufferQueue producer.  What happens if you connect them, configuring a
+virtual display that renders to a visible layer?</p>
+<p>You create a closed loop, where the composited screen appears in a window.  Of
+course, that window is now part of the composited output, so on the next refresh
+the composited image inside the window will show the window contents as well.
+It's turtles all the way down.  You can see this in action by enabling
+"<a href="">Developer options</a>" in
+settings, selecting "Simulate secondary displays", and enabling a window.  For
+bonus points, use screenrecord to capture the act of enabling the display, then
+play it back frame-by-frame.</p>
+<h2 id="surface">Surface and SurfaceHolder</h2>
+<p>The <a
+class has been part of the public API since 1.0.  Its description simply says,
+"Handle onto a raw buffer that is being managed by the screen compositor."  The
+statement was accurate when initially written but falls well short of the mark
+on a modern system.</p>
+<p>The Surface represents the producer side of a buffer queue that is often (but
+not always!) consumed by SurfaceFlinger.  When you render onto a Surface, the
+result ends up in a buffer that gets shipped to the consumer.  A Surface is not
+simply a raw chunk of memory you can scribble on.</p>
+<p>The BufferQueue for a display Surface is typically configured for
+triple-buffering; but buffers are allocated on demand.  So if the producer
+generates buffers slowly enough -- maybe it's animating at 30fps on a 60fps
+display -- there might only be two allocated buffers in the queue.  This helps
+minimize memory consumption.  You can see a summary of the buffers associated
+with every layer in the <code>dumpsys SurfaceFlinger</code> output.</p>
+<h3 id="canvas">Canvas Rendering</h3>
+<p>Once upon a time, all rendering was done in software, and you can still do this
+today.  The low-level implementation is provided by the Skia graphics library.
+If you want to draw a rectangle, you make a library call, and it sets bytes in a
+buffer appropriately.  To ensure that a buffer isn't updated by two clients at
+once, or written to while being displayed, you have to lock the buffer to access
+it.  <code>lockCanvas()</code> locks the buffer and returns a Canvas to use for drawing,
+and <code>unlockCanvasAndPost()</code> unlocks the buffer and sends it to the compositor.</p>
+<p>As time went on, and devices with general-purpose 3D engines appeared, Android
+reoriented itself around OpenGL ES.  However, it was important to keep the old
+API working, for apps as well as app framework code, so an effort was made to
+hardware-accelerate the Canvas API.  As you can see from the charts on the
+<a href="">Hardware
+page, this was a bit of a bumpy ride.  Note in particular that while the Canvas
+provided to a View's <code>onDraw()</code> method may be hardware-accelerated, the Canvas
+obtained when an app locks a Surface directly with <code>lockCanvas()</code> never is.</p>
+<p>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.</p>
+<p>The first time the producer requests a buffer from a BufferQueue, it is
+allocated and initialized to zeroes.  Initialization is necessary to avoid
+inadvertently sharing data between processes.  When you re-use a buffer,
+however, the previous contents will still be present.  If you repeatedly call
+<code>lockCanvas()</code> and <code>unlockCanvasAndPost()</code> without
+drawing anything, you'll cycle between previously-rendered frames.</p>
+<p>The Surface lock/unlock code keeps a reference to the previously-rendered
+buffer.  If you specify a dirty region when locking the Surface, it will copy
+the non-dirty pixels from the previous buffer.  There's a fair chance the buffer
+will be handled by SurfaceFlinger or HWC; but since we need to only read from
+it, there's no need to wait for exclusive access.</p>
+<p>The main non-Canvas way for an application to draw directly on a Surface is
+through OpenGL ES.  That's described in the <a href="#eglsurface">EGLSurface and
+OpenGL ES</a> section.</p>
+<h3 id="surfaceholder">SurfaceHolder</h3>
+<p>Some things that work with Surfaces want a SurfaceHolder, notably SurfaceView.
+The original idea was that Surface represented the raw compositor-managed
+buffer, while SurfaceHolder was managed by the app and kept track of
+higher-level information like the dimensions and format.  The Java-language
+definition mirrors the underlying native implementation.  It's arguably no
+longer useful to split it this way, but it has long been part of the public API.</p>
+<p>Generally speaking, anything having to do with a View will involve a
+SurfaceHolder.  Some other APIs, such as MediaCodec, will operate on the Surface
+itself.  You can easily get the Surface from the SurfaceHolder, so hang on to
+the latter when you have it.</p>
+<p>APIs to get and set Surface parameters, such as the size and format, are
+implemented through SurfaceHolder.</p>
+<h2 id="eglsurface">EGLSurface and OpenGL ES</h2>
+<p>OpenGL ES defines an API for rendering graphics.  It does not define a windowing
+system.  To allow GLES to work on a variety of platforms, it is designed to be
+combined with a library that knows how to create and access windows through the
+operating system.  The library used for Android is called EGL.  If you want to
+draw textured polygons, you use GLES calls; if you want to put your rendering on
+the screen, you use EGL calls.</p>
+<p>Before you can do anything with GLES, you need to create a GL context.  In EGL,
+this means creating an EGLContext and an EGLSurface.  GLES operations apply to
+the current context, which is accessed through thread-local storage rather than
+passed around as an argument.  This means you have to be careful about which
+thread your rendering code executes on, and which context is current on that
+<p>The EGLSurface can be an off-screen buffer allocated by EGL (called a "pbuffer")
+or a window allocated by the operating system.  EGL window surfaces are created
+with the <code>eglCreateWindowSurface()</code> call.  It takes a "window object" as an
+argument, which on Android can be a SurfaceView, a SurfaceTexture, a
+SurfaceHolder, or a Surface -- all of which have a BufferQueue underneath.  When
+you make this call, EGL creates a new EGLSurface object, and connects it to the
+producer interface of the window object's BufferQueue.  From that point onward,
+rendering to that EGLSurface results in a buffer being dequeued, rendered into,
+and queued for use by the consumer.  (The term "window" is indicative of the
+expected use, but bear in mind the output might not be destined to appear
+on the display.)</p>
+<p>EGL does not provide lock/unlock calls.  Instead, you issue drawing commands and
+then call <code>eglSwapBuffers()</code> to submit the current frame.  The
+method name comes from the traditional swap of front and back buffers, but the actual
+implementation may be very different.</p>
+<p>Only one EGLSurface can be associated with a Surface at a time -- you can have
+only one producer connected to a BufferQueue -- but if you destroy the
+EGLSurface it will disconnect from the BufferQueue and allow something else to
+<p>A given thread can switch between multiple EGLSurfaces by changing what's
+"current."  An EGLSurface must be current on only one thread at a time.</p>
+<p>The most common mistake when thinking about EGLSurface is assuming that it is
+just another aspect of Surface (like SurfaceHolder).  It's a related but
+independent concept.  You can draw on an EGLSurface that isn't backed by a
+Surface, and you can use a Surface without EGL.  EGLSurface just gives GLES a
+place to draw.</p>
+<h3 id="anativewindow">ANativeWindow</h3>
+<p>The public Surface class is implemented in the Java programming language.  The
+equivalent in C/C++ is the ANativeWindow class, semi-exposed by the <a
+href="">Android NDK</a>.  You
+can get the ANativeWindow from a Surface with the <code>ANativeWindow_fromSurface()</code>
+call.  Just like its Java-language cousin, you can lock it, render in software,
+and unlock-and-post.</p>
+<p>To create an EGL window surface from native code, you pass an instance of
+EGLNativeWindowType to <code>eglCreateWindowSurface()</code>.  EGLNativeWindowType is just
+a synonym for ANativeWindow, so you can freely cast one to the other.</p>
+<p>The fact that the basic "native window" type just wraps the producer side of a
+BufferQueue should not come as a surprise.</p>
+<h2 id="surfaceview">SurfaceView and GLSurfaceView</h2>
+<p>Now that we've explored the lower-level components, it's time to see how they
+fit into the higher-level components that apps are built from.</p>
+<p>The Android app framework UI is based on a hierarchy of objects that start with
+View.  Most of the details don't matter for this discussion, but it's helpful to
+understand that UI elements go through a complicated measurement and layout
+process that fits them into a rectangular area.  All visible View objects are
+rendered to a SurfaceFlinger-created Surface that was set up by the
+WindowManager when the app was brought to the foreground.  The layout and
+rendering is performed on the app's UI thread.</p>
+<p>Regardless of how many Layouts and Views you have, everything gets rendered into
+a single buffer.  This is true whether or not the Views are hardware-accelerated.</p>
+<p>A SurfaceView takes the same sorts of parameters as other views, so you can give
+it a position and size, and fit other elements around it.  When it comes time to
+render, however, the contents are completely transparent.  The View part of a
+SurfaceView is just a see-through placeholder.</p>
+<p>When the SurfaceView's View component is about to become visible, the framework
+asks the WindowManager to ask SurfaceFlinger to create a new Surface.  (This
+doesn't happen synchronously, which is why you should provide a callback that
+notifies you when the Surface creation finishes.)  By default, the new Surface
+is placed behind the app UI Surface, but the default "Z-ordering" can be
+overridden to put the Surface on top.</p>
+<p>Whatever you render onto this Surface will be composited by SurfaceFlinger, not
+by the app.  This is the real power of SurfaceView: the Surface you get can be
+rendered by a separate thread or a separate process, isolated from any rendering
+performed by the app UI, and the buffers go directly to SurfaceFlinger.  You
+can't totally ignore the UI thread -- you still have to coordinate with the
+Activity lifecycle, and you may need to adjust something if the size or position
+of the View changes -- but you have a whole Surface all to yourself, and
+blending with the app UI and other layers is handled by the Hardware Composer.</p>
+<p>It's worth taking a moment to note that this new Surface is the producer side of
+a BufferQueue whose consumer is a SurfaceFlinger layer.  You can update the
+Surface with any mechanism that can feed a BufferQueue.  You can: use the
+Surface-supplied Canvas functions, attach an EGLSurface and draw on it
+with GLES, and configure a MediaCodec video decoder to write to it.</p>
+<h3 id="composition">Composition and the Hardware Scaler</h3>
+<p>Now that we have a bit more context, it's useful to go back and look at a couple
+of fields from <code>dumpsys SurfaceFlinger</code> that we skipped over earlier
+on.  Back in the <a href="#hwcomposer">Hardware Composer</a> discussion, we
+looked at some output like this:</p>
+    type    |          source crop              |           frame           name
+        HWC | [    0.0,    0.0,  320.0,  240.0] | [   48,  411, 1032, 1149] SurfaceView
+        HWC | [    0.0,   75.0, 1080.0, 1776.0] | [    0,   75, 1080, 1776]
+        HWC | [    0.0,    0.0, 1080.0,   75.0] | [    0,    0, 1080,   75] StatusBar
+        HWC | [    0.0,    0.0, 1080.0,  144.0] | [    0, 1776, 1080, 1920] NavigationBar
+  FB TARGET | [    0.0,    0.0, 1080.0, 1920.0] | [    0,    0, 1080, 1920] HWC_FRAMEBUFFER_TARGET
+<p>This was taken while playing a movie in Grafika's "Play video (SurfaceView)"
+activity, on a Nexus 5 in portrait orientation.  Note that the list is ordered
+from back to front: the SurfaceView's Surface is in the back, the app UI layer
+sits on top of that, followed by the status and navigation bars that are above
+everything else.  The video is QVGA (320x240).</p>
+<p>The "source crop" indicates the portion of the Surface's buffer that
+SurfaceFlinger is going to display.  The app UI was given a Surface equal to the
+full size of the display (1080x1920), but there's no point rendering and
+compositing pixels that will be obscured by the status and navigation bars, so
+the source is cropped to a rectangle that starts 75 pixels from the top, and
+ends 144 pixels from the bottom.  The status and navigation bars have smaller
+Surfaces, and the source crop describes a rectangle that begins at the the top
+left (0,0) and spans their content.</p>
+<p>The "frame" is the rectangle where the pixels end up on the display.  For the
+app UI layer, the frame matches the source crop, because we're copying (or
+overlaying) a portion of a display-sized layer to the same location in another
+display-sized layer.  For the status and navigation bars, the size of the frame
+rectangle is the same, but the position is adjusted so that the navigation bar
+appears at the bottom of the screen.</p>
+<p>Now consider the layer labeled "SurfaceView", which holds our video content.
+The source crop matches the video size, which SurfaceFlinger knows because the
+MediaCodec decoder (the buffer producer) is dequeuing buffers that size.  The
+frame rectangle has a completely different size -- 984x738.</p>
+<p>SurfaceFlinger handles size differences by scaling the buffer contents to fill
+the frame rectangle, upscaling or downscaling as needed.  This particular size
+was chosen because it has the same aspect ratio as the video (4:3), and is as
+wide as possible given the constraints of the View layout (which includes some
+padding at the edges of the screen for aesthetic reasons).</p>
+<p>If you started playing a different video on the same Surface, the underlying
+BufferQueue would reallocate buffers to the new size automatically, and
+SurfaceFlinger would adjust the source crop.  If the aspect ratio of the new
+video is different, the app would need to force a re-layout of the View to match
+it, which causes the WindowManager to tell SurfaceFlinger to update the frame
+<p>If you're rendering on the Surface through some other means, perhaps GLES, you
+can set the Surface size using the <code>SurfaceHolder#setFixedSize()</code>
+call.  You could, for example, configure a game to always render at 1280x720,
+which would significantly reduce the number of pixels that must be touched to
+fill the screen on a 2560x1440 tablet or 4K television.  The display processor
+handles the scaling.  If you don't want to letter- or pillar-box your game, you
+could adjust the game's aspect ratio by setting the size so that the narrow
+dimension is 720 pixels, but the long dimension is set to maintain the aspect
+ratio of the physical display (e.g. 1152x720 to match a 2560x1600 display).
+You can see an example of this approach in Grafika's "Hardware scaler
+exerciser" activity.</p>
+<h3 id="glsurfaceview">GLSurfaceView</h3>
+<p>The GLSurfaceView class provides some helper classes that help manage EGL
+contexts, inter-thread communication, and interaction with the Activity
+lifecycle.  That's it.  You do not need to use a GLSurfaceView to use GLES.</p>
+<p>For example, GLSurfaceView creates a thread for rendering and configures an EGL
+context there.  The state is cleaned up automatically when the activity pauses.
+Most apps won't need to know anything about EGL to use GLES with GLSurfaceView.</p>
+<p>In most cases, GLSurfaceView is very helpful and can make working with GLES
+easier.  In some situations, it can get in the way.  Use it if it helps, don't
+if it doesn't.</p>
+<h2 id="surfacetexture">SurfaceTexture</h2>
+<p>The SurfaceTexture class is a relative newcomer, added in Android 3.0
+("Honeycomb").  Just as SurfaceView is the combination of a Surface and a View,
+SurfaceTexture is the combination of a Surface and a GLES texture.  Sort of.</p>
+<p>When you create a SurfaceTexture, you are creating a BufferQueue for which your
+app is the consumer.  When a new buffer is queued by the producer, your app is
+notified via callback (<code>onFrameAvailable()</code>).  Your app calls
+<code>updateTexImage()</code>, which releases the previously-held buffer,
+acquires the new buffer from the queue, and makes some EGL calls to make the
+buffer available to GLES as an "external" texture.</p>
+<p>External textures (<code>GL_TEXTURE_EXTERNAL_OES</code>) are not quite the
+same as textures created by GLES (<code>GL_TEXTURE_2D</code>).  You have to
+configure your renderer a bit differently, and there are things you can't do
+with them. But the key point is this: You can render textured polygons directly
+from the data received by your BufferQueue.</p>
+<p>You may be wondering how we can guarantee the format of the data in the
+buffer is something GLES can recognize -- gralloc supports a wide variety
+of formats.  When SurfaceTexture created the BufferQueue, it set the consumer's
+usage flags to <code>GRALLOC_USAGE_HW_TEXTURE</code>, ensuring that any buffer
+created by gralloc would be usable by GLES.</p>
+<p>Because SurfaceTexture interacts with an EGL context, you have to be careful to
+call its methods from the correct thread.  This is spelled out in the class
+<p>If you look deeper into the class documentation, you will see a couple of odd
+calls.  One retrieves a timestamp, the other a transformation matrix, the value
+of each having been set by the previous call to <code>updateTexImage()</code>.
+It turns out that BufferQueue passes more than just a buffer handle to the consumer.
+Each buffer is accompanied by a timestamp and transformation parameters.</p>
+<p>The transformation is provided for efficiency.  In some cases, the source data
+might be in the "wrong" orientation for the consumer; but instead of rotating
+the data before sending it, we can send the data in its current orientation with
+a transform that corrects it.  The transformation matrix can be merged with
+other transformations at the point the data is used, minimizing overhead.</p>
+<p>The timestamp is useful for certain buffer sources.  For example, suppose you
+connect the producer interface to the output of the camera (with
+<code>setPreviewTexture()</code>).  If you want to create a video, you need to
+set the presentation time stamp for each frame; but you want to base that on the time
+when the frame was captured, not the time when the buffer was received by your
+app.  The timestamp provided with the buffer is set by the camera code,
+resulting in a more consistent series of timestamps.</p>
+<h3 id="surfacet">SurfaceTexture and Surface</h3>
+<p>If you look closely at the API you'll see the only way for an application
+to create a plain Surface is through a constructor that takes a SurfaceTexture
+as the sole argument.  (Prior to API 11, there was no public constructor for
+Surface at all.)  This might seem a bit backward if you view SurfaceTexture as a
+combination of a Surface and a texture.</p>
+<p>Under the hood, SurfaceTexture is called GLConsumer, which more accurately
+reflects its role as the owner and consumer of a BufferQueue.  When you create a
+Surface from a SurfaceTexture, what you're doing is creating an object that
+represents the producer side of the SurfaceTexture's BufferQueue.</p>
+<h3 id="continuous-capture">Case Study: Grafika's "Continuous Capture" Activity</h3>
+<p>The camera can provide a stream of frames suitable for recording as a movie.  If
+you want to display it on screen, you create a SurfaceView, pass the Surface to
+<code>setPreviewDisplay()</code>, and let the producer (camera) and consumer
+(SurfaceFlinger) do all the work.  If you want to record the video, you create a
+Surface with MediaCodec's <code>createInputSurface()</code>, pass that to the
+camera, and again you sit back and relax.  If you want to show the video and
+record it at the same time, you have to get more involved.</p>
+<p>The "Continuous capture" activity displays video from the camera as it's being
+recorded.  In this case, encoded video is written to a circular buffer in memory
+that can be saved to disk at any time.  It's straightforward to implement so
+long as you keep track of where everything is.</p>
+<p>There are three BufferQueues involved.  The app uses a SurfaceTexture to receive
+frames from Camera, converting them to an external GLES texture.  The app
+declares a SurfaceView, which we use to display the frames, and we configure a
+MediaCodec encoder with an input Surface to create the video.  So one
+BufferQueue is created by the app, one by SurfaceFlinger, and one by
+<img src="images/continuous_capture_activity.png" alt="Grafika continuous
+capture activity" />
+<p class="img-caption">
+  <strong>Figure 2.</strong>Grafika's continuous capture activity
+<p>In the diagram above, the arrows show the propagation of the data from the
+camera.  BufferQueues are in color (purple producer, cyan consumer).  Note
+“Camera” actually lives in the mediaserver process.</p>
+<p>Encoded H.264 video goes to a circular buffer in RAM in the app process, and is
+written to an MP4 file on disk using the MediaMuxer class when the “capture”
+button is hit.</p>
+<p>All three of the BufferQueues are handled with a single EGL context in the
+app, and the GLES operations are performed on the UI thread.  Doing the
+SurfaceView rendering on the UI thread is generally discouraged, but since we're
+doing simple operations that are handled asynchronously by the GLES driver we
+should be fine.  (If the video encoder locks up and we block trying to dequeue a
+buffer, the app will become unresponsive. But at that point, we're probably
+failing anyway.)  The handling of the encoded data -- managing the circular
+buffer and writing it to disk -- is performed on a separate thread.</p>
+<p>The bulk of the configuration happens in the SurfaceView's <code>surfaceCreated()</code>
+callback.  The EGLContext is created, and EGLSurfaces are created for the
+display and for the video encoder.  When a new frame arrives, we tell
+SurfaceTexture to acquire it and make it available as a GLES texture, then
+render it with GLES commands on each EGLSurface (forwarding the transform and
+timestamp from SurfaceTexture).  The encoder thread pulls the encoded output
+from MediaCodec and stashes it in memory.</p>
+<h2 id="texture">TextureView</h2>
+<p>The TextureView class was
+<a href="">introduced</a>
+in Android 4.0 ("Ice Cream Sandwich").  It's the most complex of the View
+objects discussed here, combining a View with a SurfaceTexture.</p>
+<p>Recall that the SurfaceTexture is a "GL consumer", consuming buffers of graphics
+data and making them available as textures.  TextureView wraps a SurfaceTexture,
+taking over the responsibility of responding to the callbacks and acquiring new
+buffers.  The arrival of new buffers causes TextureView to issue a View
+invalidate request.  When asked to draw, the TextureView uses the contents of
+the most recently received buffer as its data source, rendering wherever and
+however the View state indicates it should.</p>
+<p>You can render on a TextureView with GLES just as you would SurfaceView.  Just
+pass the SurfaceTexture to the EGL window creation call.  However, doing so
+exposes a potential problem.</p>
+<p>In most of what we've looked at, the BufferQueues have passed buffers between
+different processes.  When rendering to a TextureView with GLES, both producer
+and consumer are in the same process, and they might even be handled on a single
+thread.  Suppose we submit several buffers in quick succession from the UI
+thread.  The EGL buffer swap call will need to dequeue a buffer from the
+BufferQueue, and it will stall until one is available.  There won't be any
+available until the consumer acquires one for rendering, but that also happens
+on the UI thread… so we're stuck.</p>
+<p>The solution is to have BufferQueue ensure there is always a buffer
+available to be dequeued, so the buffer swap never stalls.  One way to guarantee
+this is to have BufferQueue discard the contents of the previously-queued buffer
+when a new buffer is queued, and to place restrictions on minimum buffer counts
+and maximum acquired buffer counts.  (If your queue has three buffers, and all
+three buffers are acquired by the consumer, then there's nothing to dequeue and
+the buffer swap call must hang or fail.  So we need to prevent the consumer from
+acquiring more than two buffers at once.)  Dropping buffers is usually
+undesirable, so it's only enabled in specific situations, such as when the
+producer and consumer are in the same process.</p>
+<h3 id="surface-or-texture">SurfaceView or TextureView?</h3>
+SurfaceView and TextureView fill similar roles, but have very different
+implementations.  To decide which is best requires an understanding of the
+<p>Because TextureView is a proper citizen of the View hierarchy, it behaves like
+any other View, and can overlap or be overlapped by other elements.  You can
+perform arbitrary transformations and retrieve the contents as a bitmap with
+simple API calls.</p>
+<p>The main strike against TextureView is the performance of the composition step.
+With SurfaceView, the content is written to a separate layer that SurfaceFlinger
+composites, ideally with an overlay.  With TextureView, the View composition is
+always performed with GLES, and updates to its contents may cause other View
+elements to redraw as well (e.g. if they're positioned on top of the
+TextureView).  After the View rendering completes, the app UI layer must then be
+composited with other layers by SurfaceFlinger, so you're effectively
+compositing every visible pixel twice.  For a full-screen video player, or any
+other application that is effectively just UI elements layered on top of video,
+SurfaceView offers much better performance.</p>
+<p>As noted earlier, DRM-protected video can be presented only on an overlay plane.
+ Video players that support protected content must be implemented with
+<h3 id="grafika">Case Study: Grafika's Play Video (TextureView)</h3>
+<p>Grafika includes a pair of video players, one implemented with TextureView, the
+other with SurfaceView.  The video decoding portion, which just sends frames
+from MediaCodec to a Surface, is the same for both.  The most interesting
+differences between the implementations are the steps required to present the
+correct aspect ratio.</p>
+<p>While SurfaceView requires a custom implementation of FrameLayout, resizing
+SurfaceTexture is a simple matter of configuring a transformation matrix with
+<code>TextureView#setTransform()</code>.  For the former, you're sending new
+window position and size values to SurfaceFlinger through WindowManager; for
+the latter, you're just rendering it differently.</p>
+<p>Otherwise, both implementations follow the same pattern.  Once the Surface has
+been created, playback is enabled.  When "play" is hit, a video decoding thread
+is started, with the Surface as the output target.  After that, the app code
+doesn't have to do anything -- composition and display will either be handled by
+SurfaceFlinger (for the SurfaceView) or by TextureView.</p>
+<h3 id="decode">Case Study: Grafika's Double Decode</h3>
+<p>This activity demonstrates manipulation of the SurfaceTexture inside a
+<p>The basic structure of this activity is a pair of TextureViews that show two
+different videos playing side-by-side.  To simulate the needs of a
+videoconferencing app, we want to keep the MediaCodec decoders alive when the
+activity is paused and resumed for an orientation change.  The trick is that you
+can't change the Surface that a MediaCodec decoder uses without fully
+reconfiguring it, which is a fairly expensive operation; so we want to keep the
+Surface alive.  The Surface is just a handle to the producer interface in the
+SurfaceTexture's BufferQueue, and the SurfaceTexture is managed by the
+TextureView;, so we also need to keep the SurfaceTexture alive.  So how do we deal
+with the TextureView getting torn down?</p>
+<p>It just so happens TextureView provides a <code>setSurfaceTexture()</code> call
+that does exactly what we want.  We obtain references to the SurfaceTextures
+from the TextureViews and save them in a static field.  When the activity is
+shut down, we return "false" from the <code>onSurfaceTextureDestroyed()</code>
+callback to prevent destruction of the SurfaceTexture.  When the activity is
+restarted, we stuff the old SurfaceTexture into the new TextureView.  The
+TextureView class takes care of creating and destroying the EGL contexts.</p>
+<p>Each video decoder is driven from a separate thread.  At first glance it might
+seem like we need EGL contexts local to each thread; but remember the buffers
+with decoded output are actually being sent from mediaserver to our
+BufferQueue consumers (the SurfaceTextures).  The TextureViews take care of the
+rendering for us, and they execute on the UI thread.</p>
+<p>Implementing this activity with SurfaceView would be a bit harder.  We can't
+just create a pair of SurfaceViews and direct the output to them, because the
+Surfaces would be destroyed during an orientation change.  Besides, that would
+add two layers, and limitations on the number of available overlays strongly
+motivate us to keep the number of layers to a minimum.  Instead, we'd want to
+create a pair of SurfaceTextures to receive the output from the video decoders,
+and then perform the rendering in the app, using GLES to render two textured
+quads onto the SurfaceView's Surface.</p>
+<h2 id="notes">Conclusion</h2>
+<p>We hope this page has provided useful insights into the way Android handles
+graphics at the system level.</p>
+<p>Some information and advice on related topics can be found in the appendices
+that follow.</p>
+<h2 id="loops">Appendix A: Game Loops</h2>
+<p>A very popular way to implement a game loop looks like this:</p>
+while (playing) {
+    advance state by one frame
+    render the new frame
+    sleep until it’s time to do the next frame
+<p>There are a few problems with this, the most fundamental being the idea that the
+game can define what a "frame" is.  Different displays will refresh at different
+rates, and that rate may vary over time.  If you generate frames faster than the
+display can show them, you will have to drop one occasionally.  If you generate
+them too slowly, SurfaceFlinger will periodically fail to find a new buffer to
+acquire and will re-show the previous frame.  Both of these situations can
+cause visible glitches.</p>
+<p>What you need to do is match the display's frame rate, and advance game state
+according to how much time has elapsed since the previous frame.  There are two
+ways to go about this: (1) stuff the BufferQueue full and rely on the "swap
+buffers" back-pressure; (2) use Choreographer (API 16+).</p>
+<h3 id="stuffing">Queue Stuffing</h3>
+<p>This is very easy to implement: just swap buffers as fast as you can.  In early
+versions of Android this could actually result in a penalty where
+<code>SurfaceView#lockCanvas()</code> would put you to sleep for 100ms.  Now
+it's paced by the BufferQueue, and the BufferQueue is emptied as quickly as
+SurfaceFlinger is able.</p>
+<p>One example of this approach can be seen in <a
+href="">Android Breakout</a>.  It
+uses GLSurfaceView, which runs in a loop that calls the application's
+onDrawFrame() callback and then swaps the buffer.  If the BufferQueue is full,
+the <code>eglSwapBuffers()</code> call will wait until a buffer is available.
+Buffers become available when SurfaceFlinger releases them, which it does after
+acquiring a new one for display.  Because this happens on VSYNC, your draw loop
+timing will match the refresh rate.  Mostly.</p>
+<p>There are a couple of problems with this approach.  First, the app is tied to
+SurfaceFlinger activity, which is going to take different amounts of time
+depending on how much work there is to do and whether it's fighting for CPU time
+with other processes.  Since your game state advances according to the time
+between buffer swaps, your animation won't update at a consistent rate.  When
+running at 60fps with the inconsistencies averaged out over time, though, you
+probably won't notice the bumps.</p>
+<p>Second, the first couple of buffer swaps are going to happen very quickly
+because the BufferQueue isn't full yet.  The computed time between frames will
+be near zero, so the game will generate a few frames in which nothing happens.
+In a game like Breakout, which updates the screen on every refresh, the queue is
+always full except when a game is first starting (or un-paused), so the effect
+isn't noticeable.  A game that pauses animation occasionally and then returns to
+as-fast-as-possible mode might see odd hiccups.</p>
+<h3 id="choreographer">Choreographer</h3>
+<p>Choreographer allows you to set a callback that fires on the next VSYNC.  The
+actual VSYNC time is passed in as an argument.  So even if your app doesn't wake
+up right away, you still have an accurate picture of when the display refresh
+period began.  Using this value, rather than the current time, yields a
+consistent time source for your game state update logic.</p>
+<p>Unfortunately, the fact that you get a callback after every VSYNC does not
+guarantee that your callback will be executed in a timely fashion or that you
+will be able to act upon it sufficiently swiftly.  Your app will need to detect
+situations where it's falling behind and drop frames manually.</p>
+<p>The "Record GL app" activity in Grafika provides an example of this.  On some
+devices (e.g. Nexus 4 and Nexus 5), the activity will start dropping frames if
+you just sit and watch.  The GL rendering is trivial, but occasionally the View
+elements get redrawn, and the measure/layout pass can take a very long time if
+the device has dropped into a reduced-power mode.  (According to systrace, it
+takes 28ms instead of 6ms after the clocks slow on Android 4.4.  If you drag
+your finger around the screen, it thinks you're interacting with the activity,
+so the clock speeds stay high and you'll never drop a frame.)</p>
+<p>The simple fix was to drop a frame in the Choreographer callback if the current
+time is more than N milliseconds after the VSYNC time.  Ideally the value of N
+is determined based on previously observed VSYNC intervals.  For example, if the
+refresh period is 16.7ms (60fps), you might drop a frame if you're running more
+than 15ms late.</p>
+<p>If you watch "Record GL app" run, you will see the dropped-frame counter
+increase, and even see a flash of red in the border when frames drop.  Unless
+your eyes are very good, though, you won't see the animation stutter.  At 60fps,
+the app can drop the occasional frame without anyone noticing so long as the
+animation continues to advance at a constant rate.  How much you can get away
+with depends to some extent on what you're drawing, the characteristics of the
+display, and how good the person using the app is at detecting jank.</p>
+<h3 id="thread">Thread Management</h3>
+<p>Generally speaking, if you're rendering onto a SurfaceView, GLSurfaceView, or
+TextureView, you want to do that rendering in a dedicated thread.  Never do any
+"heavy lifting" or anything that takes an indeterminate amount of time on the
+UI thread.</p>
+<p>Breakout and "Record GL app" use dedicated renderer threads, and they also
+update animation state on that thread.  This is a reasonable approach so long as
+game state can be updated quickly.</p>
+<p>Other games separate the game logic and rendering completely.  If you had a
+simple game that did nothing but move a block every 100ms, you could have a
+dedicated thread that just did this:</p>
+    run() {
+        Thread.sleep(100);
+        synchronized (mLock) {
+            moveBlock();
+        }
+    }
+<p>(You may want to base the sleep time off of a fixed clock to prevent drift --
+sleep() isn't perfectly consistent, and moveBlock() takes a nonzero amount of
+time -- but you get the idea.)</p>
+<p>When the draw code wakes up, it just grabs the lock, gets the current position
+of the block, releases the lock, and draws.  Instead of doing fractional
+movement based on inter-frame delta times, you just have one thread that moves
+things along and another thread that draws things wherever they happen to be
+when the drawing starts.</p>
+<p>For a scene with any complexity you'd want to create a list of upcoming events
+sorted by wake time, and sleep until the next event is due, but it's the same
+<h2 id="activity">Appendix B: SurfaceView and the Activity Lifecycle</h2>
+<p>When using a SurfaceView, it's considered good practice to render the Surface
+from a thread other than the main UI thread.  This raises some questions about
+the interaction between that thread and the Activity lifecycle.</p>
+<p>First, a little background.  For an Activity with a SurfaceView, there are two
+separate but interdependent state machines:</p>
+<li>Application onCreate / onResume / onPause</li>
+<li>Surface created / changed / destroyed</li>
+<p>When the Activity starts, you get callbacks in this order:</p>
+<p>If you hit "back" you get:</p>
+<li>surfaceDestroyed (called just before the Surface goes away)</li>
+<p>If you rotate the screen, the Activity is torn down and recreated, so you
+get the full cycle.  If it matters, you can tell that it's a "quick" restart by
+checking <code>isFinishing()</code>.  (It might be possible to start / stop an
+Activity so quickly that surfaceCreated() might actually happen after onPause().)</p>
+<p>If you tap the power button to blank the screen, you only get
+<code>onPause()</code> -- no <code>surfaceDestroyed()</code>.  The Surface
+remains alive, and rendering can continue.  You can even keep getting
+Choreographer events if you continue to request them.  If you have a lock
+screen that forces a different orientation, your Activity may be restarted when
+the device is unblanked; but if not, you can come out of screen-blank with the
+same Surface you had before.</p>
+<p>This raises a fundamental question when using a separate renderer thread with
+SurfaceView: Should the lifespan of the thread be tied to that of the Surface or
+the Activity?  The answer depends on what you want to have happen when the
+screen goes blank. There are two basic approaches: (1) start/stop the thread on
+Activity start/stop; (2) start/stop the thread on Surface create/destroy.</p>
+<p>#1 interacts well with the app lifecycle. We start the renderer thread in
+<code>onResume()</code> and stop it in <code>onPause()</code>. It gets a bit
+awkward when creating and configuring the thread because sometimes the Surface
+will already exist and sometimes it won't (e.g. it's still alive after toggling
+the screen with the power button).  We have to wait for the surface to be
+created before we do some initialization in the thread, but we can't simply do
+it in the <code>surfaceCreated()</code> callback because that won't fire again
+if the Surface didn't get recreated.  So we need to query or cache the Surface
+state, and forward it to the renderer thread. Note we have to be a little
+careful here passing objects between threads -- it is best to pass the Surface or
+SurfaceHolder through a Handler message, rather than just stuffing it into the
+thread, to avoid issues on multi-core systems (cf. the <a
+href="">Android SMP
+<p>#2 has a certain appeal because the Surface and the renderer are logically
+intertwined. We start the thread after the Surface has been created, which
+avoids some inter-thread communication concerns.  Surface created / changed
+messages are simply forwarded.  We need to make sure rendering stops when the
+screen goes blank, and resumes when it un-blanks; this could be a simple matter
+of telling Choreographer to stop invoking the frame draw callback.  Our
+<code>onResume()</code> will need to resume the callbacks if and only if the
+renderer thread is running.  It may not be so trivial though -- if we animate
+based on elapsed time between frames, we could have a very large gap when the
+next event arrives; so an explicit pause/resume message may be desirable.</p>
+<p>The above is primarily concerned with how the renderer thread is configured and
+whether it's executing. A related concern is extracting state from the thread
+when the Activity is killed (in <code>onPause()</code> or <code>onSaveInstanceState()</code>).
+Approach #1 will work best for that, because once the renderer thread has been
+joined its state can be accessed without synchronization primitives.</p>
+<p>You can see an example of approach #2 in Grafika's "Hardware scaler exerciser."</p>
+<h2 id="tracking">Appendix C: Tracking BufferQueue with systrace</h2>
+<p>If you really want to understand how graphics buffers move around, you need to
+use systrace.  The system-level graphics code is well instrumented, as is much
+of the relevant app framework code.  Enable the "gfx" and "view" tags, and
+generally "sched" as well.</p>
+<p>A full description of how to use systrace effectively would fill a rather long
+document.  One noteworthy item is the presence of BufferQueues in the trace.  If
+you've used systrace before, you've probably seen them, but maybe weren't sure
+what they were.  As an example, if you grab a trace while Grafika's "Play video
+(SurfaceView)" is running, you will see a row labeled: "SurfaceView"  This row
+tells you how many buffers were queued up at any given time.</p>
+<p>You'll notice the value increments while the app is active -- triggering
+the rendering of frames by the MediaCodec decoder -- and decrements while
+SurfaceFlinger is doing work, consuming buffers.  If you're showing video at
+30fps, the queue's value will vary from 0 to 1, because the ~60fps display can
+easily keep up with the source.  (You'll also notice that SurfaceFlinger is only
+waking up when there's work to be done, not 60 times per second.  The system tries
+very hard to avoid work and will disable VSYNC entirely if nothing is updating
+the screen.)</p>
+<p>If you switch to "Play video (TextureView)" and grab a new trace, you'll see a
+row with a much longer name
+("").  This is the
+main UI layer, which is of course just another BufferQueue.  Because TextureView
+renders into the UI layer, rather than a separate layer, you'll see all of the
+video-driven updates here.</p>
+<p>For more information about systrace, see the <a
+documentation</a> for the tool.</p>
diff --git a/src/devices/graphics/images/continuous_capture_activity.png b/src/devices/graphics/images/continuous_capture_activity.png
new file mode 100644
index 0000000..24ba1d5
--- /dev/null
+++ b/src/devices/graphics/images/continuous_capture_activity.png
Binary files differ
diff --git a/src/devices/graphics/images/surfaceflinger_bufferqueue.png b/src/devices/graphics/images/surfaceflinger_bufferqueue.png
new file mode 100644
index 0000000..0fc1414
--- /dev/null
+++ b/src/devices/graphics/images/surfaceflinger_bufferqueue.png
Binary files differ