Self-hosted OpenGL ES Development on ChromeOS?

This is a guest post by blu about developing OpenGL ES applications on Chrome OS.

Ever since I’ve been using a chromebook in developer mode as my daily notebook (can’t beat 10h-plus battery life on ~300EUR well-performing machines), I’ve been missing one thing ‒ OpenGL ES coding under ChromeOS.

My chromebook is more than well-equipped for GLES3 hardware-wise (verified via dual-booting to ArchLinux), and I always have up-to-date toolchains self-hosted under ChromeOS, thanks to an excellent package manager aptly named Chromebrew. And yet my coding-on-the-go under ChromeOS has been limited to console apps ‒ ChromeOS has strict limitations which include no X11 display manager, or any other industry-standard display manager that I’m aware of, and I don’t feel like dual-booting into ArchLinux too often ‒ ChromeOS has spoiled me with its fine-tuned performance. The no-display-manager limitation of ChromeOS is usually worked-around via Crouton but in my case Crouton would not help ‒ no 3D-hardware-accelerated support on ARM chromebooks. So in anticipation of Project Crostini landing on my Chromebook, I’ve decided to give ChromeOS ‘stock’ developer mode a self-hosted OpenGLES quick-n-dirty try.

A disclaimer before we start: ChromeOS does support Android apps as well as native apps in the browser in the form of PNaCl Native Modules ‒ natively-built sandboxed binaries, akin to ActiveX in the Internet Explorer of yesteryears.

Unfortunately there’s one problem with that ‒ you can’t code PNaCl apps natively on an Arm chromebook ‒ the SDK toolchain was not meant to work on armhf userspaces. And frankly, I’m not keen on PNaCl so I’d rather leave hacking armhf support into that as a last resort. So what are the other options for self-hosted OGL ES development?

A quick check under /usr/lib shows the presence of libdrm, libGLESv2 and libEGL ‒ basic prerequisites met! We need to find matching headers for the latter two of these libraries as we directly interact with them. Luckily, industry-standard APIs like EGL and GLESv2 guarantee backward compatibility, so we don’t need to precisely match the libraries versions, as long as we target older-or-same-version functionality. So let’s head over to and grab the headers for EGL 1.4 and GLES2 respectively.

First attempt to build basic EGL + GLES2 code under ChromeOS results in header EGL/eglplarform.h seeking to include X11 header Xlib.h ‒ bad move. Let’s patch that into something sensible for an X11-less unix:

Our simple code builds now! Here’s a glance at the link dependencies ‒ everything originating from /usr/local/lib was provided by Chromebrew packages:

But does the so-built code run to a satisfactory result?

From using EGL under ArchLinux on my Chromebook I know that one can request a ‘null-window’ drawing surface from ImgTech’s EGL stack (a version of which is used in ChromeOS as well), which produces a straight-forward full-screen output. Trying the same approach under ChromeOS fails at eglCreateWindowSurface() with a EGL_BAD_NATIVE_WINDOW run-time error ‒ oh well. At least that surface creation happens after we have already initialized a functioning EGL stack, so we could still check for useful bits of EGL info. A quick query for valid renderable configurations reveals that our EGL stack offers a bunch of configurations, so let’s pick one for our further experiments. We’ll just go with the first available ‒ EGL_CONFIG_ID 0x1 ‒ it does not have a z-buffer or stencil attachments, but appears to be an otherwise perfectly-good native-renderable config (config attributes listed):

With our optimistic ‘null-window’ surface approach failing with a run-time error, we have a simple option left ‒ off-screen rendering. So let’s change our original EGL API call requesting a ‘null-window’ surface into one requesting a PBuffer-based surface:

Clearly, we won’t be showing anything on screen, given we transitioned from a full-screen ‘null-window’ surface to an off-screen pbuffer, but hey, we will know if we can render!

Running our simple code with the above off-screen patch (passing a bunch of CLI params among which specifying EGL config_id 1 for a renderable, requesting 1000 frames of rendering, recording the last frame to a png and specifying screen geometry of 1Kx1K at a fictitious 60Hz) produces:

So we crashed the PVR GLES stack at teardown, but hey, our framegrab contains a perfectly valid tangent-space bump-mapped stone sphere, and the framerate results should be valid as well!

opengl ES chromeos

Not bad for 15 lines of patches over code never meant to build and run on ChromeOS. Next time I’ll try to figure out how to display rendering at run-time, if Project Crostini is not released soon, that is ; )

Share this:

Support CNX Software! Donate via cryptocurrencies or become a Patron on Patreon

ROCK Pi 4C Plus

Memfault Embedded Device Reliability Platform
Notify of
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.
Weller PCB manufacturer