📝 Originally published (in Japanese) at
[forge.workstyle.tech].
When someone says, "You need a GPU," they're actually referring to two distinct scenarios:
Even within NVIDIA's GPU lineup, some models can only handle one of these tasks.
I was building an unmanned AI avatar streaming system where a 3D avatar would live-stream on video platforms 24/7. During this process, I hit the "compute vs. rendering" wall twice: once with CPU rendering and once with MIG. It seemed like a resource issue, but in reality, it was a missing functionality problem.
Below is a GPU selection procedure for rendering tasks and a record of my failures, based on actual measurements using rented cloud GPUs.
The setup was simple:
Headless Chromium (rendering the 3D avatar using WebGL)
→ Capture screen and audio
→ Encode to H.264 + AAC using ffmpeg
→ Stream to the platform via RTMP
The avatar would speak using an LLM and TTS (text-to-speech), rendered in the browser, encoded, and streamed. The biggest challenge was deciding where to run the "headless Chromium for 3D rendering" part.
Initially, I assumed the renderer would run solely on the CPU. Chromium has SwiftShader, a CPU-based WebGL backend, so WebGL "works" without a GPU.
It did work, but just barely. While plain WebGL ran at 60fps, the 3D avatar scene (toon shader + skinning) managed only about 4fps.
Typically, you'd try lowering the resolution to reduce the load. I did. Whether at 720p, 540p, or 360p, it stayed at 4fps. Since the performance didn't scale with resolution, the bottleneck wasn't pixel processing but scene processing itself. My fallback plan of "downgrade to 540p / 24fps if it's too heavy" was useless from the start.
CPU rendering was a no-go. I needed a GPU.
My cluster had an H100, divided into 1g.10gb
slices using MIG (Multi-Instance GPU) for LLM and speech inference. MIG splits a single GPU into multiple instances, great for packing inference services. I thought, "If I borrow one slice, there's no extra cost," and tried running the renderer there.
Here’s what happened with the test Pod:
nvidia-smi
inside the Pod showed the H100 and MIG devicesIt’s natural to think, "Maybe the slice isn’t enough," but that wasn’t it. No matter how I configured Chromium’s flags, whether using --use-gl=angle
with egl or vulkan, the result was the same. Checking Vulkan’s ICD (driver registration info), it was empty.
The issue was NVIDIA's official spec: MIG is compute-only and doesn’t support graphics APIs.
This isn’t a performance issue but a functionality one. No matter how many slices you stack, even the largest 7g.80gb, WebGL won’t render a single frame on the GPU. It’s like trying to park in a spot that’s not a parking space but a compute-only room. Adding more slots won’t help.
Theoretically, disabling MIG and using the entire H100 would enable graphics APIs. However, data center-focused compute GPUs lack units needed for rendering. For the H100:
Even if graphics APIs worked, rendering performance would be poor, and without H.264 hardware encoding, streaming benefits would be minimal. Operationally, disabling MIG while all slices were in use by inference services was impossible.
Catalog specs like CUDA cores and VRAM don’t reveal this. The lesson here: "Expensive GPUs don’t always do everything." The H100 is for compute, not rendering.
Finally, I moved the renderer to a cloud GPU capable of rendering. For rendering, choose GPUs designed for graphics, like L4 / T4 / RTX series. An RTX 4000 Ada / RTX 2000 Ada ($0.24–0.28/hour) easily handled 720p30. More expensive isn’t always better.
Here’s the final setup:
| Task | Location | Reason |
|---|---|---|
| LLM, TTS, Application | On-prem cluster (H100 MIG) | Compute tasks. MIG’s strength |
| Browser Rendering, Encoding | Cloud rendering-capable GPU | Requires graphics APIs |
Treat compute and rendering GPUs as separate inventories. This was the biggest design change.
Having a GPU allocated doesn’t mean graphics drivers are accessible. Even with a rendering-capable GPU, container settings can hide drivers. Check these:
NVIDIA_DRIVER_CAPABILITIES=all
in the container (default excludes graphics libraries)10_nvidia.json
equivalent) is present. Use eglinfo
to list NVIDIA EGL devicesicd.d/
) isn’t emptyWithout these, applications will see "no NVIDIA implementation available."
This is the most critical lesson.
Headless Chromium silently falls back to CPU rendering (SwiftShader) if GPU rendering fails. No errors, no warnings. It starts, gets a WebGL context, and displays the screen—just slowly. If you assume "it’s working," you won’t notice until just before production.
Always verify from the output side:
| Check Method | CPU Fallback | GPU Rendering |
|---|---|---|
GL_RENDERER string |
||
SwiftShader |
||
NVIDIA |
||
| Measured 3D scene fps | ~4 | 57–58 |
The 10x difference leaves no room for doubt. Create a minimal probe page (just GL_RENDERER and fps) to speed up troubleshooting. Since this stack fails silently, double-check with fps or GPU usage.
Testing "how many streams per GPU" yielded a surprise:
| Item | Measured |
|---|---|
| Concurrent streams | |
| 4 (720p30, real-time) | |
| GPU usage | |
| 26% | |
| First to saturate | |
| CPU (16 vCPU) |
The GPU had 3x capacity left. Why? The GPU only handles rendering.
| Task | Where |
|---|---|
| 3D Rendering | GPU |
| Frame Capture | CPU / Transfer |
| H.264 Encoding | |
| CPU (if software) | |
| Audio Mixing, Muxing, Sending | CPU |
So, NVENC availability directly impacts capacity. Hardware encoding frees up CPU, allowing more streams. When choosing a GPU, consider vCPU count and encoder presence.
Cheap GPU clouds come in two types: community (individuals/businesses renting out excess GPUs) and secure (operated by providers).
Community GPUs are cheaper but hit-or-miss. With the same image/settings, one host ran flawlessly for 10 minutes, while another crashed every 60–150 seconds.
Here’s how to use them and essential safeguards:
Another operational trap: Stopping an instance can make the GPU unavailable for restart, as it’s allocated to others. You’d keep paying without being able to restart. Always Terminate when done.
$0.28/hour × 720 hours/month = $201.6/month (1 GPU)
$201.6 ÷ 4 streams = $50.4/stream ≈ ¥7,600/stream (150 JPY/USD)
Easily overlooked costs:
When renting a GPU for rendering, check in this order:
NVIDIA_DRIVER_CAPABILITIES=all
, EGL/Vulkan ICD, libglvndGL_RENDERER
and fps. "It started" isn’t proofGL_RENDERER
and fps"Rent the strongest GPU available" is the easiest way to fail. Cheaper, purpose-built cards can be faster and cheaper. Distinguish between "no space available" and "wrong room entirely." Mistaking missing functionality for insufficient resources is a common GPU pitfall.