blob: 47cc9cca8cacab7d3681e06ae26821eab7fbf058 [file] [log] [blame]
Clay Murphye3ae3962014-09-02 17:30:57 -07001page.title=Graphics architecture
Clay Murphyccf30372014-04-07 16:13:19 -07002@jd:body
3
4<!--
5 Copyright 2014 The Android Open Source Project
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18-->
19<div id="qv-wrapper">
20 <div id="qv">
21 <h2>In this document</h2>
22 <ol id="auto-toc">
23 </ol>
24 </div>
25</div>
26
27
28<p><em>What every developer should know about Surface, SurfaceHolder, EGLSurface,
29SurfaceView, GLSurfaceView, SurfaceTexture, TextureView, and SurfaceFlinger</em>
30</p>
Heidi von Markham2684c462016-06-24 13:46:53 -070031<p>This page describes the essential elements of system-level graphics
32architecture in Android N and how it is used by the application framework and
33multimedia system. The focus is on how buffers of graphical data move through
34the system. If you've ever wondered why SurfaceView and TextureView behave the
35way they do, or how Surface and EGLSurface interact, you are in the correct
Clay Murphyccf30372014-04-07 16:13:19 -070036place.</p>
37
38<p>Some familiarity with Android devices and application development is assumed.
Heidi von Markham2684c462016-06-24 13:46:53 -070039You don't need detailed knowledge of the app framework and very few API calls
40are mentioned, but the material doesn't overlap with other public
41documentation. The goal here is to provide details on the significant events
42involved in rendering a frame for output to help you make informed choices
43when designing an application. To achieve this, we work from the bottom up,
44describing how the UI classes work rather than how they can be used.</p>
Clay Murphyccf30372014-04-07 16:13:19 -070045
46<p>Early sections contain background material used in later sections, so it's a
47good idea to read straight through rather than skipping to a section that sounds
Heidi von Markham2684c462016-06-24 13:46:53 -070048interesting. We start with an explanation of Android's graphics buffers,
Clay Murphyccf30372014-04-07 16:13:19 -070049describe the composition and display mechanism, and then proceed to the
50higher-level mechanisms that supply the compositor with data.</p>
51
Heidi von Markham2684c462016-06-24 13:46:53 -070052<p class="note">This page includes references to AOSP source code and
53<a href="https://github.com/google/grafika">Grafika</a>, a Google open source
54project for testing.</p>
Clay Murphyccf30372014-04-07 16:13:19 -070055
Clay Murphyccf30372014-04-07 16:13:19 -070056<h2 id="BufferQueue">BufferQueue and gralloc</h2>
57
Heidi von Markham2684c462016-06-24 13:46:53 -070058<p>To understand how Android's graphics system works, we must start behind the
59scenes. At the heart of everything graphical in Android is a class called
60BufferQueue. Its role is simple: connect something that generates buffers of
61graphical data (the <em>producer</em>) to something that accepts the data for
62display or further processing (the <em>consumer</em>). The producer and consumer
63can live in different processes. Nearly everything that moves buffers of
Clay Murphyccf30372014-04-07 16:13:19 -070064graphical data through the system relies on BufferQueue.</p>
65
Heidi von Markham2684c462016-06-24 13:46:53 -070066<p>Basic usage is straightforward: The producer requests a free buffer
67(<code>dequeueBuffer()</code>), specifying a set of characteristics including
68width, height, pixel format, and usage flags. The producer populates the buffer
69and returns it to the queue (<code>queueBuffer()</code>). Some time later, the
70consumer acquires the buffer (<code>acquireBuffer()</code>) and makes use of the
71buffer contents. When the consumer is done, it returns the buffer to the queue
Clay Murphyccf30372014-04-07 16:13:19 -070072(<code>releaseBuffer()</code>).</p>
73
Heidi von Markham2684c462016-06-24 13:46:53 -070074<p>Recent Android devices support the <em>sync framework</em>, which enables the
75system to do nifty things when combined with hardware components that can
76manipulate graphics data asynchronously. For example, a producer can submit a
Clay Murphyccf30372014-04-07 16:13:19 -070077series of OpenGL ES drawing commands and then enqueue the output buffer before
Heidi von Markham2684c462016-06-24 13:46:53 -070078rendering completes. The buffer is accompanied by a fence that signals when the
79contents are ready. A second fence accompanies the buffer when it is returned
80to the free list, so the consumer can release the buffer while the contents are
81still in use. This approach improves latency and throughput as the buffers
Clay Murphyccf30372014-04-07 16:13:19 -070082move through the system.</p>
83
Heidi von Markham2684c462016-06-24 13:46:53 -070084<p>Some characteristics of the queue, such as the maximum number of buffers it
85can hold, are determined jointly by the producer and the consumer.</p>
Clay Murphyccf30372014-04-07 16:13:19 -070086
Heidi von Markham2684c462016-06-24 13:46:53 -070087<p>The BufferQueue is responsible for allocating buffers as it needs them.
88Buffers are retained unless the characteristics change; for example, if the
89producer requests buffers with a different size, old buffers are freed and new
90buffers are allocated on demand.</p>
Clay Murphyccf30372014-04-07 16:13:19 -070091
Heidi von Markham2684c462016-06-24 13:46:53 -070092<p>Currently, the consumer always creates and owns the data structure. In
93Android 4.3, only the producer side was binderized (i.e. producer could be
94in a remote process but consumer had to live in the process where the queue
95was created). Android 4.4 and later releases moved toward a more general
Clay Murphyccf30372014-04-07 16:13:19 -070096implementation.</p>
97
Heidi von Markham2684c462016-06-24 13:46:53 -070098<p>Buffer contents are never copied by BufferQueue (moving that much data around
99would be very inefficient). Instead, buffers are always passed by handle.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700100
101<h3 id="gralloc_HAL">gralloc HAL</h3>
102
Heidi von Markham2684c462016-06-24 13:46:53 -0700103<p>Buffer allocations are performed through the <em>gralloc</em> memory
104allocator, which is implemented through a vendor-specific HAL interface (for
105details, refer to <code>hardware/libhardware/include/hardware/gralloc.h</code>).
106The <code>alloc()</code> function takes expected arguments (width, height, pixel
107format) as well as a set of usage flags that merit closer attention.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700108
Heidi von Markham2684c462016-06-24 13:46:53 -0700109<p>The gralloc allocator is not just another way to allocate memory on the
110native heap; in some situations, the allocated memory may not be cache-coherent
111or could be totally inaccessible from user space. The nature of the allocation
112is determined by the usage flags, which include attributes such as:</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700113
114<ul>
Heidi von Markham2684c462016-06-24 13:46:53 -0700115<li>How often the memory will be accessed from software (CPU)</li>
116<li>How often the memory will be accessed from hardware (GPU)</li>
117<li>Whether the memory will be used as an OpenGL ES (GLES) texture</li>
118<li>Whether the memory will be used by a video encoder</li>
Clay Murphyccf30372014-04-07 16:13:19 -0700119</ul>
120
Heidi von Markham2684c462016-06-24 13:46:53 -0700121<p>For example, if your format specifies RGBA 8888 pixels, and you indicate the
122buffer will be accessed from software (meaning your application will touch
123pixels directly) then the allocator must create a buffer with 4 bytes per pixel
124in R-G-B-A order. If instead you say the buffer will be only accessed from
125hardware and as a GLES texture, the allocator can do anything the GLES driver
126wants&mdash;BGRA ordering, non-linear swizzled layouts, alternative color
127formats, etc. Allowing the hardware to use its preferred format can improve
128performance.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700129
Heidi von Markham2684c462016-06-24 13:46:53 -0700130<p>Some values cannot be combined on certain platforms. For example, the video
131encoder flag may require YUV pixels, so adding software access and specifying
Clay Murphyccf30372014-04-07 16:13:19 -0700132RGBA 8888 would fail.</p>
133
134<p>The handle returned by the gralloc allocator can be passed between processes
135through Binder.</p>
136
137<h2 id="SurfaceFlinger">SurfaceFlinger and Hardware Composer</h2>
138
Heidi von Markham2684c462016-06-24 13:46:53 -0700139<p>Having buffers of graphical data is wonderful, but life is even better when
140you get to see them on your device's screen. That's where SurfaceFlinger and the
Clay Murphyccf30372014-04-07 16:13:19 -0700141Hardware Composer HAL come in.</p>
142
143<p>SurfaceFlinger's role is to accept buffers of data from multiple sources,
Heidi von Markham2684c462016-06-24 13:46:53 -0700144composite them, and send them to the display. Once upon a time this was done
Clay Murphyccf30372014-04-07 16:13:19 -0700145with software blitting to a hardware framebuffer (e.g.
146<code>/dev/graphics/fb0</code>), but those days are long gone.</p>
147
148<p>When an app comes to the foreground, the WindowManager service asks
Heidi von Markham2684c462016-06-24 13:46:53 -0700149SurfaceFlinger for a drawing surface. SurfaceFlinger creates a layer (the
150primary component of which is a BufferQueue) for which SurfaceFlinger acts as
151the consumer. A Binder object for the producer side is passed through the
Clay Murphyccf30372014-04-07 16:13:19 -0700152WindowManager to the app, which can then start sending frames directly to
Bert McMeen3bb4b8f2015-05-06 17:21:27 -0700153SurfaceFlinger.</p>
154
Heidi von Markham2684c462016-06-24 13:46:53 -0700155<p class="note"><strong>Note:</strong> While this section uses SurfaceFlinger
156terminology, WindowManager uses the term <em>window</em> instead of
157<em>layer</em>&hellip;and uses layer to mean something else. (It can be argued
158that SurfaceFlinger should really be called LayerFlinger.)</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700159
Heidi von Markham2684c462016-06-24 13:46:53 -0700160<p>Most applications have three layers on screen at any time: the status bar at
161the top of the screen, the navigation bar at the bottom or side, and the
162application UI. Some apps have more, some less (e.g. the default home app has a
Clay Murphyccf30372014-04-07 16:13:19 -0700163separate layer for the wallpaper, while a full-screen game might hide the status
Heidi von Markham2684c462016-06-24 13:46:53 -0700164bar. Each layer can be updated independently. The status and navigation bars
Clay Murphyccf30372014-04-07 16:13:19 -0700165are rendered by a system process, while the app layers are rendered by the app,
166with no coordination between the two.</p>
167
168<p>Device displays refresh at a certain rate, typically 60 frames per second on
Heidi von Markham2684c462016-06-24 13:46:53 -0700169phones and tablets. If the display contents are updated mid-refresh, tearing
Clay Murphyccf30372014-04-07 16:13:19 -0700170will be visible; so it's important to update the contents only between cycles.
171The system receives a signal from the display when it's safe to update the
Heidi von Markham2684c462016-06-24 13:46:53 -0700172contents. For historical reasons we'll call this the VSYNC signal.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700173
174<p>The refresh rate may vary over time, e.g. some mobile devices will range from 58
Heidi von Markham2684c462016-06-24 13:46:53 -0700175to 62fps depending on current conditions. For an HDMI-attached television, this
176could theoretically dip to 24 or 48Hz to match a video. Because we can update
177the screen only once per refresh cycle, submitting buffers for display at 200fps
178would be a waste of effort as most of the frames would never be seen. Instead of
179taking action whenever an app submits a buffer, SurfaceFlinger wakes up when the
180display is ready for something new.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700181
Heidi von Markham2684c462016-06-24 13:46:53 -0700182<p>When the VSYNC signal arrives, SurfaceFlinger walks through its list of
183layers looking for new buffers. If it finds a new one, it acquires it; if not,
184it continues to use the previously-acquired buffer. SurfaceFlinger always wants
185to have something to display, so it will hang on to one buffer. If no buffers
186have ever been submitted on a layer, the layer is ignored.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700187
Heidi von Markham2684c462016-06-24 13:46:53 -0700188<p>After SurfaceFlinger has collected all buffers for visible layers, it asks
189the Hardware Composer how composition should be performed.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700190
191<h3 id="hwcomposer">Hardware Composer</h3>
192
Heidi von Markham2684c462016-06-24 13:46:53 -0700193<p>The Hardware Composer HAL (HWC) was introduced in Android 3.0 and has evolved
194steadily over the years. Its primary purpose is to determine the most efficient
195way to composite buffers with the available hardware. As a HAL, its
196implementation is device-specific and usually done by the display hardware OEM.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700197
Heidi von Markham2684c462016-06-24 13:46:53 -0700198<p>The value of this approach is easy to recognize when you consider <em>overlay
199planes</em>, the purpose of which is to composite multiple buffers together in
200the display hardware rather than the GPU. For example, consider a typical
201Android phone in portrait orientation, with the status bar on top, navigation
202bar at the bottom, and app content everywhere else. The contents for each layer
203are in separate buffers. You could handle composition using either of the
204following methods:</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700205
Heidi von Markham2684c462016-06-24 13:46:53 -0700206<ul>
207<li>Rendering the app content into a scratch buffer, then rendering the status
208bar over it, the navigation bar on top of that, and finally passing the scratch
209buffer to the display hardware.</li>
210<li>Passing all three buffers to the display hardware and tell it to read data
211from different buffers for different parts of the screen.</li>
212</ul>
213
214<p>The latter approach can be significantly more efficient.</p>
215
216<p>Display processor capabilities vary significantly. The number of overlays,
217whether layers can be rotated or blended, and restrictions on positioning and
218overlap can be difficult to express through an API. The HWC attempts to
219accommodate such diversity through a series of decisions:</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700220
221<ol>
Heidi von Markham2684c462016-06-24 13:46:53 -0700222<li>SurfaceFlinger provides HWC with a full list of layers and asks, "How do
Clay Murphyccf30372014-04-07 16:13:19 -0700223you want to handle this?"</li>
Heidi von Markham2684c462016-06-24 13:46:53 -0700224<li>HWC responds by marking each layer as overlay or GLES composition.</li>
Clay Murphyccf30372014-04-07 16:13:19 -0700225<li>SurfaceFlinger takes care of any GLES composition, passing the output buffer
226to HWC, and lets HWC handle the rest.</li>
227</ol>
228
Heidi von Markhamfd022c72016-06-30 10:15:28 -0700229<p>Since hardware vendors can custom tailor decision-making code, it's possible
230to get the best performance out of every device.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700231
232<p>Overlay planes may be less efficient than GL composition when nothing on the
Heidi von Markham2684c462016-06-24 13:46:53 -0700233screen is changing. This is particularly true when overlay contents have
234transparent pixels and overlapping layers are blended together. In such cases,
235the HWC can choose to request GLES composition for some or all layers and retain
236the composited buffer. If SurfaceFlinger comes back asking to composite the same
237set of buffers, the HWC can continue to show the previously-composited scratch
238buffer. This can improve the battery life of an idle device.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700239
Heidi von Markham2684c462016-06-24 13:46:53 -0700240<p>Devices running Android 4.4 and later typically support four overlay planes.
241Attempting to composite more layers than overlays causes the system to use GLES
242composition for some of them, meaning the number of layers used by an app can
243have a measurable impact on power consumption and performance.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700244
Clay Murphyccf30372014-04-07 16:13:19 -0700245<h3 id="virtual-displays">Virtual Displays</h3>
246
Heidi von Markhamfd022c72016-06-30 10:15:28 -0700247<p>SurfaceFlinger supports a primary display, i.e. what's built into your phone
248or tablet, and an external display, such as a television connected through
249HDMI. It also supports a number of virtual displays that can make composited
250output available within the system. Virtual displays can be used to record the
Clay Murphyccf30372014-04-07 16:13:19 -0700251screen or send it over a network.</p>
252
253<p>Virtual displays may share the same set of layers as the main display
Heidi von Markhamfd022c72016-06-30 10:15:28 -0700254(the layer stack) or have its own set. There is no VSYNC for a virtual
Clay Murphyccf30372014-04-07 16:13:19 -0700255display, so the VSYNC for the primary display is used to trigger composition for
256all displays.</p>
257
Heidi von Markhamfd022c72016-06-30 10:15:28 -0700258<p>In the past, virtual displays were always composited with GLES; the Hardware
259Composer managed composition for only the primary display. In Android 4.4, the
Clay Murphyccf30372014-04-07 16:13:19 -0700260Hardware Composer gained the ability to participate in virtual display
261composition.</p>
262
Heidi von Markhamfd022c72016-06-30 10:15:28 -0700263<p>As you might expect, the frames generated for a virtual display are written
264to a BufferQueue.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700265
266<h3 id="screenrecord">Case study: screenrecord</h3>
267
268<p>Now that we've established some background on BufferQueue and SurfaceFlinger,
269it's useful to examine a practical use case.</p>
270
271<p>The <a href="https://android.googlesource.com/platform/frameworks/av/+/kitkat-release/cmds/screenrecord/">screenrecord
272command</a>,
273introduced in Android 4.4, allows you to record everything that appears on the
274screen as an .mp4 file on disk. To implement this, we have to receive composited
275frames from SurfaceFlinger, write them to the video encoder, and then write the
276encoded video data to a file. The video codecs are managed by a separate
277process - called "mediaserver" - so we have to move large graphics buffers around
278the system. To make it more challenging, we're trying to record 60fps video at
279full resolution. The key to making this work efficiently is BufferQueue.</p>
280
281<p>The MediaCodec class allows an app to provide data as raw bytes in buffers, or
282through a Surface. We'll discuss Surface in more detail later, but for now just
283think of it as a wrapper around the producer end of a BufferQueue. When
284screenrecord requests access to a video encoder, mediaserver creates a
285BufferQueue and connects itself to the consumer side, and then passes the
286producer side back to screenrecord as a Surface.</p>
287
288<p>The screenrecord command then asks SurfaceFlinger to create a virtual display
289that mirrors the main display (i.e. it has all of the same layers), and directs
290it to send output to the Surface that came from mediaserver. Note that, in this
291case, SurfaceFlinger is the producer of buffers rather than the consumer.</p>
292
293<p>Once the configuration is complete, screenrecord can just sit and wait for
294encoded data to appear. As apps draw, their buffers travel to SurfaceFlinger,
295which composites them into a single buffer that gets sent directly to the video
296encoder in mediaserver. The full frames are never even seen by the screenrecord
297process. Internally, mediaserver has its own way of moving buffers around that
298also passes data by handle, minimizing overhead.</p>
299
300<h3 id="simulate-secondary">Case study: Simulate Secondary Displays</h3>
301
302<p>The WindowManager can ask SurfaceFlinger to create a visible layer for which
303SurfaceFlinger will act as the BufferQueue consumer. It's also possible to ask
304SurfaceFlinger to create a virtual display, for which SurfaceFlinger will act as
305the BufferQueue producer. What happens if you connect them, configuring a
306virtual display that renders to a visible layer?</p>
307
308<p>You create a closed loop, where the composited screen appears in a window. Of
309course, that window is now part of the composited output, so on the next refresh
310the composited image inside the window will show the window contents as well.
311It's turtles all the way down. You can see this in action by enabling
312"<a href="http://developer.android.com/tools/index.html">Developer options</a>" in
313settings, selecting "Simulate secondary displays", and enabling a window. For
314bonus points, use screenrecord to capture the act of enabling the display, then
315play it back frame-by-frame.</p>
316
317<h2 id="surface">Surface and SurfaceHolder</h2>
318
319<p>The <a
320href="http://developer.android.com/reference/android/view/Surface.html">Surface</a>
321class has been part of the public API since 1.0. Its description simply says,
322"Handle onto a raw buffer that is being managed by the screen compositor." The
323statement was accurate when initially written but falls well short of the mark
324on a modern system.</p>
325
326<p>The Surface represents the producer side of a buffer queue that is often (but
327not always!) consumed by SurfaceFlinger. When you render onto a Surface, the
328result ends up in a buffer that gets shipped to the consumer. A Surface is not
329simply a raw chunk of memory you can scribble on.</p>
330
331<p>The BufferQueue for a display Surface is typically configured for
332triple-buffering; but buffers are allocated on demand. So if the producer
333generates buffers slowly enough -- maybe it's animating at 30fps on a 60fps
334display -- there might only be two allocated buffers in the queue. This helps
335minimize memory consumption. You can see a summary of the buffers associated
336with every layer in the <code>dumpsys SurfaceFlinger</code> output.</p>
337
338<h3 id="canvas">Canvas Rendering</h3>
339
340<p>Once upon a time, all rendering was done in software, and you can still do this
341today. The low-level implementation is provided by the Skia graphics library.
342If you want to draw a rectangle, you make a library call, and it sets bytes in a
343buffer appropriately. To ensure that a buffer isn't updated by two clients at
344once, or written to while being displayed, you have to lock the buffer to access
345it. <code>lockCanvas()</code> locks the buffer and returns a Canvas to use for drawing,
346and <code>unlockCanvasAndPost()</code> unlocks the buffer and sends it to the compositor.</p>
347
348<p>As time went on, and devices with general-purpose 3D engines appeared, Android
349reoriented itself around OpenGL ES. However, it was important to keep the old
350API working, for apps as well as app framework code, so an effort was made to
351hardware-accelerate the Canvas API. As you can see from the charts on the
352<a href="http://developer.android.com/guide/topics/graphics/hardware-accel.html">Hardware
353Acceleration</a>
354page, this was a bit of a bumpy ride. Note in particular that while the Canvas
355provided to a View's <code>onDraw()</code> method may be hardware-accelerated, the Canvas
356obtained when an app locks a Surface directly with <code>lockCanvas()</code> never is.</p>
357
358<p>When you lock a Surface for Canvas access, the "CPU renderer" connects to the
359producer side of the BufferQueue and does not disconnect until the Surface is
360destroyed. Most other producers (like GLES) can be disconnected and reconnected
361to a Surface, but the Canvas-based "CPU renderer" cannot. This means you can't
362draw on a surface with GLES or send it frames from a video decoder if you've
363ever locked it for a Canvas.</p>
364
365<p>The first time the producer requests a buffer from a BufferQueue, it is
366allocated and initialized to zeroes. Initialization is necessary to avoid
367inadvertently sharing data between processes. When you re-use a buffer,
368however, the previous contents will still be present. If you repeatedly call
369<code>lockCanvas()</code> and <code>unlockCanvasAndPost()</code> without
370drawing anything, you'll cycle between previously-rendered frames.</p>
371
372<p>The Surface lock/unlock code keeps a reference to the previously-rendered
373buffer. If you specify a dirty region when locking the Surface, it will copy
374the non-dirty pixels from the previous buffer. There's a fair chance the buffer
375will be handled by SurfaceFlinger or HWC; but since we need to only read from
376it, there's no need to wait for exclusive access.</p>
377
378<p>The main non-Canvas way for an application to draw directly on a Surface is
379through OpenGL ES. That's described in the <a href="#eglsurface">EGLSurface and
380OpenGL ES</a> section.</p>
381
382<h3 id="surfaceholder">SurfaceHolder</h3>
383
384<p>Some things that work with Surfaces want a SurfaceHolder, notably SurfaceView.
385The original idea was that Surface represented the raw compositor-managed
386buffer, while SurfaceHolder was managed by the app and kept track of
387higher-level information like the dimensions and format. The Java-language
388definition mirrors the underlying native implementation. It's arguably no
389longer useful to split it this way, but it has long been part of the public API.</p>
390
391<p>Generally speaking, anything having to do with a View will involve a
392SurfaceHolder. Some other APIs, such as MediaCodec, will operate on the Surface
393itself. You can easily get the Surface from the SurfaceHolder, so hang on to
394the latter when you have it.</p>
395
396<p>APIs to get and set Surface parameters, such as the size and format, are
397implemented through SurfaceHolder.</p>
398
399<h2 id="eglsurface">EGLSurface and OpenGL ES</h2>
400
401<p>OpenGL ES defines an API for rendering graphics. It does not define a windowing
402system. To allow GLES to work on a variety of platforms, it is designed to be
403combined with a library that knows how to create and access windows through the
404operating system. The library used for Android is called EGL. If you want to
405draw textured polygons, you use GLES calls; if you want to put your rendering on
406the screen, you use EGL calls.</p>
407
408<p>Before you can do anything with GLES, you need to create a GL context. In EGL,
409this means creating an EGLContext and an EGLSurface. GLES operations apply to
410the current context, which is accessed through thread-local storage rather than
411passed around as an argument. This means you have to be careful about which
412thread your rendering code executes on, and which context is current on that
413thread.</p>
414
415<p>The EGLSurface can be an off-screen buffer allocated by EGL (called a "pbuffer")
416or a window allocated by the operating system. EGL window surfaces are created
417with the <code>eglCreateWindowSurface()</code> call. It takes a "window object" as an
418argument, which on Android can be a SurfaceView, a SurfaceTexture, a
419SurfaceHolder, or a Surface -- all of which have a BufferQueue underneath. When
420you make this call, EGL creates a new EGLSurface object, and connects it to the
421producer interface of the window object's BufferQueue. From that point onward,
422rendering to that EGLSurface results in a buffer being dequeued, rendered into,
423and queued for use by the consumer. (The term "window" is indicative of the
424expected use, but bear in mind the output might not be destined to appear
425on the display.)</p>
426
427<p>EGL does not provide lock/unlock calls. Instead, you issue drawing commands and
428then call <code>eglSwapBuffers()</code> to submit the current frame. The
429method name comes from the traditional swap of front and back buffers, but the actual
430implementation may be very different.</p>
431
432<p>Only one EGLSurface can be associated with a Surface at a time -- you can have
433only one producer connected to a BufferQueue -- but if you destroy the
434EGLSurface it will disconnect from the BufferQueue and allow something else to
435connect.</p>
436
437<p>A given thread can switch between multiple EGLSurfaces by changing what's
438"current." An EGLSurface must be current on only one thread at a time.</p>
439
440<p>The most common mistake when thinking about EGLSurface is assuming that it is
441just another aspect of Surface (like SurfaceHolder). It's a related but
442independent concept. You can draw on an EGLSurface that isn't backed by a
443Surface, and you can use a Surface without EGL. EGLSurface just gives GLES a
444place to draw.</p>
445
446<h3 id="anativewindow">ANativeWindow</h3>
447
448<p>The public Surface class is implemented in the Java programming language. The
449equivalent in C/C++ is the ANativeWindow class, semi-exposed by the <a
450href="https://developer.android.com/tools/sdk/ndk/index.html">Android NDK</a>. You
451can get the ANativeWindow from a Surface with the <code>ANativeWindow_fromSurface()</code>
452call. Just like its Java-language cousin, you can lock it, render in software,
453and unlock-and-post.</p>
454
455<p>To create an EGL window surface from native code, you pass an instance of
456EGLNativeWindowType to <code>eglCreateWindowSurface()</code>. EGLNativeWindowType is just
457a synonym for ANativeWindow, so you can freely cast one to the other.</p>
458
459<p>The fact that the basic "native window" type just wraps the producer side of a
460BufferQueue should not come as a surprise.</p>
461
462<h2 id="surfaceview">SurfaceView and GLSurfaceView</h2>
463
464<p>Now that we've explored the lower-level components, it's time to see how they
465fit into the higher-level components that apps are built from.</p>
466
467<p>The Android app framework UI is based on a hierarchy of objects that start with
468View. Most of the details don't matter for this discussion, but it's helpful to
469understand that UI elements go through a complicated measurement and layout
470process that fits them into a rectangular area. All visible View objects are
471rendered to a SurfaceFlinger-created Surface that was set up by the
472WindowManager when the app was brought to the foreground. The layout and
473rendering is performed on the app's UI thread.</p>
474
475<p>Regardless of how many Layouts and Views you have, everything gets rendered into
476a single buffer. This is true whether or not the Views are hardware-accelerated.</p>
477
478<p>A SurfaceView takes the same sorts of parameters as other views, so you can give
479it a position and size, and fit other elements around it. When it comes time to
480render, however, the contents are completely transparent. The View part of a
481SurfaceView is just a see-through placeholder.</p>
482
483<p>When the SurfaceView's View component is about to become visible, the framework
484asks the WindowManager to ask SurfaceFlinger to create a new Surface. (This
485doesn't happen synchronously, which is why you should provide a callback that
486notifies you when the Surface creation finishes.) By default, the new Surface
487is placed behind the app UI Surface, but the default "Z-ordering" can be
488overridden to put the Surface on top.</p>
489
490<p>Whatever you render onto this Surface will be composited by SurfaceFlinger, not
491by the app. This is the real power of SurfaceView: the Surface you get can be
492rendered by a separate thread or a separate process, isolated from any rendering
493performed by the app UI, and the buffers go directly to SurfaceFlinger. You
494can't totally ignore the UI thread -- you still have to coordinate with the
495Activity lifecycle, and you may need to adjust something if the size or position
496of the View changes -- but you have a whole Surface all to yourself, and
497blending with the app UI and other layers is handled by the Hardware Composer.</p>
498
499<p>It's worth taking a moment to note that this new Surface is the producer side of
500a BufferQueue whose consumer is a SurfaceFlinger layer. You can update the
501Surface with any mechanism that can feed a BufferQueue. You can: use the
502Surface-supplied Canvas functions, attach an EGLSurface and draw on it
503with GLES, and configure a MediaCodec video decoder to write to it.</p>
504
505<h3 id="composition">Composition and the Hardware Scaler</h3>
506
507<p>Now that we have a bit more context, it's useful to go back and look at a couple
508of fields from <code>dumpsys SurfaceFlinger</code> that we skipped over earlier
509on. Back in the <a href="#hwcomposer">Hardware Composer</a> discussion, we
510looked at some output like this:</p>
511
512<pre>
513 type | source crop | frame name
514------------+-----------------------------------+--------------------------------
515 HWC | [ 0.0, 0.0, 320.0, 240.0] | [ 48, 411, 1032, 1149] SurfaceView
516 HWC | [ 0.0, 75.0, 1080.0, 1776.0] | [ 0, 75, 1080, 1776] com.android.grafika/com.android.grafika.PlayMovieSurfaceActivity
517 HWC | [ 0.0, 0.0, 1080.0, 75.0] | [ 0, 0, 1080, 75] StatusBar
518 HWC | [ 0.0, 0.0, 1080.0, 144.0] | [ 0, 1776, 1080, 1920] NavigationBar
519 FB TARGET | [ 0.0, 0.0, 1080.0, 1920.0] | [ 0, 0, 1080, 1920] HWC_FRAMEBUFFER_TARGET
520</pre>
521
522<p>This was taken while playing a movie in Grafika's "Play video (SurfaceView)"
523activity, on a Nexus 5 in portrait orientation. Note that the list is ordered
524from back to front: the SurfaceView's Surface is in the back, the app UI layer
525sits on top of that, followed by the status and navigation bars that are above
526everything else. The video is QVGA (320x240).</p>
527
528<p>The "source crop" indicates the portion of the Surface's buffer that
529SurfaceFlinger is going to display. The app UI was given a Surface equal to the
530full size of the display (1080x1920), but there's no point rendering and
531compositing pixels that will be obscured by the status and navigation bars, so
532the source is cropped to a rectangle that starts 75 pixels from the top, and
533ends 144 pixels from the bottom. The status and navigation bars have smaller
534Surfaces, and the source crop describes a rectangle that begins at the the top
535left (0,0) and spans their content.</p>
536
537<p>The "frame" is the rectangle where the pixels end up on the display. For the
538app UI layer, the frame matches the source crop, because we're copying (or
539overlaying) a portion of a display-sized layer to the same location in another
540display-sized layer. For the status and navigation bars, the size of the frame
541rectangle is the same, but the position is adjusted so that the navigation bar
542appears at the bottom of the screen.</p>
543
544<p>Now consider the layer labeled "SurfaceView", which holds our video content.
545The source crop matches the video size, which SurfaceFlinger knows because the
546MediaCodec decoder (the buffer producer) is dequeuing buffers that size. The
547frame rectangle has a completely different size -- 984x738.</p>
548
549<p>SurfaceFlinger handles size differences by scaling the buffer contents to fill
550the frame rectangle, upscaling or downscaling as needed. This particular size
551was chosen because it has the same aspect ratio as the video (4:3), and is as
552wide as possible given the constraints of the View layout (which includes some
553padding at the edges of the screen for aesthetic reasons).</p>
554
555<p>If you started playing a different video on the same Surface, the underlying
556BufferQueue would reallocate buffers to the new size automatically, and
557SurfaceFlinger would adjust the source crop. If the aspect ratio of the new
558video is different, the app would need to force a re-layout of the View to match
559it, which causes the WindowManager to tell SurfaceFlinger to update the frame
560rectangle.</p>
561
562<p>If you're rendering on the Surface through some other means, perhaps GLES, you
563can set the Surface size using the <code>SurfaceHolder#setFixedSize()</code>
564call. You could, for example, configure a game to always render at 1280x720,
565which would significantly reduce the number of pixels that must be touched to
566fill the screen on a 2560x1440 tablet or 4K television. The display processor
567handles the scaling. If you don't want to letter- or pillar-box your game, you
568could adjust the game's aspect ratio by setting the size so that the narrow
569dimension is 720 pixels, but the long dimension is set to maintain the aspect
570ratio of the physical display (e.g. 1152x720 to match a 2560x1600 display).
571You can see an example of this approach in Grafika's "Hardware scaler
572exerciser" activity.</p>
573
574<h3 id="glsurfaceview">GLSurfaceView</h3>
575
576<p>The GLSurfaceView class provides some helper classes that help manage EGL
577contexts, inter-thread communication, and interaction with the Activity
578lifecycle. That's it. You do not need to use a GLSurfaceView to use GLES.</p>
579
580<p>For example, GLSurfaceView creates a thread for rendering and configures an EGL
581context there. The state is cleaned up automatically when the activity pauses.
582Most apps won't need to know anything about EGL to use GLES with GLSurfaceView.</p>
583
584<p>In most cases, GLSurfaceView is very helpful and can make working with GLES
585easier. In some situations, it can get in the way. Use it if it helps, don't
586if it doesn't.</p>
587
588<h2 id="surfacetexture">SurfaceTexture</h2>
589
Heidi von Markham2684c462016-06-24 13:46:53 -0700590<p>The SurfaceTexture class was introduced in Android 3.0. Just as SurfaceView
591is the combination of a Surface and a View, SurfaceTexture is a rough
592combination of a Surface and a GLES texture (with a few caveats).</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700593
Heidi von Markham2684c462016-06-24 13:46:53 -0700594<p>When you create a SurfaceTexture, you are creating a BufferQueue for which
595your app is the consumer. When a new buffer is queued by the producer, your app
596is notified via callback (<code>onFrameAvailable()</code>). Your app calls
Clay Murphyccf30372014-04-07 16:13:19 -0700597<code>updateTexImage()</code>, which releases the previously-held buffer,
598acquires the new buffer from the queue, and makes some EGL calls to make the
Heidi von Markham2684c462016-06-24 13:46:53 -0700599buffer available to GLES as an external texture.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700600
601<p>External textures (<code>GL_TEXTURE_EXTERNAL_OES</code>) are not quite the
Heidi von Markham2684c462016-06-24 13:46:53 -0700602same as textures created by GLES (<code>GL_TEXTURE_2D</code>): You have to
Clay Murphyccf30372014-04-07 16:13:19 -0700603configure your renderer a bit differently, and there are things you can't do
Heidi von Markham2684c462016-06-24 13:46:53 -0700604with them. The key point is that you can render textured polygons directly
605from the data received by your BufferQueue. gralloc supports a wide variety of
606formats, so we need to guarantee the format of the data in the buffer is
607something GLES can recognize. To do so, when SurfaceTexture creates the
608BufferQueue, it sets the consumer usage flags to
609<code>GRALLOC_USAGE_HW_TEXTURE</code>, ensuring that any buffer created by
610gralloc would be usable by GLES.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700611
Heidi von Markham2684c462016-06-24 13:46:53 -0700612<p>Because SurfaceTexture interacts with an EGL context, you must be careful to
613call its methods from the correct thread (this is detailed in the class
614documentation).</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700615
616<p>If you look deeper into the class documentation, you will see a couple of odd
Heidi von Markham2684c462016-06-24 13:46:53 -0700617calls. One retrieves a timestamp, the other a transformation matrix, the value
Clay Murphyccf30372014-04-07 16:13:19 -0700618of each having been set by the previous call to <code>updateTexImage()</code>.
619It turns out that BufferQueue passes more than just a buffer handle to the consumer.
620Each buffer is accompanied by a timestamp and transformation parameters.</p>
621
622<p>The transformation is provided for efficiency. In some cases, the source data
623might be in the "wrong" orientation for the consumer; but instead of rotating
624the data before sending it, we can send the data in its current orientation with
625a transform that corrects it. The transformation matrix can be merged with
626other transformations at the point the data is used, minimizing overhead.</p>
627
628<p>The timestamp is useful for certain buffer sources. For example, suppose you
629connect the producer interface to the output of the camera (with
630<code>setPreviewTexture()</code>). If you want to create a video, you need to
631set the presentation time stamp for each frame; but you want to base that on the time
632when the frame was captured, not the time when the buffer was received by your
633app. The timestamp provided with the buffer is set by the camera code,
634resulting in a more consistent series of timestamps.</p>
635
636<h3 id="surfacet">SurfaceTexture and Surface</h3>
637
638<p>If you look closely at the API you'll see the only way for an application
639to create a plain Surface is through a constructor that takes a SurfaceTexture
640as the sole argument. (Prior to API 11, there was no public constructor for
641Surface at all.) This might seem a bit backward if you view SurfaceTexture as a
642combination of a Surface and a texture.</p>
643
644<p>Under the hood, SurfaceTexture is called GLConsumer, which more accurately
645reflects its role as the owner and consumer of a BufferQueue. When you create a
646Surface from a SurfaceTexture, what you're doing is creating an object that
647represents the producer side of the SurfaceTexture's BufferQueue.</p>
648
649<h3 id="continuous-capture">Case Study: Grafika's "Continuous Capture" Activity</h3>
650
651<p>The camera can provide a stream of frames suitable for recording as a movie. If
652you want to display it on screen, you create a SurfaceView, pass the Surface to
653<code>setPreviewDisplay()</code>, and let the producer (camera) and consumer
654(SurfaceFlinger) do all the work. If you want to record the video, you create a
655Surface with MediaCodec's <code>createInputSurface()</code>, pass that to the
656camera, and again you sit back and relax. If you want to show the video and
657record it at the same time, you have to get more involved.</p>
658
659<p>The "Continuous capture" activity displays video from the camera as it's being
660recorded. In this case, encoded video is written to a circular buffer in memory
661that can be saved to disk at any time. It's straightforward to implement so
662long as you keep track of where everything is.</p>
663
664<p>There are three BufferQueues involved. The app uses a SurfaceTexture to receive
665frames from Camera, converting them to an external GLES texture. The app
666declares a SurfaceView, which we use to display the frames, and we configure a
667MediaCodec encoder with an input Surface to create the video. So one
668BufferQueue is created by the app, one by SurfaceFlinger, and one by
669mediaserver.</p>
670
671<img src="images/continuous_capture_activity.png" alt="Grafika continuous
672capture activity" />
673
674<p class="img-caption">
675 <strong>Figure 2.</strong>Grafika's continuous capture activity
676</p>
677
678<p>In the diagram above, the arrows show the propagation of the data from the
679camera. BufferQueues are in color (purple producer, cyan consumer). Note
680“Camera” actually lives in the mediaserver process.</p>
681
682<p>Encoded H.264 video goes to a circular buffer in RAM in the app process, and is
683written to an MP4 file on disk using the MediaMuxer class when the “capture”
684button is hit.</p>
685
686<p>All three of the BufferQueues are handled with a single EGL context in the
687app, and the GLES operations are performed on the UI thread. Doing the
688SurfaceView rendering on the UI thread is generally discouraged, but since we're
689doing simple operations that are handled asynchronously by the GLES driver we
690should be fine. (If the video encoder locks up and we block trying to dequeue a
691buffer, the app will become unresponsive. But at that point, we're probably
692failing anyway.) The handling of the encoded data -- managing the circular
693buffer and writing it to disk -- is performed on a separate thread.</p>
694
695<p>The bulk of the configuration happens in the SurfaceView's <code>surfaceCreated()</code>
696callback. The EGLContext is created, and EGLSurfaces are created for the
697display and for the video encoder. When a new frame arrives, we tell
698SurfaceTexture to acquire it and make it available as a GLES texture, then
699render it with GLES commands on each EGLSurface (forwarding the transform and
700timestamp from SurfaceTexture). The encoder thread pulls the encoded output
701from MediaCodec and stashes it in memory.</p>
702
Heidi von Markham2684c462016-06-24 13:46:53 -0700703
704<h3 id="secure-texture-video-playback">Secure Texture Video Playback</h3>
705<p>Android N supports GPU post-processing of protected video content. This
706allows using the GPU for complex non-linear video effects (such as warps),
707mapping protected video content onto textures for use in general graphics scenes
708(e.g., using OpenGL ES), and virtual reality (VR).</p>
709
710<img src="images/graphics_secure_texture_playback.png" alt="Secure Texture Video Playback" />
711<p class="img-caption"><strong>Figure 3.</strong>Secure texture video playback</p>
712
713<p>Support is enabled using the following two extensions:</p>
714<ul>
715<li><strong>EGL extension</strong>
716(<code><a href="https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_protected_content.txt">EGL_EXT_protected_content</code></a>).
717Allows the creation of protected GL contexts and surfaces, which can both
718operate on protected content.</li>
719<li><strong>GLES extension</strong>
720(<code><a href="https://www.khronos.org/registry/gles/extensions/EXT/EXT_protected_textures.txt">GL_EXT_protected_textures</code></a>).
721Allows tagging textures as protected so they can be used as framebuffer texture
722attachments.</li>
723</ul>
724
725<p>Android N also updates SurfaceTexture and ACodec
726(<code>libstagefright.so</code>) to allow protected content to be sent even if
727the windows surface does not queue to the window composer (i.e., SurfaceFlinger)
728and provide a protected video surface for use within a protected context. This
729is done by setting the correct protected consumer bits
730(<code>GRALLOC_USAGE_PROTECTED</code>) on surfaces created in a protected
731context (verified by ACodec).</p>
732
733<p>These changes benefit app developers who can create apps that perform
734enhanced video effects or apply video textures using protected content in GL
735(for example, in VR), end users who can view high-value video content (such as
736movies and TV shows) in GL environment (for example, in VR), and OEMs who can
737achieve higher sales due to added device functionality (for example, watching HD
738movies in VR). The new EGL and GLES extensions can be used by system on chip
739(SoCs) providers and other vendors, and are currently implemented on the
740Qualcomm MSM8994 SoC chipset used in the Nexus 6P.
741
742<p>Secure texture video playback sets the foundation for strong DRM
743implementation in the OpenGL ES environment. Without a strong DRM implementation
744such as Widevine Level 1, many content providers would not allow rendering of
745their high-value content in the OpenGL ES environment, preventing important VR
746use cases such as watching DRM protected content in VR.</p>
747
748<p>AOSP includes framework code for secure texture video playback; driver
749support is up to the vendor. Partners must implement the
750<code>EGL_EXT_protected_content</code> and
751<code>GL_EXT_protected_textures extensions</code>. When using your own codec
752library (to replace libstagefright), note the changes in
753<code>/frameworks/av/media/libstagefright/SurfaceUtils.cpp</code> that allow
754buffers marked with <code>GRALLOC_USAGE_PROTECTED</code> to be sent to
755ANativeWindows (even if the ANativeWindow does not queue directly to the window
756composer) as long as the consumer usage bits contain
757<code>GRALLOC_USAGE_PROTECTED</code>. For detailed documentation on implementing
758the extensions, refer to the Khronos Registry
759(<a href="https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_protected_content.txt">EGL_EXT_protected_content</a>,
760<a href="https://www.khronos.org/registry/gles/extensions/EXT/EXT_protected_textures.txt">GL_EXT_protected_textures</a>).</p>
761
762<p>Partners may also need to make hardware changes to ensure that protected
763memory mapped onto the GPU remains protected and unreadable by unprotected
764code.</p>
765
Clay Murphyccf30372014-04-07 16:13:19 -0700766<h2 id="texture">TextureView</h2>
767
Heidi von Markham2684c462016-06-24 13:46:53 -0700768<p>The TextureView class introduced in Android 4.0 and is the most complex of
769the View objects discussed here, combining a View with a SurfaceTexture.</p>
Clay Murphyccf30372014-04-07 16:13:19 -0700770
771<p>Recall that the SurfaceTexture is a "GL consumer", consuming buffers of graphics
772data and making them available as textures. TextureView wraps a SurfaceTexture,
773taking over the responsibility of responding to the callbacks and acquiring new
774buffers. The arrival of new buffers causes TextureView to issue a View
775invalidate request. When asked to draw, the TextureView uses the contents of
776the most recently received buffer as its data source, rendering wherever and
777however the View state indicates it should.</p>
778
779<p>You can render on a TextureView with GLES just as you would SurfaceView. Just
780pass the SurfaceTexture to the EGL window creation call. However, doing so
781exposes a potential problem.</p>
782
783<p>In most of what we've looked at, the BufferQueues have passed buffers between
784different processes. When rendering to a TextureView with GLES, both producer
785and consumer are in the same process, and they might even be handled on a single
786thread. Suppose we submit several buffers in quick succession from the UI
787thread. The EGL buffer swap call will need to dequeue a buffer from the
788BufferQueue, and it will stall until one is available. There won't be any
789available until the consumer acquires one for rendering, but that also happens
790on the UI thread… so we're stuck.</p>
791
792<p>The solution is to have BufferQueue ensure there is always a buffer
793available to be dequeued, so the buffer swap never stalls. One way to guarantee
794this is to have BufferQueue discard the contents of the previously-queued buffer
795when a new buffer is queued, and to place restrictions on minimum buffer counts
796and maximum acquired buffer counts. (If your queue has three buffers, and all
797three buffers are acquired by the consumer, then there's nothing to dequeue and
798the buffer swap call must hang or fail. So we need to prevent the consumer from
799acquiring more than two buffers at once.) Dropping buffers is usually
800undesirable, so it's only enabled in specific situations, such as when the
801producer and consumer are in the same process.</p>
802
803<h3 id="surface-or-texture">SurfaceView or TextureView?</h3>
804SurfaceView and TextureView fill similar roles, but have very different
805implementations. To decide which is best requires an understanding of the
806trade-offs.</p>
807
808<p>Because TextureView is a proper citizen of the View hierarchy, it behaves like
809any other View, and can overlap or be overlapped by other elements. You can
810perform arbitrary transformations and retrieve the contents as a bitmap with
811simple API calls.</p>
812
813<p>The main strike against TextureView is the performance of the composition step.
814With SurfaceView, the content is written to a separate layer that SurfaceFlinger
815composites, ideally with an overlay. With TextureView, the View composition is
816always performed with GLES, and updates to its contents may cause other View
817elements to redraw as well (e.g. if they're positioned on top of the
818TextureView). After the View rendering completes, the app UI layer must then be
819composited with other layers by SurfaceFlinger, so you're effectively
820compositing every visible pixel twice. For a full-screen video player, or any
821other application that is effectively just UI elements layered on top of video,
822SurfaceView offers much better performance.</p>
823
824<p>As noted earlier, DRM-protected video can be presented only on an overlay plane.
825 Video players that support protected content must be implemented with
826SurfaceView.</p>
827
828<h3 id="grafika">Case Study: Grafika's Play Video (TextureView)</h3>
829
830<p>Grafika includes a pair of video players, one implemented with TextureView, the
831other with SurfaceView. The video decoding portion, which just sends frames
832from MediaCodec to a Surface, is the same for both. The most interesting
833differences between the implementations are the steps required to present the
834correct aspect ratio.</p>
835
836<p>While SurfaceView requires a custom implementation of FrameLayout, resizing
837SurfaceTexture is a simple matter of configuring a transformation matrix with
838<code>TextureView#setTransform()</code>. For the former, you're sending new
839window position and size values to SurfaceFlinger through WindowManager; for
840the latter, you're just rendering it differently.</p>
841
842<p>Otherwise, both implementations follow the same pattern. Once the Surface has
843been created, playback is enabled. When "play" is hit, a video decoding thread
844is started, with the Surface as the output target. After that, the app code
845doesn't have to do anything -- composition and display will either be handled by
846SurfaceFlinger (for the SurfaceView) or by TextureView.</p>
847
848<h3 id="decode">Case Study: Grafika's Double Decode</h3>
849
850<p>This activity demonstrates manipulation of the SurfaceTexture inside a
851TextureView.</p>
852
853<p>The basic structure of this activity is a pair of TextureViews that show two
854different videos playing side-by-side. To simulate the needs of a
855videoconferencing app, we want to keep the MediaCodec decoders alive when the
856activity is paused and resumed for an orientation change. The trick is that you
857can't change the Surface that a MediaCodec decoder uses without fully
858reconfiguring it, which is a fairly expensive operation; so we want to keep the
859Surface alive. The Surface is just a handle to the producer interface in the
860SurfaceTexture's BufferQueue, and the SurfaceTexture is managed by the
861TextureView;, so we also need to keep the SurfaceTexture alive. So how do we deal
862with the TextureView getting torn down?</p>
863
864<p>It just so happens TextureView provides a <code>setSurfaceTexture()</code> call
865that does exactly what we want. We obtain references to the SurfaceTextures
866from the TextureViews and save them in a static field. When the activity is
867shut down, we return "false" from the <code>onSurfaceTextureDestroyed()</code>
868callback to prevent destruction of the SurfaceTexture. When the activity is
869restarted, we stuff the old SurfaceTexture into the new TextureView. The
870TextureView class takes care of creating and destroying the EGL contexts.</p>
871
872<p>Each video decoder is driven from a separate thread. At first glance it might
873seem like we need EGL contexts local to each thread; but remember the buffers
874with decoded output are actually being sent from mediaserver to our
875BufferQueue consumers (the SurfaceTextures). The TextureViews take care of the
876rendering for us, and they execute on the UI thread.</p>
877
878<p>Implementing this activity with SurfaceView would be a bit harder. We can't
879just create a pair of SurfaceViews and direct the output to them, because the
880Surfaces would be destroyed during an orientation change. Besides, that would
881add two layers, and limitations on the number of available overlays strongly
882motivate us to keep the number of layers to a minimum. Instead, we'd want to
883create a pair of SurfaceTextures to receive the output from the video decoders,
884and then perform the rendering in the app, using GLES to render two textured
885quads onto the SurfaceView's Surface.</p>
886
887<h2 id="notes">Conclusion</h2>
888
889<p>We hope this page has provided useful insights into the way Android handles
890graphics at the system level.</p>
891
892<p>Some information and advice on related topics can be found in the appendices
893that follow.</p>
894
895<h2 id="loops">Appendix A: Game Loops</h2>
896
897<p>A very popular way to implement a game loop looks like this:</p>
898
899<pre>
900while (playing) {
901 advance state by one frame
902 render the new frame
903 sleep until it’s time to do the next frame
904}
905</pre>
906
907<p>There are a few problems with this, the most fundamental being the idea that the
908game can define what a "frame" is. Different displays will refresh at different
909rates, and that rate may vary over time. If you generate frames faster than the
910display can show them, you will have to drop one occasionally. If you generate
911them too slowly, SurfaceFlinger will periodically fail to find a new buffer to
912acquire and will re-show the previous frame. Both of these situations can
913cause visible glitches.</p>
914
915<p>What you need to do is match the display's frame rate, and advance game state
916according to how much time has elapsed since the previous frame. There are two
917ways to go about this: (1) stuff the BufferQueue full and rely on the "swap
918buffers" back-pressure; (2) use Choreographer (API 16+).</p>
919
920<h3 id="stuffing">Queue Stuffing</h3>
921
922<p>This is very easy to implement: just swap buffers as fast as you can. In early
923versions of Android this could actually result in a penalty where
924<code>SurfaceView#lockCanvas()</code> would put you to sleep for 100ms. Now
925it's paced by the BufferQueue, and the BufferQueue is emptied as quickly as
926SurfaceFlinger is able.</p>
927
928<p>One example of this approach can be seen in <a
929href="https://code.google.com/p/android-breakout/">Android Breakout</a>. It
930uses GLSurfaceView, which runs in a loop that calls the application's
931onDrawFrame() callback and then swaps the buffer. If the BufferQueue is full,
932the <code>eglSwapBuffers()</code> call will wait until a buffer is available.
933Buffers become available when SurfaceFlinger releases them, which it does after
934acquiring a new one for display. Because this happens on VSYNC, your draw loop
935timing will match the refresh rate. Mostly.</p>
936
937<p>There are a couple of problems with this approach. First, the app is tied to
938SurfaceFlinger activity, which is going to take different amounts of time
939depending on how much work there is to do and whether it's fighting for CPU time
940with other processes. Since your game state advances according to the time
941between buffer swaps, your animation won't update at a consistent rate. When
942running at 60fps with the inconsistencies averaged out over time, though, you
943probably won't notice the bumps.</p>
944
945<p>Second, the first couple of buffer swaps are going to happen very quickly
946because the BufferQueue isn't full yet. The computed time between frames will
947be near zero, so the game will generate a few frames in which nothing happens.
948In a game like Breakout, which updates the screen on every refresh, the queue is
949always full except when a game is first starting (or un-paused), so the effect
950isn't noticeable. A game that pauses animation occasionally and then returns to
951as-fast-as-possible mode might see odd hiccups.</p>
952
953<h3 id="choreographer">Choreographer</h3>
954
955<p>Choreographer allows you to set a callback that fires on the next VSYNC. The
956actual VSYNC time is passed in as an argument. So even if your app doesn't wake
957up right away, you still have an accurate picture of when the display refresh
958period began. Using this value, rather than the current time, yields a
959consistent time source for your game state update logic.</p>
960
961<p>Unfortunately, the fact that you get a callback after every VSYNC does not
962guarantee that your callback will be executed in a timely fashion or that you
963will be able to act upon it sufficiently swiftly. Your app will need to detect
964situations where it's falling behind and drop frames manually.</p>
965
966<p>The "Record GL app" activity in Grafika provides an example of this. On some
967devices (e.g. Nexus 4 and Nexus 5), the activity will start dropping frames if
968you just sit and watch. The GL rendering is trivial, but occasionally the View
969elements get redrawn, and the measure/layout pass can take a very long time if
970the device has dropped into a reduced-power mode. (According to systrace, it
971takes 28ms instead of 6ms after the clocks slow on Android 4.4. If you drag
972your finger around the screen, it thinks you're interacting with the activity,
973so the clock speeds stay high and you'll never drop a frame.)</p>
974
975<p>The simple fix was to drop a frame in the Choreographer callback if the current
976time is more than N milliseconds after the VSYNC time. Ideally the value of N
977is determined based on previously observed VSYNC intervals. For example, if the
978refresh period is 16.7ms (60fps), you might drop a frame if you're running more
979than 15ms late.</p>
980
981<p>If you watch "Record GL app" run, you will see the dropped-frame counter
982increase, and even see a flash of red in the border when frames drop. Unless
983your eyes are very good, though, you won't see the animation stutter. At 60fps,
984the app can drop the occasional frame without anyone noticing so long as the
985animation continues to advance at a constant rate. How much you can get away
986with depends to some extent on what you're drawing, the characteristics of the
987display, and how good the person using the app is at detecting jank.</p>
988
989<h3 id="thread">Thread Management</h3>
990
991<p>Generally speaking, if you're rendering onto a SurfaceView, GLSurfaceView, or
992TextureView, you want to do that rendering in a dedicated thread. Never do any
993"heavy lifting" or anything that takes an indeterminate amount of time on the
994UI thread.</p>
995
996<p>Breakout and "Record GL app" use dedicated renderer threads, and they also
997update animation state on that thread. This is a reasonable approach so long as
998game state can be updated quickly.</p>
999
1000<p>Other games separate the game logic and rendering completely. If you had a
1001simple game that did nothing but move a block every 100ms, you could have a
1002dedicated thread that just did this:</p>
1003
1004<pre>
1005 run() {
1006 Thread.sleep(100);
1007 synchronized (mLock) {
1008 moveBlock();
1009 }
1010 }
1011</pre>
1012
1013<p>(You may want to base the sleep time off of a fixed clock to prevent drift --
1014sleep() isn't perfectly consistent, and moveBlock() takes a nonzero amount of
1015time -- but you get the idea.)</p>
1016
1017<p>When the draw code wakes up, it just grabs the lock, gets the current position
1018of the block, releases the lock, and draws. Instead of doing fractional
1019movement based on inter-frame delta times, you just have one thread that moves
1020things along and another thread that draws things wherever they happen to be
1021when the drawing starts.</p>
1022
1023<p>For a scene with any complexity you'd want to create a list of upcoming events
1024sorted by wake time, and sleep until the next event is due, but it's the same
1025idea.</p>
1026
1027<h2 id="activity">Appendix B: SurfaceView and the Activity Lifecycle</h2>
1028
1029<p>When using a SurfaceView, it's considered good practice to render the Surface
1030from a thread other than the main UI thread. This raises some questions about
1031the interaction between that thread and the Activity lifecycle.</p>
1032
1033<p>First, a little background. For an Activity with a SurfaceView, there are two
1034separate but interdependent state machines:</p>
1035
1036<ol>
1037<li>Application onCreate / onResume / onPause</li>
1038<li>Surface created / changed / destroyed</li>
1039</ol>
1040
1041<p>When the Activity starts, you get callbacks in this order:</p>
1042
1043<ul>
1044<li>onCreate</li>
1045<li>onResume</li>
1046<li>surfaceCreated</li>
1047<li>surfaceChanged</li>
1048</ul>
1049
1050<p>If you hit "back" you get:</p>
1051
1052<ul>
1053<li>onPause</li>
1054<li>surfaceDestroyed (called just before the Surface goes away)</li>
1055</ul>
1056
1057<p>If you rotate the screen, the Activity is torn down and recreated, so you
1058get the full cycle. If it matters, you can tell that it's a "quick" restart by
1059checking <code>isFinishing()</code>. (It might be possible to start / stop an
1060Activity so quickly that surfaceCreated() might actually happen after onPause().)</p>
1061
1062<p>If you tap the power button to blank the screen, you only get
1063<code>onPause()</code> -- no <code>surfaceDestroyed()</code>. The Surface
1064remains alive, and rendering can continue. You can even keep getting
1065Choreographer events if you continue to request them. If you have a lock
1066screen that forces a different orientation, your Activity may be restarted when
1067the device is unblanked; but if not, you can come out of screen-blank with the
1068same Surface you had before.</p>
1069
1070<p>This raises a fundamental question when using a separate renderer thread with
1071SurfaceView: Should the lifespan of the thread be tied to that of the Surface or
1072the Activity? The answer depends on what you want to have happen when the
1073screen goes blank. There are two basic approaches: (1) start/stop the thread on
1074Activity start/stop; (2) start/stop the thread on Surface create/destroy.</p>
1075
1076<p>#1 interacts well with the app lifecycle. We start the renderer thread in
1077<code>onResume()</code> and stop it in <code>onPause()</code>. It gets a bit
1078awkward when creating and configuring the thread because sometimes the Surface
1079will already exist and sometimes it won't (e.g. it's still alive after toggling
1080the screen with the power button). We have to wait for the surface to be
1081created before we do some initialization in the thread, but we can't simply do
1082it in the <code>surfaceCreated()</code> callback because that won't fire again
1083if the Surface didn't get recreated. So we need to query or cache the Surface
1084state, and forward it to the renderer thread. Note we have to be a little
1085careful here passing objects between threads -- it is best to pass the Surface or
1086SurfaceHolder through a Handler message, rather than just stuffing it into the
1087thread, to avoid issues on multi-core systems (cf. the <a
1088href="http://developer.android.com/training/articles/smp.html">Android SMP
1089Primer</a>).</p>
1090
1091<p>#2 has a certain appeal because the Surface and the renderer are logically
1092intertwined. We start the thread after the Surface has been created, which
1093avoids some inter-thread communication concerns. Surface created / changed
1094messages are simply forwarded. We need to make sure rendering stops when the
1095screen goes blank, and resumes when it un-blanks; this could be a simple matter
1096of telling Choreographer to stop invoking the frame draw callback. Our
1097<code>onResume()</code> will need to resume the callbacks if and only if the
1098renderer thread is running. It may not be so trivial though -- if we animate
1099based on elapsed time between frames, we could have a very large gap when the
1100next event arrives; so an explicit pause/resume message may be desirable.</p>
1101
1102<p>The above is primarily concerned with how the renderer thread is configured and
1103whether it's executing. A related concern is extracting state from the thread
1104when the Activity is killed (in <code>onPause()</code> or <code>onSaveInstanceState()</code>).
1105Approach #1 will work best for that, because once the renderer thread has been
1106joined its state can be accessed without synchronization primitives.</p>
1107
1108<p>You can see an example of approach #2 in Grafika's "Hardware scaler exerciser."</p>
1109
1110<h2 id="tracking">Appendix C: Tracking BufferQueue with systrace</h2>
1111
1112<p>If you really want to understand how graphics buffers move around, you need to
1113use systrace. The system-level graphics code is well instrumented, as is much
1114of the relevant app framework code. Enable the "gfx" and "view" tags, and
1115generally "sched" as well.</p>
1116
1117<p>A full description of how to use systrace effectively would fill a rather long
1118document. One noteworthy item is the presence of BufferQueues in the trace. If
1119you've used systrace before, you've probably seen them, but maybe weren't sure
1120what they were. As an example, if you grab a trace while Grafika's "Play video
1121(SurfaceView)" is running, you will see a row labeled: "SurfaceView" This row
1122tells you how many buffers were queued up at any given time.</p>
1123
1124<p>You'll notice the value increments while the app is active -- triggering
1125the rendering of frames by the MediaCodec decoder -- and decrements while
1126SurfaceFlinger is doing work, consuming buffers. If you're showing video at
112730fps, the queue's value will vary from 0 to 1, because the ~60fps display can
1128easily keep up with the source. (You'll also notice that SurfaceFlinger is only
1129waking up when there's work to be done, not 60 times per second. The system tries
1130very hard to avoid work and will disable VSYNC entirely if nothing is updating
1131the screen.)</p>
1132
1133<p>If you switch to "Play video (TextureView)" and grab a new trace, you'll see a
1134row with a much longer name
1135("com.android.grafika/com.android.grafika.PlayMovieActivity"). This is the
1136main UI layer, which is of course just another BufferQueue. Because TextureView
1137renders into the UI layer, rather than a separate layer, you'll see all of the
1138video-driven updates here.</p>
1139
1140<p>For more information about systrace, see the <a
1141href="http://developer.android.com/tools/help/systrace.html">Android
1142documentation</a> for the tool.</p>