1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
<!doctype html>
<html class="html-note-page" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Software Rendering and Android</title>
<meta name="dcterms.date" content="2024-06-27" />
<link rel="stylesheet" href="/assets/style.css">
<link rel="icon" type="image/x-icon" href="/assets/favicon.svg">
<link rel="icon" type="image/png" href="/assets/favicon.png">
<link rel="alternate" type="application/atom+xml" title="Fryzek Concepts" href="/feed.xml">
</head>
<body>
<div class="header-bar">
<a href="/index.html">
<img src="/assets/favicon.svg" alt="frycon logo">
</a>
<div class="header-links">
<a href="/about.html" class="header-link">About</a>
<a rel="me" href="https://mastodon.social/@hazematman" class="header-link">Social</a>
<a href="https://git.fryzekconcepts.com" class="header-link">Code</a>
</div>
</div>
<main>
<div class="page-title-header-container">
<h1 class="page-title-header">Software Rendering and Android</h1>
<div class="page-info-container">
<div class="plant-status">
<img src="/assets/evergreen.svg">
<div class="plant-status-text">
<p>evergreen</p>
</div>
</div>
<div class="page-info-date-container">
<p class="page-info-date">Published: 2024-06-27</p>
<p class="page-info-date">Last Edited: 2024-06-27</p>
</div>
</div>
</div>
<div class="note-divider"></div>
<div class="main-container">
<div class="note-body">
<p>My current project at Igalia has had me working on Mesa’s software
renderers, llvmpipe and lavapipe. I’ve been working to get them running
on Android, and I wanted to document the progress I’ve made, the
challenges I’ve faced, and talk a little bit about the development
process for a project like this. My work is not totally merged into
upstream mesa yet, but you can see the MRs I made here:</p>
<ul>
<li><a
href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29344">llvmpipe:
Add android platform integration</a></li>
<li><a
href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29785">u_gralloc/fallback:
Set fd from handle directly</a></li>
<li><a
href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27805">llvmpipe
& lavalpipe: Implement sync fd import/export extensions</a></li>
<li><a
href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28735">lavapipe:
Implement <code>VK_EXT_external_memory_dma_buf</code></a></li>
</ul>
<h2 id="setting-up-an-android-development-environment">Setting up an
Android development environment</h2>
<p>Getting system level software to build and run on Android is
unfortunately not straightforward. Since we are doing software rendering
we don’t need a physical device and instead we can make use of the
Android emulator, and if you didn’t know Android has two emulators, the
common one most people use is “goldfish” and the other lesser known is
“cuttlefish”. For this project I did my work on the cuttlefish emulator
as its meant for testing the Android OS itself instead of just Android
apps and is more reflective of real hardware. The cuttlefish emulator
takes a little bit more work to setup, and I’ve found that it only works
properly in Debian based linux distros. I run Fedora, so I had to run
the emulator in a debian VM.</p>
<p>Thankfully Google has good instructions for building and running
cuttlefish, which you can find <a
href="https://source.android.com/docs/devices/cuttlefish/get-started">here</a>.
The instructions show you how to setup the emulator using nightly build
images from Google. We’ll also need to setup our own Android OS images
so after we’ve confirmed we can run the emulator, we need to start
looking at building AOSP.</p>
<p>For building our own AOSP image, we can also follow the instructions
from Google <a
href="https://source.android.com/docs/setup/build/building">here</a>.
For the target we’ll want
<code>aosp_cf_x86_64_phone-trunk_staging-eng</code>. At this point it’s
a good idea to verify that you can build the image, which you can do by
following the rest of the instructions on the page. Building AOSP from
source does take a while though, so prepare to wait potentially an
entire day for the image to build. Also if you get errors complaining
that you’re out of memory, you can try to reduce the number of parallel
builds. Google officially recommends to have 64GB of RAM, and I only had
32GB so some packages had to be built with the parallel builds set to 1
so I wouldn’t run out of RAM.</p>
<p>For running this custom-built image on Cuttlefish, you can just copy
all the <code>*.img</code> files from
<code>out/target/product/vsoc_x86_64/</code> to the root cuttlefish
directory, and then launch cuttlefish. If everything worked successfully
you should be able to see your custom built AOSP image running in the
cuttlefish webui.</p>
<h2 id="building-mesa-targeting-android">Building Mesa targeting
Android</h2>
<p>Working from the changes in MR <a
href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29344">!29344</a>
building llvmpipe or lavapipe targeting Android should just work™️. To
get to that stage required a few changes. First llvmpipe actually
already had some support on Android, as long as it was running on a
device that supports a DRM display driver. In that case it could use the
<code>dri</code> window system integration which already works on
Android. I wanted to get llvmpipe (and lavapipe) running without dri, so
I had to add support for Android in the <code>drisw</code> window system
integration.</p>
<p>To support Android in <code>drisw</code>, this mainly meant adding
support for importing dmabuf as framebuffers. The Android windowing
system will provide us with a “gralloc” buffer which inside has a dmabuf
fd that represents the framebuffer. Adding support for importing dmabufs
in drisw means we can import and begin drawing to these frame buffers.
Most the changes to support that can be found in <a
href="https://gitlab.freedesktop.org/mesa/mesa/-/blob/9705df53408777d493eab19e5a58c432c1e75acb/src/gallium/frontends/dri/drisw.c#L405"><code>drisw_allocate_textures</code></a>
and the underlying changes to llvmpipe to support importing dmabufs in
MR <a
href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27805">!27805</a>.
The EGL Android platform code also needed some changes to use the
<code>drisw</code> window system code. Previously this code would only
work with true dri drivers, but with some small tweaks it was possible
to get to have it initialize the drisw window system and then using it
for rendering if no hardware devices are available.</p>
<p>For lavapipe the changes were a lot simpler. The Android Vulkan
loader requires your driver to have <code>HAL_MODULE_INFO_SYM</code>
symbol in the binary, so that got created and populated correctly,
following other Vulkan drivers in Mesa like turnip. Then the image
creation code had to be modified to support the
<code>VK_ANDROID_native_buffer</code> extension which allows the Android
Vulkan loader to create images using Android native buffer handles.
Under the hood this means getting the dmabuf fd from the native buffer
handle. Thankfully mesa already has some common code to handle this, so
I could just use that. Some other small changes were also necessary to
address crashes and other failures that came up during testing.</p>
<p>With the changes out of of the way we can now start building Mesa on
Android. For this project I had to update the Android documentation for
Mesa to include steps for building LLVM for Android since the version
Google ships with the NDK is missing libraries that llvmpipe/lavapipe
need to function. You can see the updated documentation <a
href="https://gitlab.freedesktop.org/mesa/mesa/-/blob/9705df53408777d493eab19e5a58c432c1e75acb/docs/drivers/llvmpipe.rst">here</a>
and <a
href="https://gitlab.freedesktop.org/mesa/mesa/-/blob/9705df53408777d493eab19e5a58c432c1e75acb/docs/android.rst">here</a>.
After sorting out LLVM, building llvmpipe/lavapipe is the same as
building any other Mesa driver for Android: we setup a cross file to
tell meson how to cross compile and then we run meson. At this point you
could manual modify the Android image and copy these files to the vm,
but I also wanted to support building a new AOSP image directly
including the driver. In order to do that you also have to rename the
driver binaries to match Android’s naming convention, and make sure
SO_NAME matches as well. If you check out <a
href="https://gitlab.freedesktop.org/mesa/mesa/-/blob/9705df53408777d493eab19e5a58c432c1e75acb/docs/android.rst?plain=1#L183">this</a>
section of the documentation I wrote, it covers how to do that.</p>
<p>If you followed all of that you should have built an version of
llvmpipe and lavapipe that you can run on Android’s cuttlefish
emulator.</p>
<figure>
<img src="/assets/2024-06-27-android-swrast/lavapipe.png"
alt="Android running lavapipe" />
<figcaption aria-hidden="true">Android running lavapipe</figcaption>
</figure>
<h2 id="references">References</h2>
<ul>
<li><a
href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29344"
class="uri">https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29344</a>
<ul>
<li>Main MR with Android changes</li>
</ul></li>
<li><a
href="https://source.android.com/docs/devices/cuttlefish/get-started"
class="uri">https://source.android.com/docs/devices/cuttlefish/get-started</a>
<ul>
<li>Google’s official guide for getting started with the Cuttlefish
emulator</li>
</ul></li>
<li><a href="https://source.android.com/docs/setup/build/building"
class="uri">https://source.android.com/docs/setup/build/building</a>
<ul>
<li>Google’s official guide for building AOSP images</li>
</ul></li>
<li><a
href="https://gitlab.freedesktop.org/mesa/mesa/-/blob/9705df53408777d493eab19e5a58c432c1e75acb/docs/drivers/llvmpipe.rst"
class="uri">https://gitlab.freedesktop.org/mesa/mesa/-/blob/9705df53408777d493eab19e5a58c432c1e75acb/docs/drivers/llvmpipe.rst</a>
<ul>
<li>My updated documentation in MR for llvmpipe</li>
</ul></li>
<li><a
href="https://gitlab.freedesktop.org/mesa/mesa/-/blob/9705df53408777d493eab19e5a58c432c1e75acb/docs/android.rst"
class="uri">https://gitlab.freedesktop.org/mesa/mesa/-/blob/9705df53408777d493eab19e5a58c432c1e75acb/docs/android.rst</a>
<ul>
<li>My updated documentation in MR for Android integration in mesa</li>
</ul></li>
</ul>
</div>
</div> </main>
</body>
</html>
|