bitdrift
PricingDocs

episode 17 | June 16 2026

Inside the Renderer: Android's Graphics Story With Romain Guy

Inside the Renderer: Android's Graphics Story With Romain Guy

Inside the Renderer: Android's Graphics Story With Romain Guy

Beyond the Noise

About the episode

In this episode of Beyond the Noise, Matt talks with Romain Guy, who spent 18 years as an engineer and engineering leader at Google on Android, joining when the team was around 40 people and the product was still a secret internal project.

Romain walks through the technical reality of those early days: a VM with no JIT compiler, stop-the-world garbage collection, and a UI toolkit with no GPU acceleration. The conversation covers the bandwidth ceiling that forced Android's UI toolkit onto the GPU, the surprising complexity of text rendering, and the tradeoff behind Jetpack Compose sharing a rendering layer with the old View system.

From the pain of Java Native Interface (JNI) to building Filament, a 3D rendering engine now powering Android XR headsets, the episode shows that performance is less about benchmarking and more about the mindset you bring to every decision.

Matt Klein: Welcome to another episode of Beyond the Noise: Signals, Stories, and Spicy Takes, the show where we dig into the stories of the people shaping the future of app-based computing, with a special focus on mobile. I'm your host, Matt Klein, co-founder and CTO of bitdrift, as well as the creator of Envoy Proxy. Each episode we'll talk with engineers, founders, and technical leaders who've transformed the way their companies build and understand what's happening inside their systems. We'll dig into the challenges, the breakthroughs, the lessons learned, and we'll wrap it all up with their hottest takes. So let's dive in.

Matt Klein: Today I'm thrilled to have Romain Guy, who worked on Android at Google for 18 years, nearly the entire history of the product, as both an engineer and engineering leader. He focused on graphics, performance optimization, and a great deal more. Thank you so much for joining us, Romain.

Romain Guy: Thank you for having me. I'm very excited for this conversation. I must say I'm a little jealous of your podcast voice. I've listened to a lot of podcasts, and I do not sound like that.

Matt Klein: It's all pretend. I'm a pretend podcaster.Romain Guy: Well, you've clearly worked at it. Maybe I should do that someday.

[00:01:20] GETTING INTO MOBILE AND JOINING ANDROID

Matt Klein: You've had such a remarkable career. I'd love to start at the beginning. How did you get into mobile, and how did you end up on Android?

Romain Guy: I joined Android in 2007. It was still a secret project internally at Google at the time. Interestingly, I'd done a lot of mobile work before that, mostly as a hobby. Android was technically my first full-time job out of school, but in the years prior I had both a genuine passion for it and a practical reason to explore it: I was writing articles about programming every month for French computing magazines. I was always looking for interesting topics to cover.

Romain Guy: So at the tail end of the nineties and into the early 2000s, I learned Palm PDA development, how to write games for the Game Boy Advance, J2ME, Java Card, Java rings. I touched a lot of random things on mobile platforms. It was always fascinating to be able to build something you could carry in your pocket. I remember being on a ski trip with friends in the early 2000s, uploading photos from my phone directly to my blog via WAP. Nobody around me had any idea what I was talking about, but it felt like the future.

Romain Guy: When the opportunity to work on Android came along, it was hard to say no. The way it happened was that someone reached out about an internship. There were people on the Android team who knew me from open source work in the Java world, and they said: "Trust us, we can't tell you what it is, but you're going to love it. Just come." And that turned out to be exactly the right call.

Matt Klein: Had you already moved to the US at that point, or did you relocate for Android?

Romain Guy: I'd spent time in the US before. I did an internship at Sun Microsystems one summer to work on the JDK, and I loved it so much that I called my school in France and told them I'd be back in a year. I stayed the full year, went back to finish my last year, then returned for another internship at Google. During that internship I was working on Android, and I also met my wife. At the end of the summer when they asked if I'd like to stay, the answer was pretty easy.

[00:03:54] BUILDING AN OPERATING SYSTEM: LESSONS FROM THE EARLY DAYS

Matt Klein: I'd love to hear more about what it was like to work on a pre-release product, especially one tied to hardware. A lot of software engineers are used to being able to fix bugs after the fact, but when you're shipping a phone, some problems can't wait. What was that like?

Romain Guy: There were a couple of releases where the marching order was essentially: as long as we can boot to the launcher and take an update, we'll be fine. That tells you something about the urgency.

Romain Guy: Working on an operating system is interesting for a lot of reasons. One of the first things you realize is that an OS is really just a very large application. There's no dark magic anywhere. Some parts are complicated, sure, but once you're inside it, it's more complexity in terms of the number of processes and services, not some fundamentally different kind of engineering.

Romain Guy: What made the early Android experience especially valuable was the size of the team. When I joined, I think there were around 40 people total, not just engineers but everyone. And the people I was working alongside had shipped the Xbox, BeOS, Palm OS, WebTV. They were all veterans of operating systems. Coming straight out of school, I had no idea how lucky I was. I just assumed that was what corporate life was like. You start emulating the people around you and it raises your floor dramatically.

Romain Guy: One of the most important skills I developed, though it took me years to recognize it, was knowing which shortcuts you can take and which ones you absolutely cannot. When you're building a platform with public APIs, there are things you cannot change later for compatibility reasons. But there are also architectural decisions you can swap out mid-flight, and Android has done that many times without anyone noticing. There's no formula for knowing the difference. It just takes experience.

Matt Klein: That resonates a lot. I consider myself pretty pragmatic. Taking shortcuts is fine as long as you're honest with yourself about whether you'll be able to fix them later.

Romain Guy: Exactly. And for a long-lived product like Android, the hardware you're designing for today looks nothing like what will exist in ten years. The first phone I worked on had a single CPU running at around 528 megahertz, something like 32 megabytes of RAM, and no GPU. You write code that fits that reality, and then a decade later developers are complaining about decisions you made, and you just have to nod and say, "Yeah. I know. You're right."

[00:07:37] GRAPHICS, PERFORMANCE, AND WHY THEY GO TOGETHER

Matt Klein: It seems like over time you gravitated toward the graphics and performance side of things. How did that happen, and what draws you to that space?

Romain Guy: It was always a natural fit for me. Even before joining Android, my open source work was largely about pushing the Java Swing UI toolkit into places most people didn't know it could go: visual effects, animations, creative experiments. Outside of work I love photography. There are cameras all over the wall behind me. I'm just drawn to anything visual.

Romain Guy: And when you care about visuals, performance comes with the territory. If you want your animations to feel good, you have to worry about the frame rate. That was especially true in the early days of Android, because the Dalvik VM shipped without a JIT compiler. It was purely interpreted, running on slow CPUs.

Matt Klein: I didn't know that. By that point the server JDK had already had JIT compilation for years, right?

Romain Guy: It had. Hotspot had been doing JIT for a long time. The garbage collector was also quite slow in Dalvik. It was stop-the-world, and every GC pause could run around 160 milliseconds.

Matt Klein: Why didn't Android ship with a JIT from the start? Was it code size, or something else?

Romain Guy: I think it was simpler than any technical reason: you have to ship for the project to keep existing. For several years it was essentially "we ship this version of Android by this date, or we're done." Google wasn't known as a company that built mobile operating systems, and convincing hardware partners and carriers to trust them was genuinely hard. There were constant deadlines. In many ways it felt like a startup that happened to have Google money behind it.

Romain Guy: My personal read is that owning the key components of the stack was also part of it. Wanting to be the master of your own destiny. The compromise was that the first version didn't have a JIT. It came pretty quickly after, in Android 2.0. But getting good performance out of a purely software-rendered system with no GPU-accelerated UI, on interpreted Java, was a real challenge.

[00:11:04] PERFORMANCE AS A MINDSET

Matt Klein: This leads into something I think is worth discussing directly. Performance, specifically how developers think about it. What's your take?

Romain Guy: The problem is that performance is difficult to do well and it requires real expertise. The tooling can look impressive, there's a lot of data to interpret, and so a lot of developers look for recipes to follow rather than genuine understanding. That leads to cargo-culting. We contributed to that ourselves by publishing guidance that was accurate for a given era and then watching it get repeated a decade later when it was no longer true.

Romain Guy: The other damaging thing is the Knuth quote about premature optimization. The full quote is more nuanced, but people use it as a blanket reason not to think about performance at all. And that's genuinely dangerous, because fixing performance after the fact can be nearly impossible without breaking your APIs or redesigning your architecture. We had that problem in parts of Android.

Matt Klein: My own experience has been that having a performance mindset is a better return on investment than micro-benchmarking everything. Being thoughtful about where it matters as you're making decisions, rather than trying to measure everything.

Romain Guy: That's exactly it. I always tell developers: when someone clicks a button, don't worry too much. In your drawing code, please think carefully. The point is just having enough knowledge about the system beneath your code to make informed decisions. And even then, understanding what you're measuring is itself extremely hard.

Romain Guy: A few months ago I wrote a blog post showing that the Android runtime reorders the fields of a class based on type and name. So depending on how fields are named and accessed, the memory layout changes, which changes the performance profile because your cache locality changes. I have a benchmark where just renaming a field makes the code run four times faster.

Matt Klein: It alpha-orders them?

Romain Guy: It does. I have no idea why, but that's what it does. And that's the kind of thing that, when you benchmark something and you see a number go up or down for reasons you can't explain, it pays to be curious and dig deeper. Though I also recognize you can't always do that. You have features to ship.

[00:19:18] AI TOOLS AND THE FUTURE OF ENGINEERING KNOWLEDGE

Matt Klein: This connects to something I've been thinking about a lot with AI coding tools. They're genuinely impressive, I'm not dismissing them. But I've been doing a lot of agent-assisted coding lately and I keep wondering: how do junior engineers in the future learn the things we've been talking about? The things you need to know to guide the agent toward the right answer?

Romain Guy: You're not alone in asking that. But if you want to look at the glass as half full, maybe these agents will make that kind of deep knowledge more accessible rather than less. Even for me, I've been feeding assembly output into AI tools and asking it to translate into plain English. Sometimes the results are a bit silly, "it does some math," but it can help you move faster through tedious parts.

Romain Guy: The engineers who can combine agent assistance with genuine understanding of what's happening underneath, those will probably be the most valuable people. The agents still need someone who knows when the output is wrong.

[00:20:42] RUST ON ANDROID AND THE JNI PROBLEM

Matt Klein: In the last several years, Android has started incorporating Rust, mostly at the lower levels for security reasons. But I wonder whether there's an opportunity to use it to replace some Java code for performance reasons too.

Romain Guy: I don't recall that being a serious discussion, honestly. The runtime has gotten good enough, and the VM combined with modern hardware handles most app-level code well. The cost of adopting a new language, rethinking your tooling, and managing the interop overhead is significant.

Romain Guy: If anything, I think one of the missed opportunities on Android more broadly was making it easier to drop into native code from Java or Kotlin for the cases where it genuinely matters. JNI has always been painful. It's not well documented even though a lot of people use it, and it's very easy to make expensive mistakes, like accidentally copying an entire array when you didn't mean to.

Matt Klein: That's something we deal with directly at bitdrift. Our SDK is mostly written in Rust, and we have bindings in both Kotlin and Swift. The Swift bindings are fairly straightforward, native to native. The Java bindings are genuinely nontrivial, both from a performance standpoint and just in terms of understanding what's actually happening.

Romain Guy: The most productive and performant approach I found when doing JNI on the platform was to pass only primitive types across the boundary. Extract all the data you need on the Java side first, then call the native function with nothing but primitives. That way the JIT can optimize cleanly and you avoid all the pain of calling back into the VM from C++. The JNI layer becomes a very thin piece of glue. But you have to design for it up front. You can't really retrofit it easily.

Matt Klein: We may need to consult you on our SDK.

Romain Guy: Happy to help.

[00:24:59] THE ANDROID RENDERING PIPELINE

Matt Klein: I'd love to dig into the graphics work more. Can you walk us through how the rendering pipeline on Android has evolved, from the early days to Jetpack Compose?

Romain Guy: There are three major components to think about end-to-end. You have the UI toolkit, which is your buttons and text fields and so on. That sits on top of the canvas, which is the 2D rendering layer, analogous to the canvas API on the web. And then when a window finishes rendering, the buffer it produced gets handed off to the window compositor, which on Android is called SurfaceFlinger. SurfaceFlinger takes all the visible windows and composites them together, using either the GPU or a hardware-specific path that OEMs can provide.

Romain Guy: The original UI toolkit is what we call the View system, because the base class is called View. It existed before I arrived at Android. It's powerful, but it has some architectural issues that accumulated over time. There's one file in the framework that's something like 35,000 lines long. Most of it is getters, setters, and comments, but every new feature for the UI toolkit essentially has to land in that base class. The thing just keeps growing. Every widget is heavy in memory, and maintaining it is genuinely difficult.

Romain Guy: The canvas API was originally backed by an open source library called Skia, which Google acquired for Android. Skia is also used by Chrome. But back then, Skia was entirely CPU-based, software rendered. The window compositor itself was always using OpenGL or a hardware composer abstraction for OEMs, but the UI toolkit wasn't touching the GPU at all.

Matt Klein: When did that change?

Romain Guy: Android 3.0, the first tablet release. I was doing some benchmarks and discovered that on a 720p display, just doing a full-screen bitmap copy, nothing else, we couldn't hit 60 frames per second. We were bandwidth-limited before we'd even started drawing any app content. That made it clear we had to move the UI toolkit to the GPU.

Romain Guy: So with the help of a couple other engineers, I rewrote the canvas to use the GPU instead while keeping the existing API completely unchanged. I only had a few months to do it, and it is probably the worst code I have ever written. But it worked well enough to ship the device.

Romain Guy: That GPU renderer stayed in place, with a lot of evolution, all the way to Android P, which would be around 2017 or 2018. At that point, Skia had developed its own GPU renderer, and it had matured to the point where it made sense for Android to go back to Skia rather than continue investing in a separate renderer.

[00:29:57] HOW GPU RENDERING ACTUALLY WORKS

Matt Klein: For people who haven't worked in this space, how does GPU rendering of UI actually work? A GPU expects triangles, but text and buttons are not triangles.

Romain Guy: Right, so the fundamental primitive on a GPU is a textured triangle. You send geometry, you apply textures, and you write shaders, which are small programs that run per pixel to compute color. Something like a gradient is a shader: for a given pixel at a given screen location, I compute the color based on the gradient parameters.

Romain Guy: For shapes and rectangular elements it's manageable. Text is where it gets genuinely hard. The actual data in font files is vector outlines, curves representing each character. The GPUs of that era weren't powerful enough to rasterize those curves directly on the hardware. So the approach we used was to rasterize each glyph on the CPU into a texture atlas, then for each character you want to draw you generate two triangles pointing into the atlas.

Romain Guy: The difficulty is that a UI toolkit doesn't know ahead of time what text will appear on screen. Every frame, especially with Chinese, Japanese, or Korean text, or when font sizes change, you have to repopulate that atlas efficiently. We ended up with a fairly complex pyramid of atlases: one for color images, one for monochrome glyphs, and various fallback layers. Most of the code in that renderer was actually text handling.

Romain Guy: The other thing that's counterintuitive is that optimizing for a GPU is completely different from optimizing for a CPU. On a GPU you want to minimize state changes. If you're alternating between drawing text and drawing images, you're constantly switching the GPU's state, which creates bubbles in the pipeline where neither the CPU nor the GPU is fully utilized. So the renderer would analyze all the drawing commands ahead of time, reorder them, and batch them. Five buttons scattered around the screen? Draw them as one call. That kind of optimization, done invisibly without changing any app APIs, is where a lot of the performance work lived.

[00:33:35] JETPACK COMPOSE AND WHY IT EXISTS

Matt Klein: And then there's Jetpack Compose, which is much higher up the stack. What's the relationship between all of this and Compose?

Romain Guy: Jetpack Compose is to the View system what React or Flutter are to older UI frameworks: a more reactive, compositional model for building UI components. We started working on it around 2018 or so.

Romain Guy: By that point we had reached a limit with the View system. There were bugs we couldn't fix without breaking apps, and optimizations we couldn't make because of architectural constraints. We'd also essentially extracted every performance gain available within the existing design. The framework was fully optimized and there was just nothing left to squeeze.

Romain Guy: The strategic decision that shaped Compose was that it would share the same canvas layer as the View system, rather than bringing its own renderer. That was a deliberate tradeoff. We sacrificed some potential for deeper integration in exchange for making adoption a non-issue. Because Compose and the View system share the same rendering layer, you can drop a single Compose button into a screen that's otherwise entirely the old View system, or embed an old custom View inside a Compose screen. You can migrate at your own pace. Given how large and mature the Android ecosystem is, I think that was the right call.

[00:36:40] BATTERY, PERFORMANCE, AND PLATFORM BUGS

Matt Klein: Shifting slightly, how does all of this rendering work relate to battery? I feel like we've talked a lot about CPU performance but not battery.

Romain Guy: Battery is a product of several things. The CPU is a significant drain if you're running the big cores at full speed. The GPU can be similarly expensive. And the radios, doing networking, can be surprisingly costly. I'm reminded of that at home because my house apparently blocks cell signals, so my phone is constantly boosting transmit power trying to connect. I basically can't make it through the day.

Romain Guy: For apps, one of the biggest differentiators is whether you're rendering continuously or on demand. Games typically render every single frame the display will accept, because something is always moving. That's why a game like Pokemon Go would heat up your device: the screen is on, the GPS is running, the CPU and GPU are both loaded. But a good UI toolkit only renders when something actually changes on screen. A lot of internal logic is dedicated to not drawing when you don't have to.

Romain Guy: Some of the most memorable bugs from the early days were in that category. There was one where, if your lock screen had a password field with a blinking cursor, turning the screen off didn't turn off the cursor animation. So in your pocket the system was redrawing that cursor twice per second, all night. That kind of thing is not good for the battery.

[00:41:02] FILAMENT: BUILDING A 3D RENDERER FROM SCRATCH

Matt Klein: Are there other projects from your time at Google that stand out to you?

Romain Guy: The one I'm probably most proud of is a 3D rendering engine I built with one other engineer. It's called Filament. It's open source and it's still in use today, including in the Samsung XR headset announced in 2025.

Romain Guy: The premise was that if you're an app developer and you want to show a small 3D element in your app, a credit card, a product visualization, whatever, your options were either to write raw OpenGL or Vulkan code, which is painful, or use a game engine, which is large and wants to be full-screen. We wanted something small and embeddable that could give you state-of-the-art rendering without the overhead.

Romain Guy: A lot of the focus was keeping the binary size as small as possible while delivering high performance. We spent a lot of time reading assembly output to understand what the compiler was generating, making sure vectorized instructions were being used correctly, optimizing both the CPU and GPU paths carefully.

Romain Guy: Starting from 2D and adding a third axis is a genuinely large jump in complexity. We read hundreds of research papers, and one thing we noticed was that even the papers sometimes skip steps as if the author isn't entirely certain themselves. So we built our own internal document that worked through everything from first principles, citing our sources but rewriting the derivations in our own words, and explicitly noting every place where we made an approximation and why. I really liked that approach. It forced us to actually understand what we were doing rather than just implement something that seemed to work.

[00:43:24] WHAT'S EXCITING NOW

Matt Klein: Last question: what excites you in technology right now?

Romain Guy: Somewhat surprisingly, audio programming. I've never done it before and I keep trying to find the time. There are some parallels with graphics in that you're manipulating large chunks of data in real time, so performance is central to the craft. I'm drawn to that.

Romain Guy: On the AI side, I think what I'm most curious about is what comes beyond large language models. A lot of what these systems do is genuinely impressive, but I'm waiting to see what can be done for domains that aren't fundamentally about words. Debugging, for instance. If I capture a performance trace from a device, I'd love an AI that can look across processes, correlate CPU behavior, and guide me toward the problem. That's not really an LLM problem in its current form.

Romain Guy: One area where I'm seeing genuinely interesting AI work is in graphics, using small neural networks as a form of data compression to replace traditional textures or materials. These are networks tiny enough to fit in a few lines of shader code. I love that because it's a domain-specific approach: here is this specific problem, here is a model designed around that problem. Rather than just throwing everything at a large general model and hoping. I'm excited to see where that goes.

Matt Klein: That's a great place to end it. Thank you so much, Romain. This was a fantastic conversation. That's a wrap for this episode of Beyond the Noise. Huge thanks to Romain for joining and sharing his story. You can find this and all past episodes on the bitdrift YouTube channel.

Romain Guy: Thank you. It was a real pleasure.

Matt Klein and Ryan Cooke chatting

Invisible Work That Keeps Pinterest Running with Ryan Cooke

June 2 2026

55 mins

Matt Klein and Miguel de Icaza chatting

Miguel de Icaza: GNOME, Mono, Xamarin, and No Sign of Stopping

May 19 2026

60 mins

Subscribe for new episode announcements


© 2023-2026 bitdrift, Inc. All rights reserved.

SOC 2 Type II Compliant