blob: 59aca16d61fe08145a58fe69744b03332778d7f4 [file] [log] [blame]
page.title=Implementing graphics
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,
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">
<p>Follow the instructions here to implement the Android graphics HAL.</p>
<h2 id=requirements>Requirements</h2>
<p>The following list and sections describe what you need to provide to support
graphics in your product:</p>
<ul> <li> OpenGL ES 1.x Driver <li> OpenGL ES 2.0 Driver <li> OpenGL ES 3.0
Driver (optional) <li> EGL Driver <li> Gralloc HAL implementation <li> Hardware
Composer HAL implementation <li> Framebuffer HAL implementation </ul>
<h2 id=implementation>Implementation</h2>
<h3 id=opengl_and_egl_drivers>OpenGL and EGL drivers</h3>
<p>You must provide drivers for OpenGL ES 1.x, OpenGL ES 2.0, and EGL. Here are
some key considerations:</p>
<ul> <li> The GL driver needs to be robust and conformant to OpenGL ES
standards. <li> Do not limit the number of GL contexts. Because Android allows
apps in the background and tries to keep GL contexts alive, you should not
limit the number of contexts in your driver. <li> It is not uncommon to have
20-30 active GL contexts at once, so you should also be careful with the amount
of memory allocated for each context. <li> Support the YV12 image format and
any other YUV image formats that come from other components in the system such
as media codecs or the camera. <li> Support the mandatory extensions:
<code>EGL_ANDROID_image_native_buffer</code>, and
<code>EGL_ANDROID_recordable</code>. The
<code>EGL_ANDROID_framebuffer_target</code> extension is required for Hardware
Composer 1.1 and higher, as well. <li> We highly recommend also supporting
<code>EGL_ANDROID_blob_cache</code>, <code>EGL_KHR_fence_sync</code>,
<code>EGL_KHR_wait_sync</code>, and <code>EGL_ANDROID_native_fence_sync</code>.
<p>Note the OpenGL API exposed to app developers is different from the OpenGL
interface that you are implementing. Apps do not have access to the GL driver
layer and must go through the interface provided by the APIs.</p>
<h3 id=pre-rotation>Pre-rotation</h3>
<p>Many hardware overlays do not support rotation, and even if they do it costs
processing power. So the solution is to pre-transform the buffer before it
reaches SurfaceFlinger. A query hint in <code>ANativeWindow</code> was added
(<code>NATIVE_WINDOW_TRANSFORM_HINT</code>) that represents the most likely
transform to be applied to the buffer by SurfaceFlinger. Your GL driver can use
this hint to pre-transform the buffer before it reaches SurfaceFlinger so when
the buffer arrives, it is correctly transformed.</p>
<p>For example, you may receive a hint to rotate 90 degrees. You must generate
a matrix and apply it to the buffer to prevent it from running off the end of
the page. To save power, this should be done in pre-rotation. See the
<code>ANativeWindow</code> interface defined in
<code>system/core/include/system/window.h</code> for more details.</p>
<h3 id=gralloc_hal>Gralloc HAL</h3>
<p>The graphics memory allocator is needed to allocate memory that is requested
by image producers. You can find the interface definition of the HAL at:
<h3 id=protected_buffers>Protected buffers</h3>
<p>The gralloc usage flag <code>GRALLOC_USAGE_PROTECTED</code> allows the
graphics buffer to be displayed only through a hardware-protected path. These
overlay planes are the only way to display DRM content. DRM-protected buffers
cannot be accessed by SurfaceFlinger or the OpenGL ES driver.</p>
<p>DRM-protected video can be presented only on an overlay plane. Video players
that support protected content must be implemented with SurfaceView. Software
running on unprotected hardware cannot read or write the buffer.
Hardware-protected paths must appear on the Hardware Composer overlay. For
instance, protected videos will disappear from the display if Hardware Composer
switches to OpenGL ES composition.</p>
<p>See the <a href="{@docRoot}devices/drm.html">DRM</a> page for a description
of protected content.</p>
<h3 id=hardware_composer_hal>Hardware Composer HAL</h3>
<p>The Hardware Composer HAL is used by SurfaceFlinger to composite surfaces to
the screen. The Hardware Composer abstracts objects like overlays and 2D
blitters and helps offload some work that would normally be done with
<p>We recommend you start using version 1.3 of the Hardware Composer HAL as it
will provide support for the newest features (explicit synchronization,
external displays, and more). Because the physical display hardware behind the
Hardware Composer abstraction layer can vary from device to device, it is
difficult to define recommended features. But here is some guidance:</p>
<ul> <li> The Hardware Composer should support at least four overlays (status
bar, system bar, application, and wallpaper/background). <li> Layers can be
bigger than the screen, so the Hardware Composer should be able to handle
layers that are larger than the display (for example, a wallpaper). <li>
Pre-multiplied per-pixel alpha blending and per-plane alpha blending should be
supported at the same time. <li> The Hardware Composer should be able to
consume the same buffers that the GPU, camera, video decoder, and Skia buffers
are producing, so supporting some of the following properties is helpful: <ul>
<li> RGBA packing order <li> YUV formats <li> Tiling, swizzling, and stride
properties </ul> <li> A hardware path for protected video playback must be
present if you want to support protected content. </ul>
<p>The general recommendation when implementing your Hardware Composer is to
implement a non-operational Hardware Composer first. Once you have the
structure done, implement a simple algorithm to delegate composition to the
Hardware Composer. For example, just delegate the first three or four surfaces
to the overlay hardware of the Hardware Composer.</p>
<p>Focus on optimization, such as intelligently selecting the surfaces to send
to the overlay hardware that maximizes the load taken off of the GPU. Another
optimization is to detect whether the screen is updating. If not, delegate
composition to OpenGL instead of the Hardware Composer to save power. When the
screen updates again, continue to offload composition to the Hardware
<p>Devices must report the display mode (or resolution). Android uses the first
mode reported by the device. To support televisions, have the TV device report
the mode selected for it by the manufacturer to Hardware Composer. See
hwcomposer.h for more details.</p>
<p>Prepare for common use cases, such as:</p>
<ul> <li> Full-screen games in portrait and landscape mode <li> Full-screen
video with closed captioning and playback control <li> The home screen
(compositing the status bar, system bar, application window, and live
wallpapers) <li> Protected video playback <li> Multiple display support </ul>
<p>These use cases should address regular, predictable uses rather than edge
cases that are rarely encountered. Otherwise, any optimization will have little
benefit. Implementations must balance two competing goals: animation smoothness
and interaction latency.</p>
<p>Further, to make best use of Android graphics, you must develop a robust
clocking strategy. Performance matters little if clocks have been turned down
to make every operation slow. You need a clocking strategy that puts the clocks
at high speed when needed, such as to make animations seamless, and then slows
the clocks whenever the increased speed is no longer needed.</p>
<p>Use the <code>adb shell dumpsys SurfaceFlinger</code> command to see
precisely what SurfaceFlinger is doing. See the <a
Composer</a> section of the Architecture page for example output and a
description of relevant fields.</p>
<p>You can find the HAL for the Hardware Composer and additional documentation
in: <code>hardware/libhardware/include/hardware/hwcomposer.h
<p>A stub implementation is available in the
<code>hardware/libhardware/modules/hwcomposer</code> directory.</p>
<h3 id=vsync>VSYNC</h3>
<p>VSYNC synchronizes certain events to the refresh cycle of the display.
Applications always start drawing on a VSYNC boundary, and SurfaceFlinger
always composites on a VSYNC boundary. This eliminates stutters and improves
visual performance of graphics. The Hardware Composer has a function
<pre class=prettyprint> int (waitForVsync*) (int64_t *timestamp) </pre>
<p>This points to a function you must implement for VSYNC. This function blocks
until a VSYNC occurs and returns the timestamp of the actual VSYNC. A message
must be sent every time VSYNC occurs. A client can receive a VSYNC timestamp
once, at specified intervals, or continuously (interval of 1). You must
implement VSYNC to have no more than a 1ms lag at the maximum (0.5ms or less is
recommended), and the timestamps returned must be extremely accurate.</p>
<h4 id=explicit_synchronization>Explicit synchronization</h4>
<p>Explicit synchronization is required and provides a mechanism for Gralloc
buffers to be acquired and released in a synchronized way. Explicit
synchronization allows producers and consumers of graphics buffers to signal
when they are done with a buffer. This allows the Android system to
asynchronously queue buffers to be read or written with the certainty that
another consumer or producer does not currently need them. See the <a
href="#synchronization_framework">Synchronization framework</a> section for an overview of
this mechanism.</p>
<p>The benefits of explicit synchronization include less behavior variation
between devices, better debugging support, and improved testing metrics. For
instance, the sync framework output readily identifies problem areas and root
causes. And centralized SurfaceFlinger presentation timestamps show when events
occur in the normal flow of the system.</p>
<p>This communication is facilitated by the use of synchronization fences,
which are now required when requesting a buffer for consuming or producing. The
synchronization framework consists of three main building blocks:
sync_timeline, sync_pt, and sync_fence.</p>
<h5 id=sync_timeline>sync_timeline</h5>
<p>A sync_timeline is a monotonically increasing timeline that should be
implemented for each driver instance, such as a GL context, display controller,
or 2D blitter. This is essentially a counter of jobs submitted to the kernel
for a particular piece of hardware. It provides guarantees about the order of
operations and allows hardware-specific implementations.</p>
<p>Please note, the sync_timeline is offered as a CPU-only reference
implementation called sw_sync (which stands for software sync). If possible,
use sw_sync instead of a sync_timeline to save resources and avoid complexity.
If youre not employing a hardware resource, sw_sync should be sufficient.</p>
<p>If you must implement a sync_timeline, use the sw_sync driver as a starting
point. Follow these guidelines:</p>
<ul> <li> Provide useful names for all drivers, timelines, and fences. This
simplifies debugging. <li> Implement timeline_value str and pt_value_str
operators in your timelines as they make debugging output much more readable.
<li> If you want your userspace libraries (such as the GL library) to have
access to the private data of your timelines, implement the fill driver_data
operator. This lets you get information about the immutable sync_fence and
sync_pts so you might build command lines based upon them. </ul>
<p>When implementing a sync_timeline, <strong>dont</strong>:</p>
<ul> <li> Base it on any real view of time, such as when a wall clock or other
piece of work might finish. It is better to create an abstract timeline that
you can control. <li> Allow userspace to explicitly create or signal a fence.
This can result in one piece of the user pipeline creating a denial-of-service
attack that halts all functionality. This is because the userspace cannot make
promises on behalf of the kernel. <li> Access sync_timeline, sync_pt, or
sync_fence elements explicitly, as the API should provide all required
functions. </ul>
<h5 id=sync_pt>sync_pt</h5>
<p>A sync_pt is a single value or point on a sync_timeline. A point has three
states: active, signaled, and error. Points start in the active state and
transition to the signaled or error states. For instance, when a buffer is no
longer needed by an image consumer, this sync_point is signaled so that image
producers know it is okay to write into the buffer again.</p>
<h5 id=sync_fence>sync_fence</h5>
<p>A sync_fence is a collection of sync_pts that often have different
sync_timeline parents (such as for the display controller and GPU). These are
the main primitives over which drivers and userspace communicate their
dependencies. A fence is a promise from the kernel that it gives upon accepting
work that has been queued and assures completion in a finite amount of
<p>This allows multiple consumers or producers to signal they are using a
buffer and to allow this information to be communicated with one function
parameter. Fences are backed by a file descriptor and can be passed from
kernel-space to user-space. For instance, a fence can contain two sync_points
that signify when two separate image consumers are done reading a buffer. When
the fence is signaled, the image producers know both consumers are done
Fences, like sync_pts, start active and then change state based upon the state
of their points. If all sync_pts become signaled, the sync_fence becomes
signaled. If one sync_pt falls into an error state, the entire sync_fence has
an error state.
Membership in the sync_fence is immutable once the fence is created. And since
a sync_pt can be in only one fence, it is included as a copy. Even if two
points have the same value, there will be two copies of the sync_pt in the
To get more than one point in a fence, a merge operation is conducted. In the
merge, the points from two distinct fences are added to a third fence. If one
of those points was signaled in the originating fence, and the other was not,
the third fence will also not be in a signaled state.</p>
<p>To implement explicit synchronization, you need to provide the
<ul> <li> A kernel-space driver that implements a synchronization timeline for
a particular piece of hardware. Drivers that need to be fence-aware are
generally anything that accesses or communicates with the Hardware Composer.
Here are the key files (found in the android-3.4 kernel branch): <ul> <li> Core
implementation: <ul> <li> <code>kernel/common/include/linux/sync.h</code> <li>
<code>kernel/common/drivers/base/sync.c</code> </ul> <li> sw_sync: <ul> <li>
<code>kernel/common/include/linux/sw_sync.h</code> <li>
<code>kernel/common/drivers/base/sw_sync.c</code> </ul> <li> Documentation:
<li> <code>kernel/common//Documentation/sync.txt</code> Finally, the
<code>platform/system/core/libsync</code> directory includes a library to
communicate with the kernel-space. </ul> <li> A Hardware Composer HAL module
(version 1.3 or later) that supports the new synchronization functionality. You
will need to provide the appropriate synchronization fences as parameters to
the set() and prepare() functions in the HAL. <li> Two GL-specific extensions
related to fences, <code>EGL_ANDROID_native_fence_sync</code> and
<code>EGL_ANDROID_wait_sync</code>, along with incorporating fence support into
your graphics drivers. </ul>
<p>For example, to use the API supporting the synchronization function, you
might develop a display driver that has a display buffer function. Before the
synchronization framework existed, this function would receive dma-bufs, put
those buffers on the display, and block while the buffer is visible, like
<pre class=prettyprint>
* assumes buf is ready to be displayed. returns when buffer is no longer on
* screen.
void display_buffer(struct dma_buf *buf); </pre>
<p>With the synchronization framework, the API call is slightly more complex.
While putting a buffer on display, you associate it with a fence that says when
the buffer will be ready. So you queue up the work, which you will initiate
once the fence clears.</p>
<p>In this manner, you are not blocking anything. You immediately return your
own fence, which is a guarantee of when the buffer will be off of the display.
As you queue up buffers, the kernel will list dependencies. With the
synchronization framework:</p>
<pre class=prettyprint>
* will display buf when fence is signaled. returns immediately with a fence
* that will signal when buf is no longer displayed.
struct sync_fence* display_buffer(struct dma_buf *buf, struct sync_fence
*fence); </pre>
<h4 id=sync_integration>Sync integration</h4>
<h5 id=integration_conventions>Integration conventions</h5>
<p>This section explains how to integrate the low-level sync framework with
different parts of the Android framework and the drivers that need to
communicate with one another.</p>
<p>The Android HAL interfaces for graphics follow consistent conventions so
when file descriptors are passed across a HAL interface, ownership of the file
descriptor is always transferred. This means:</p>
<ul> <li> if you receive a fence file descriptor from the sync framework, you
must close it. <li> if you return a fence file descriptor to the sync
framework, the framework will close it. <li> if you want to continue using the
fence file descriptor, you must duplicate the descriptor. </ul>
<p>Every time a fence is passed through BufferQueue - such as for a window that
passes a fence to BufferQueue saying when its new contents will be ready - the
fence object is renamed. Since kernel fence support allows fences to have
strings for names, the sync framework uses the window name and buffer index
that is being queued to name the fence, for example:
<p>This is helpful in debugging to identify the source of a deadlock. Those
names appear in the output of <code>/d/sync</code> and bug reports when
<h5 id=anativewindow_integration>ANativeWindow integration</h5>
<p>ANativeWindow is fence aware. <code>dequeueBuffer</code>,
<code>queueBuffer</code>, and <code>cancelBuffer</code> have fence
<h5 id=opengl_es_integration>OpenGL ES integration</h5>
<p>OpenGL ES sync integration relies upon these two EGL extensions:</p>
<ul> <li> <code>EGL_ANDROID_native_fence_sync</code> - provides a way to either
wrap or create native Android fence file descriptors in EGLSyncKHR objects.
<li> <code>EGL_ANDROID_wait_sync</code> - allows GPU-side stalls rather than in
CPU, making the GPU wait for an EGLSyncKHR. This is essentially the same as the
<code>EGL_KHR_wait_sync</code> extension. See the
<code>EGL_KHR_wait_sync</code> specification for details. </ul>
<p>These extensions can be used independently and are controlled by a compile
flag in libgui. To use them, first implement the
<code>EGL_ANDROID_native_fence_sync</code> extension along with the associated
kernel support. Next add a ANativeWindow support for fences to your driver and
then turn on support in libgui to make use of the
<code>EGL_ANDROID_native_fence_sync</code> extension.</p>
<p>Then, as a second pass, enable the <code>EGL_ANDROID_wait_sync</code>
extension in your driver and turn it on separately. The
<code>EGL_ANDROID_native_fence_sync</code> extension consists of a distinct
native fence EGLSync object type so extensions that apply to existing EGLSync
object types dont necessarily apply to <code>EGL_ANDROID_native_fence</code>
objects to avoid unwanted interactions.</p>
<p>The EGL_ANDROID_native_fence_sync extension employs a corresponding native
fence file descriptor attribute that can be set only at creation time and
cannot be directly queried onward from an existing sync object. This attribute
can be set to one of two modes:</p>
<ul> <li> A valid fence file descriptor - wraps an existing native Android
fence file descriptor in an EGLSyncKHR object. <li> -1 - creates a native
Android fence file descriptor from an EGLSyncKHR object. </ul>
<p>The DupNativeFenceFD function call is used to extract the EGLSyncKHR object
from the native Android fence file descriptor. This has the same result as
querying the attribute that was set but adheres to the convention that the
recipient closes the fence (hence the duplicate operation). Finally, destroying
the EGLSync object should close the internal fence attribute.</p>
<h5 id=hardware_composer_integration>Hardware Composer integration</h5>
<p>Hardware Composer handles three types of sync fences:</p>
<ul> <li> <em>Acquire fence</em> - one per layer, this is set before calling
HWC::set. It signals when Hardware Composer may read the buffer. <li>
<em>Release fence</em> - one per layer, this is filled in by the driver in
HWC::set. It signals when Hardware Composer is done reading the buffer so the
framework can start using that buffer again for that particular layer. <li>
<em>Retire fence</em> - one per the entire frame, this is filled in by the
driver each time HWC::set is called. This covers all of the layers for the set
operation. It signals to the framework when all of the effects of this set
operation has completed. The retire fence signals when the next set operation
takes place on the screen. </ul>
<p>The retire fence can be used to determine how long each frame appears on the
screen. This is useful in identifying the location and source of delays, such
as a stuttering animation. </p>
<h4 id=vsync_offset>VSYNC Offset</h4>
<p>Application and SurfaceFlinger render loops should be synchronized to the
hardware VSYNC. On a VSYNC event, the display begins showing frame N while
SurfaceFlinger begins compositing windows for frame N+1. The app handles
pending input and generates frame N+2.</p>
<p>Synchronizing with VSYNC delivers consistent latency. It reduces errors in
apps and SurfaceFlinger and the drifting of displays in and out of phase with
each other. This, however, does assume application and SurfaceFlinger per-frame
times dont vary widely. Nevertheless, the latency is at least two frames.</p>
<p>To remedy this, you may employ VSYNC offsets to reduce the input-to-display
latency by making application and composition signal relative to hardware
VSYNC. This is possible because application plus composition usually takes less
than 33 ms.</p>
<p>The result of VSYNC offset is three signals with same period, offset
<ul> <li> <em>HW_VSYNC_0</em> - Display begins showing next frame <li>
<em>VSYNC</em> - App reads input and generates next frame <li> <em>SF
VSYNC</em> - SurfaceFlinger begins compositing for next frame </ul>
<p>With VSYNC offset, SurfaceFlinger receives the buffer and composites the
frame, while the application processes the input and renders the frame, all
within a single frame of time.</p>
<p>Please note, VSYNC offsets reduce the time available for app and composition
and therefore provide a greater chance for error.</p>
<h5 id=dispsync>DispSync</h5>
<p>DispSync maintains a model of the periodic hardware-based VSYNC events of a
display and uses that model to execute periodic callbacks at specific phase
offsets from the hardware VSYNC events.</p>
<p>DispSync is essentially a software phase lock loop (PLL) that generates the
VSYNC and SF VSYNC signals used by Choreographer and SurfaceFlinger, even if
not offset from hardware VSYNC.</p>
<img src="images/dispsync.png" alt="DispSync flow">
<p class="img-caption"><strong>Figure 4.</strong> DispSync flow</p>
<p>DispSync has these qualities:</p>
<ul> <li> <em>Reference</em> - HW_VSYNC_0 <li> <em>Output</em> - VSYNC and SF
VSYNC <li> <em>Feedback</em> - Retire fence signal timestamps from Hardware
Composer </ul>
<h5 id=vsync_retire_offset>VSYNC/Retire Offset</h5>
<p>The signal timestamp of retire fences must match HW VSYNC even on devices
that dont use the offset phase. Otherwise, errors appear to have greater
severity than reality.</p>
<p>Smart panels often have a delta. Retire fence is the end of direct memory
access (DMA) to display memory. The actual display switch and HW VSYNC is some
time later.</p>
<p><code>PRESENT_TIME_OFFSET_FROM_VSYNC_NS</code> is set in the devices make file. It is based upon the display controller and panel
characteristics. Time from retire fence timestamp to HW Vsync signal is
measured in nanoseconds.</p>
<h5 id=vsync_and_sf_vsync_offsets>VSYNC and SF_VSYNC Offsets</h5>
<p>The <code>VSYNC_EVENT_PHASE_OFFSET_NS</code> and
<code>SF_VSYNC_EVENT_PHASE_OFFSET_NS</code> are set conservatively based on
high-load use cases, such as partial GPU composition during window transition
or Chrome scrolling through a webpage containing animations. These offsets
allow for long application render time and long GPU composition time.</p>
<p>More than a millisecond or two of latency is noticeable. We recommend
integrating thorough automated error testing to minimize latency without
significantly increasing error counts.</p>
<p>Note these offsets are also set in the devices make file.
The default if not set is zero offset. Both settings are offset in nanoseconds
after HW_VSYNC_0. Either can be negative.</p>
<h3 id=virtual_displays>Virtual displays</h3>
<p>Android added support for virtual displays to Hardware Composer in version
1.3. This support was implemented in the Android platform and can be used by
<p>The virtual display composition is similar to the physical display: Input
layers are described in prepare(), SurfaceFlinger conducts GPU composition, and
layers and GPU framebuffer are provided to Hardware Composer in set().</p>
<p>Instead of the output going to the screen, it is sent to a gralloc buffer.
Hardware Composer writes output to a buffer and provides the completion fence.
The buffer is sent to an arbitrary consumer: video encoder, GPU, CPU, etc.
Virtual displays can use 2D/blitter or overlays if the display pipeline can
write to memory.</p>
<h4 id=modes>Modes</h4>
<p>Each frame is in one of three modes after prepare():</p>
<ul> <li> <em>GLES</em> - All layers composited by GPU. GPU writes directly to
the output buffer while Hardware Composer does nothing. This is equivalent to
virtual display composition with Hardware Composer <1.3. <li> <em>MIXED</em> -
GPU composites some layers to framebuffer, and Hardware Composer composites
framebuffer and remaining layers. GPU writes to scratch buffer (framebuffer).
Hardware Composer reads scratch buffer and writes to the output buffer. Buffers
may have different formats, e.g. RGBA and YCbCr. <li> <em>HWC</em> - All
layers composited by Hardware Composer. Hardware Composer writes directly to
the output buffer. </ul>
<h4 id=output_format>Output format</h4>
<p><em>MIXED and HWC modes</em>: If the consumer needs CPU access, the consumer
chooses the format. Otherwise, the format is IMPLEMENTATION_DEFINED. Gralloc
can choose best format based on usage flags. For example, choose a YCbCr format
if the consumer is video encoder, and Hardware Composer can write the format
<p><em>GLES mode</em>: EGL driver chooses output buffer format in
dequeueBuffer(), typically RGBA8888. The consumer must be able to accept this
<h4 id=egl_requirement>EGL requirement</h4>
<p>Hardware Composer 1.3 virtual displays require that eglSwapBuffers() does
not dequeue the next buffer immediately. Instead, it should defer dequeueing
the buffer until rendering begins. Otherwise, EGL always owns the next output
buffer. SurfaceFlinger cant get the output buffer for Hardware Composer in
MIXED/HWC mode. </p>
<p>If Hardware Composer always sends all virtual display layers to GPU, all
frames will be in GLES mode. Although it is not recommended, you may use this
method if you need to support Hardware Composer 1.3 for some other reason but
cant conduct virtual display composition.</p>
<h2 id=testing>Testing</h2>
<p>For benchmarking, we suggest following this flow by phase:</p>
<ul> <li> <em>Specification</em> - When initially specifying the device, such
as when using immature drivers, you should use predefined (fixed) clocks and
workloads to measure the frames per second rendered. This gives a clear view of
what the hardware is capable of doing. <li> <em>Development</em> - In the
development phase as drivers mature, you should use a fixed set of user actions
to measure the number of visible stutters (janks) in animations. <li>
<em>Production</em> - Once the device is ready for production and you want to
compare against competitors, you should increase the workload until stutters
increase. Determine if the current clock settings can keep up with the load.
This can help you identify where you might be able to slow the clocks and
reduce power use. </ul>
<p>For the specification phase, Android offers the Flatland tool to help derive
device capabilities. It can be found at:
<p>Flatland relies upon fixed clocks and shows the throughput that can be
achieved with composition-based workloads. It uses gralloc buffers to simulate
multiple window scenarios, filling in the window with GL and then measuring the
compositing. Please note, Flatland uses the synchronization framework to
measure time. So you must support the synchronization framework to readily use