etnaviv is now OpenGL ES 3.0 conformant
etnaviv is the open source Mesa driver for Vivante GPUs, the GPUs found in most NXP i.MX chips. In September 2026, etnaviv passed the Khronos conformance test suite for OpenGL ES 3.0 on the NXP i.MX8M Plus and the NXP i.MX8M Quad: more than 235,000 tests with zero failures. So, we can proudly say that etnaviv is now a conformant OpenGL ES 3.0 driver on both System on Chips (SoCs).
tl;dr
Between May and October 2026, we landed more than 200 etnaviv commits in upstream Mesa. They turned a driver that reported OpenGL ES 2.0 on these boards into one that passes the full ES 3.0 conformance suite. Most of that work emulates hardware features that the GC7000UL in the i.MX8MP and the GC7000L in the i.MX8MQ do not have. The Vivante vendor driver on the same boards was the reference for all of them.
Our progress towards ES 3.0 was steady for years, but it gained a lot of speed this year thanks to the support of Mecha Systems. Their Mecha Comet, a modular handheld Linux computer, is built around the i.MX8M Plus, and they wanted a fully open graphics stack on it. Thank you, Mecha!
What the hardware is missing
The i.MX8MP and i.MX8MQ are popular chips, but their GPUs are not very big. Three limitations made ES 3.0 hard on both:
- No 128-bit pixel formats. The pixel engine stores at most 64 bits per pixel. ES 3.0 requires
RGBA32F,RGBA32IandRGBA32UIas render targets and textures. - No float depth. The depth buffer is 16-bit or 24-bit integer. ES 3.0 requires
DEPTH_COMPONENT32FandDEPTH32F_STENCIL8. - No transform feedback. There is no hardware unit that writes vertex shader outputs back to memory.
The two chips differ in one place. The i.MX8MQ has a BLT engine for copies, clears and resolves. The i.MX8MP does not, so the same work goes through the older and more limited RS engine, or through shaders. Those paths get far less testing, and the last bugs before conformance were all there.
128-bit color formats
etnaviv stores every 128-bit pixel as two 64-bit halves. Each render target gets a hidden companion target, and a NIR pass splits each color write into two 64-bit stores. On the sampling side, every 128-bit texture takes two texture descriptors, and the same pass merges the two fetches back into one value. This mirrors what the vendor driver does.
This design was simple enough, but the devil is in the (hardware) details. On one GPU revision, the color mask for these targets needs two bits per 32-bit word instead of one bit per channel. Getting that wrong was silently dropping the alpha channel. That one fix repaired 260 tests, 82 of them shader precision tests that looked like compiler bugs because they read their results back through 128-bit images.
32-bit float depth
Float depth is stored as 24-bit integer depth everywhere, exactly like the vendor driver. etnaviv converts on upload and read back through Mesa’s u_transfer_helper, and lowers shadow comparisons against float depth in the shader. The ES 3.0 specification allows this precision.
Transform feedback
Without hardware transform feedback, the vertex shader itself writes the captured outputs to memory. etnaviv adds store instructions to a dedicated shader variant, driven by a few uniforms for buffer addresses, strides and the vertex offset. The “primitives written” queries are computed on the CPU.
The worst bug here was not in the stores. The vertex shader works on vertices in batches, and the batch size was a constant copied from a bigger GPU. The vertex cache in the GC7000UL only fits 16 vertices per batch, and etnaviv asked for up to 136. Every vertex after number 24 silently went missing, but only when the fragment shader read many outputs. Now etnaviv derives the limit from the cache size reported by the kernel, like the vendor driver does.
Multisampling, texelFetch and the rest
ES 3.0 also brings multisample textures, texelFetch, integer textures, sRGB render targets and CLAMP_TO_BORDER. Each of these got its own round of fixes, and two are worth a mention:
- A GPU crash that looked like a wrong copy. Blit shaders can fetch one texel past the edge of an image. On an unmapped page the GPU faults, gets reset, and the next test reads back the picture of the test before. etnaviv now clamps
texelFetchcoordinates. - Antialiased images shifted by 32 pixels. The first full conformance run failed more than 2,000 multisample tests. The RS resolve scaled the region size for the sample count, but not its offset. That code was from 2017.
And the single most effective change was one line: etnaviv never told Mesa which GLSL version it supports, so Mesa quietly capped the driver at ES 2.0.
How we narrowed the bugs
Almost every fix above came from the same method: a second board with the same GPU runs the closed source vendor driver. If it passes a test and etnaviv does not, the bug is ours. Record the command streams of both drivers, diff them, and the answer is usually in there.
What comes next
Conformance is just the beginning. The next round of work is performance: fewer CPU cycles per draw, no stalls on busy buffers, and better tracing to determine where time goes. The first of these commits are already in Mesa 26.3. The i.MX8QuadMax is next in line for conformance. Its GC7000XSVX has hardware transform feedback, so it exercises the native paths the two conformant chips haven’t touched. After that, OpenGL ES 3.1.