9 Jun 2017

GPU Support with OpenEmbedded (etnaviv/vivante)

 Introduction

This series of articles assumes some familiarity with OpenEmbedded, but if you haven't used it before, hopefully you can follow along. If you've never used OpenEmbedded before and would like to give these build instructions a try, start off by reading and trying the examples in The Yocto Project's Quick Start Guide. Hopefully that will get you and your machine setup.

There are many SoCs that incorporate the Vivante GPU. I happen to have the Wandboard Dual, so that's the board I'll be using for my tests.

Build Setup

To begin an OpenEmbedded build (assuming your Linux build machine has all the necessary packages), we need to choose some place on our computer to which we have rwx access, and grab the necessary metadata. The first chunks of metadata contains all the base, generic things:

$ git clone git://git.openembedded.org/openembedded-core
$ git clone git://git.openembedded.org/meta-openembedded

Then we need to add BSP metadata. Most BSPs consist of one layer, but in the case of the Wandboard we need the generic freescale BSP layer (meta-freescale) and the BSP that specifically supports the Wandboard (meta-freescale-3rdparty). The Wandboard has an i.MX6 SoC on it which was made by Freescale. In 2015 NXP merged with Freescale. Although the i.MX6 is, technically, an NXP SoC, the layer retains the "freescale" name.

$ git clone https://git.yoctoproject.org/git/meta-freescale
$ git clone https://github.com/Freescale/meta-freescale-3rdparty

How did I possibly know I needed those two layers? By consulting the layer index. The layer index is where layer maintainers go to make their layers known, and it's a great place for users to go to find support machines, software, distros, etc. If you're not working with the Wandboard, then you'll need to consult the layer index to figure out which layers you need for your specific hardware.

Now we need the tool that uses all this metadata and actually performs the build:

$ git clone  git://git.openembedded.org/bitbake

Now that we have all the pieces in place, we setup our shell

$ . openembedded-core/oe-init-build-env build bitbake/
You had no conf/local.conf file. This configuration file has therefore been
created for you with some default values. You may wish to edit it to, for
example, select a different MACHINE (target hardware). See conf/local.conf
for more information as common configuration options are commented.

You had no conf/bblayers.conf file. This configuration file has therefore been
created for you with some default values. To add additional metadata layers
into your configuration please add entries to conf/bblayers.conf.

The Yocto Project has extensive documentation about OE including a reference
manual which can be found at:
    http://yoctoproject.org/documentation

For more information about OpenEmbedded see their website:
    http://www.openembedded.org/


### Shell environment set up for builds. ###

You can now run 'bitbake <target>'

Common targets are:
    core-image-minimal
    core-image-sato
    meta-toolchain
    meta-ide-support

You can also run generated qemu images with a command like 'runqemu qemux86'

This creates the build directory ("build") that was specified on the shell setup line. Now we tell bitbake about our additional layers:

$ bitbake-layers add-layer ../meta-freescale
Parsing recipes: 100% |#########################################################| Time: 0:00:12
Parsing of 925 .bb files complete (0 cached, 925 parsed). 1408 targets, 149 skipped, 0 masked, 0 errors.
$ bitbake-layers add-layer ../meta-freescale-3rdparty
Parsing recipes: 100% |#########################################################| Time: 0:00:07
Parsing of 962 .bb files complete (0 cached, 962 parsed). 1445 targets, 185 skipped, 0 masked, 0 errors.
$ bitbake-layers add-layer ../meta-openembedded/meta-oe
Parsing recipes: 100% |#########################################################| Time: 0:00:13
Parsing of 1614 .bb files complete (0 cached, 1614 parsed). 2226 targets, 265 skipped, 0 masked, 0 errors.

Vivante Build

 By default, the "freescale" BSP layers assume the user wants to build an image using the vivante binary blob. This blob isn't "free", so in order to use it, you have to agree to its EULA. To do that, you have to read the "EULA" file you'll find at the top-level of the meta-freescale BSP that was cloned earlier. Once you've read that file and agreed to it, you can proceed with this build. If you don't or can't agree to the EULA, then you can proceed directly to the Etnaviv build.

When you setup your shell, earlier, it created a boilerplate configuration file for you. From the "build" directory that was created for you during setup, open the conf/local.conf file with your favourite text editor and add the following lines at the top (be sure to leave the rest of the file as-is!):

ACCEPT_FSL_EULA = "1"
CORE_IMAGE_EXTRA_INSTALL += "openbox glmark2"
DISTRO_FEATURES_append = " opengl x11"
IMAGE_FEATURES += "x11"

Once that's done you can run your build:

$ MACHINE=wandboard bitbake core-image-full-cmdline
Parsing recipes: 100% |#########################################################| Time: 0:00:14
Parsing of 1614 .bb files complete (0 cached, 1614 parsed). 2226 targets, 249 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION        = "1.34.0"
BUILD_SYS         = "x86_64-linux"
NATIVELSBSTRING   = "opensuse-42.2"
TARGET_SYS        = "arm-oe-linux-gnueabi"
MACHINE           = "wandboard"
DISTRO            = "nodistro"
DISTRO_VERSION    = "nodistro.0"
TUNE_FEATURES     = "arm armv7a vfp thumb neon callconvention-hard cortexa9"
TARGET_FPU        = "hard"
meta              = "master:186882ca62bf683b93cd7a250963921b89ba071f"
meta-freescale    = "master:98d57b06d88cb22129bd417a9a3edbaf24612460"
meta-freescale-3rdparty = "master:fd3962a994b2f477d3e81fa7083f6b3d4e666df5"
meta-oe           = "master:41cf832cc9abd6f2293a6d612463a34a53a9a52a"

Initialising tasks: 100% |######################################################| Time: 0:00:04
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 4369 tasks of which 2317 didn't need to be rerun and all succeeded.

From this successful build we'll find our device image located at:

tmp-glibc/deploy/images/wandboard/core-image-full-cmdline-wandboard.wic.gz

If you unzip this wic file, it can be dd'ed directly to a microSD card, this microSD card can be inserted into the Wandboard, which can then be powered up.

$ gzip -d < tmp-glibc/deploy/images/wandboard/core-image-full-cmdline-wandboard.wic.gz > core-image-full-cmdline-wandboard.wic
$ su
Password:
# dd if=core-image-full-cmdline-wandboard.wic of=/dev/sdi bs=10M
21+1 records in
21+1 records out
222298112 bytes (222 MB, 212 MiB) copied, 85.6691 s, 2.6 MB/s

I like to interact with embedded boards via a serial console. On the Wandboard, this means using a DE-9 serial cable. Once the board boots up I login and run the benchmark application:

OpenEmbedded nodistro.0 wandboard /dev/ttymxc0

wandboard login: D-BUS per-session daemon address is: unix:abstract=/tmp/dbus-fd5NI0apUa,guid=772b87be1cee0f1d2acde6c25938e674
Using calibration data stored in /etc/pointercal.xinput
Invalid format 42060
unable to find device EETI eGalax Touch Screen
INFO: width=1920, height=1080
Obt-Message: Failed to open an Input Method
Openbox-Message: X server does not support locale.
Openbox-Message: Cannot set locale modifiers for the X server.

root
root@wandboard:~# uname -a
Linux wandboard 4.1.15-1.1.0-ga-wandboard+g8b015473d340 #1 SMP PREEMPT Wed Jun 7 23:42:49 EDT 2017 armv7l armv7l armv7l GNU/Linux
root@wandboard:~# export DISPLAY=:0
root@wandboard:~# glmark2-es2
=======================================================
    glmark2 2014.03
=======================================================
    OpenGL Information
    GL_VENDOR:     Vivante Corporation
    GL_RENDERER:   Vivante GC880
    GL_VERSION:    OpenGL ES 3.0 V5.0.11.p8.41671
=======================================================
[build] use-vbo=false: FPS: 206 FrameTime: 4.854 ms
[build] use-vbo=true: FPS: 246 FrameTime: 4.065 ms
[texture] texture-filter=nearest: FPS: 200 FrameTime: 5.000 ms
[texture] texture-filter=linear: FPS: 200 FrameTime: 5.000 ms
[texture] texture-filter=mipmap: FPS: 199 FrameTime: 5.025 ms
[shading] shading=gouraud: FPS: 205 FrameTime: 4.878 ms
[shading] shading=blinn-phong-inf: FPS: 170 FrameTime: 5.882 ms
[shading] shading=phong: FPS: 108 FrameTime: 9.259 ms
[shading] shading=cel: FPS: 81 FrameTime: 12.346 ms
[bump] bump-render=high-poly: FPS: 124 FrameTime: 8.065 ms
[bump] bump-render=normals: FPS: 220 FrameTime: 4.545 ms
[bump] bump-render=height: FPS: 203 FrameTime: 4.926 ms
libpng warning: iCCP: known incorrect sRGB profile
[effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 62 FrameTime: 16.129 ms
libpng warning: iCCP: known incorrect sRGB profile
[effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 23 FrameTime: 43.478 ms
[pulsar] light=false:quads=5:texture=false: FPS: 183 FrameTime: 5.464 ms
libpng warning: iCCP: known incorrect sRGB profile
[desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 31 FrameTime: 32.258 ms
libpng warning: iCCP: known incorrect sRGB profile
[desktop] effect=shadow:windows=4: FPS: 103 FrameTime: 9.709 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 49 FrameTime: 20.408 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 49 FrameTime: 20.408 ms
[buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 57 FrameTime: 17.544 ms
[ideas] speed=duration: FPS: 44 FrameTime: 22.727 ms
[jellyfish] <default>: FPS: 61 FrameTime: 16.393 ms
[terrain] <default>: FPS: 1 FrameTime: 1000.000 ms
[shadow] <default>: FPS: 92 FrameTime: 10.870 ms
[refract] <default>: FPS: 20 FrameTime: 50.000 ms
[conditionals] fragment-steps=0:vertex-steps=0: FPS: 209 FrameTime: 4.785 ms
[conditionals] fragment-steps=5:vertex-steps=0: FPS: 61 FrameTime: 16.393 ms
[conditionals] fragment-steps=0:vertex-steps=5: FPS: 203 FrameTime: 4.926 ms
[function] fragment-complexity=low:fragment-steps=5: FPS: 114 FrameTime: 8.772 ms
[function] fragment-complexity=medium:fragment-steps=5: FPS: 34 FrameTime: 29.412 ms
[loop] fragment-loop=false:fragment-steps=5:vertex-steps=5: FPS: 105 FrameTime: 9.524 ms
[loop] fragment-steps=5:fragment-uniform=false:vertex-steps=5: FPS: 105 FrameTime: 9.524 ms
[loop] fragment-steps=5:fragment-uniform=true:vertex-steps=5: FPS: 55 FrameTime: 18.182 ms
=======================================================
                                  glmark2 Score: 115
=======================================================

Some of the relevant packages in this build include:
  • libegl-mesa_2:17.1.1
  • libgles2-mesa_2:17.1.1
  • libgl-mesa_2:17.1.1
  • xserver-xorg_2:1.19.3
  • kernel-4.1.15-1.1.0-ga-wandboard+g8b015473d340
  • libc6_2.25
  • glmark2_2014.03+0+7215c0f337
  • cross-compiler: gcc-6.3.0

Etnaviv Build

Switching to a build that uses etnaviv isn't very hard. Keeping the bottom part of the configuration file as it was found, modify the top of conf/local.conf so that it looks like:

MACHINEOVERRIDES .= ":use-mainline-bsp"
CORE_IMAGE_EXTRA_INSTALL += "openbox glmark2"
DISTRO_FEATURES_append = " opengl x11"
IMAGE_FEATURES += "x11"

Since you're no longer using the binary blob, agreeing to the EULA is no longer required. Telling the build you want to switch to more "upstream" components is just a matter of adding the MACHINEOVERRIDES line.

Building:

$ MACHINE=wandboard bitbake core-image-full-cmdline
Parsing recipes: 100% |#########################################################| Time: 0:00:17
Parsing of 1614 .bb files complete (0 cached, 1614 parsed). 2226 targets, 265 skipped, 0 masked, 0 errors.
NOTE: There are 199 recipes to be removed from sysroot wandboard, removing...
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION        = "1.34.0"
BUILD_SYS         = "x86_64-linux"
NATIVELSBSTRING   = "opensuse-42.2"
TARGET_SYS        = "arm-oe-linux-gnueabi"
MACHINE           = "wandboard"
DISTRO            = "nodistro"
DISTRO_VERSION    = "nodistro.0"
TUNE_FEATURES     = "arm armv7a vfp thumb neon callconvention-hard"
TARGET_FPU        = "hard"
meta              = "master:186882ca62bf683b93cd7a250963921b89ba071f"
meta-freescale    = "master:98d57b06d88cb22129bd417a9a3edbaf24612460"
meta-freescale-3rdparty = "master:fd3962a994b2f477d3e81fa7083f6b3d4e666df5"
meta-oe           = "master:41cf832cc9abd6f2293a6d612463a34a53a9a52a"

Initialising tasks: 100% |######################################################| Time: 0:00:07
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 4396 tasks of which 1407 didn't need to be rerun and all succeeded.

Unpack the wic file, dd it to a microSD card, and boot it up on the Wandboard:

OpenEmbedded nodistro.0 wandboard /dev/ttymxc0

wandboard login: Error: No calibratable devices found.
Obt-Message: Failed to open an Input Method
Openbox-Message: X server does not support locale.
Openbox-Message: Cannot set locale modifiers for the X server.

root
root@wandboard:~# uname -a
Linux wandboard 4.9.21-fslc+gb69ecd63c123 #1 SMP Thu Jun 8 02:34:26 EDT 2017 armv7l armv7l armv7l GNU/Linux
root@wandboard:~#
export DISPLAY=:0
root@wandboard:~# glmark2-es2
=======================================================
    glmark2 2014.03
=======================================================
    OpenGL Information
    GL_VENDOR:     etnaviv
    GL_RENDERER:   Gallium 0.4 on Vivante GC880 rev 5106
    GL_VERSION:    OpenGL ES 2.0 Mesa 17.1.1
=======================================================
[build] use-vbo=false: FPS: 81 FrameTime: 12.346 ms
[build] use-vbo=true:[   59.956033] random: crng init done
 FPS: 91 FrameTime: 10.989 ms
[texture] texture-filter=nearest: FPS: 80 FrameTime: 12.500 ms
[texture] texture-filter=linear: FPS: 78 FrameTime: 12.821 ms
[texture] texture-filter=mipmap: FPS: 75 FrameTime: 13.333 ms
[shading] shading=gouraud: FPS: 87 FrameTime: 11.494 ms
[shading] shading=blinn-phong-inf: FPS: 68 FrameTime: 14.706 ms
[shading] shading=phong: FPS: 51 FrameTime: 19.608 ms
[shading] shading=cel: FPS: 42 FrameTime: 23.810 ms
[bump] bump-render=high-poly: FPS: 57 FrameTime: 17.544 ms
[bump] bump-render=normals: FPS: 74 FrameTime: 13.514 ms
[bump] bump-render=height: FPS: 66 FrameTime: 15.152 ms
libpng warning: iCCP: known incorrect sRGB profile
[effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 34 FrameTime: 29.412 ms
libpng warning: iCCP: known incorrect sRGB profile
[effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 14 FrameTime: 71.429 ms
[pulsar] light=false:quads=5:texture=false: FPS: 75 FrameTime: 13.333 ms
libpng warning: iCCP: known incorrect sRGB profile
[desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 15 FrameTime: 66.667 ms
libpng warning: iCCP: known incorrect sRGB profile
[desktop] effect=shadow:windows=4: FPS: 42 FrameTime: 23.810 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 30 FrameTime: 33.333 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 29 FrameTime: 34.483 ms
[buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 34 FrameTime: 29.412 ms
[ideas] speed=duration:[  253.131165] etnaviv-gpu 130000.gpu: hangcheck detected gpu lockup!
[  253.137434] etnaviv-gpu 130000.gpu:      completed fence: 11419
[  253.143413] etnaviv-gpu 130000.gpu:      active fence: 11420
[  253.150061] etnaviv-gpu 130000.gpu: hangcheck recover!
[  257.691146] etnaviv-gpu 130000.gpu: hangcheck detected gpu lockup!
[  257.697403] etnaviv-gpu 130000.gpu:      completed fence: 11420
[  257.703374] etnaviv-gpu 130000.gpu:      active fence: 11421
[  257.709247] etnaviv-gpu 130000.gpu: hangcheck recover!
[  263.931124] etnaviv-gpu 130000.gpu: hangcheck detected gpu lockup!
[  263.937380] etnaviv-gpu 130000.gpu:      completed fence: 11423
[  263.943352] etnaviv-gpu 130000.gpu:      active fence: 11425
[  263.949221] etnaviv-gpu 130000.gpu: hangcheck recover!
[  269.131129] etnaviv-gpu 130000.gpu: hangcheck detected gpu lockup!
[  269.137383] etnaviv-gpu 130000.gpu:      completed fence: 11425
[  269.143355] etnaviv-gpu 130000.gpu:      active fence: 11427
[  269.149324] etnaviv-gpu 130000.gpu: hangcheck recover!
 FPS: 0 FrameTime: inf ms
[jellyfish] <default>: FPS: 29 FrameTime: 34.483 ms
[terrain] <default>:error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!

etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
error: compile failed!
etna_draw_vbo:199: compiled shaders are not okay
 FPS: 2 FrameTime: 500.000 ms
[shadow] <default>: FPS: 39 FrameTime: 25.641 ms
[refract] <default>: FPS: 10 FrameTime: 100.000 ms
[conditionals] fragment-steps=0:vertex-steps=0: FPS: 70 FrameTime: 14.286 ms
[conditionals] fragment-steps=5:vertex-steps=0: FPS: 33 FrameTime: 30.303 ms
[conditionals] fragment-steps=0:vertex-steps=5: FPS: 65 FrameTime: 15.385 ms
[function] fragment-complexity=low:fragment-steps=5: FPS: 50 FrameTime: 20.000 ms
[function] fragment-complexity=medium:fragment-steps=5: FPS: 30 FrameTime: 33.333 ms
[loop] fragment-loop=false:fragment-steps=5:vertex-steps=5: FPS: 49 FrameTime: 20.408 ms
[loop] fragment-steps=5:fragment-uniform=false:vertex-steps=5: FPS: 49 FrameTime: 20.408 ms
[loop] fragment-steps=5:fragment-uniform=true:vertex-steps=5: FPS: 30 FrameTime: 33.333 ms
=======================================================
                                  glmark2 Score: 47
=======================================================

Some of the relevant packages in this build include:
  • libegl-mesa_2:17.1.1
  • libgles2-mesa_2:17.1.1
  • libgl-mesa_2:17.1.1
  • xserver-xorg_2:1.19.3
  • kernel-image-4.9.21-fslc
  • libc6_2.25
  • glmark2_2014.03+0+7215c0f337
  • cross-compiler: gcc-6.3.0

Results

My test currently consists of running glmark2-es2 (i.e. the OpenGL ES2 version of glmark2). As of today, the etnaviv support isn't as full-featured as the binary blob. However, using etnaviv doesn't require any EULAs, and it lets you use a newer kernel. Thanks to how well the freescale layers are organized/maintained, switching between the two builds is quite easy.

Here's a side-by-side comparison:

vivanteetnaviv
GL_VENDORVivante Corporationetnaviv
GL_RENDERERVivante GC880Gallium 0.4 on Vivante GC880 rev 5106
GL_VERSIONOpenGL ES 3.0 V5.0.11.p8.41671OpenGL ES 2.0 Mesa 17.1.1

glmark2(-es2) is a set of individual tests that are run back-to-back. They can be run individually, but calling "glmark2-es2" by itself simply invokes all of them sequentially.

vivanteetnaviv
glmark2-es2 score11547
[build]20681
[build]24691
[texture]20080
[texture]20078
[texture]19975
[shading]20587
[shading]17068
[shading]10851
[shading]8142
[bump]12457
[bump]22074
[bump]20366
[effect2d]6234
[effect2d]2314
[pulsar]18375
[desktop]3115
[desktop]10342
[buffer]4930
[buffer]4929
[buffer]5734
[ideas]44(hangcheck)
[jellyfish]6129
[terrain]12 (shader compile failed)
[shadow]9239
[refract]2010
[conditionals]20970
[conditionals]6133
[conditionals]20365
[function]11450
[function]3430
[loop]10549
[loop]10549
[loop]5530

2 comments:

  1. What resolution did you use in these runs? 1080p?

    ReplyDelete
    Replies
    1. I don't do anything to explicitly set the resolution, and it comes up at 1024x768.

      Delete