{"slug": "borrowed-an-h100-but-couldn-t-draw-a-single-frame-why-compute-gpus-and-rendering", "title": "Borrowed an H100 but couldn't draw a single frame — Why compute GPUs and rendering GPUs are different beasts", "summary": "A developer building an AI avatar streaming system discovered that NVIDIA's H100 GPU, when partitioned via MIG, cannot render graphics because MIG is compute-only and lacks graphics API support. The project required moving rendering to a cloud GPU like the RTX 4000 Ada, while keeping compute tasks on the H100, highlighting that expensive compute GPUs are not suitable for rendering tasks.", "body_md": "📝 Originally published (in Japanese) at\n\n[forge.workstyle.tech].\n\nWhen someone says, \"You need a GPU,\" they're actually referring to two distinct scenarios:\n\nEven within NVIDIA's GPU lineup, **some models can only handle one of these tasks.**\n\nI 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.\n\nBelow is a GPU selection procedure for rendering tasks and a record of my failures, based on actual measurements using rented cloud GPUs.\n\nThe setup was simple:\n\n```\nHeadless Chromium (rendering the 3D avatar using WebGL)\n  → Capture screen and audio\n  → Encode to H.264 + AAC using ffmpeg\n  → Stream to the platform via RTMP\n```\n\nThe 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.\n\nInitially, I assumed the renderer would run solely on the CPU. Chromium has SwiftShader, a CPU-based WebGL backend, so WebGL \"works\" without a GPU.\n\nIt did work, but just barely. While plain WebGL ran at 60fps, **the 3D avatar scene (toon shader + skinning) managed only about 4fps**.\n\nTypically, 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.\n\nCPU rendering was a no-go. I needed a GPU.\n\nMy cluster had an H100, divided into `1g.10gb`\n\nslices 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.\n\nHere’s what happened with the test Pod:\n\n`nvidia-smi`\n\ninside 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`\n\nwith egl or vulkan, the result was the same. Checking Vulkan’s ICD (driver registration info), **it was empty**.\n\nThe issue was NVIDIA's official spec: **MIG is compute-only and doesn’t support graphics APIs.**\n\nThis 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.\n\nTheoretically, 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:\n\nEven 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.\n\n**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.\n\nFinally, 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.**\n\nHere’s the final setup:\n\n| Task | Location | Reason |\n|---|---|---|\n| LLM, TTS, Application | On-prem cluster (H100 MIG) | Compute tasks. MIG’s strength |\n| Browser Rendering, Encoding | Cloud rendering-capable GPU | Requires graphics APIs |\n\n**Treat compute and rendering GPUs as separate inventories.** This was the biggest design change.\n\nHaving a GPU allocated doesn’t mean **graphics drivers are accessible.** Even with a rendering-capable GPU, container settings can hide drivers. Check these:\n\n`NVIDIA_DRIVER_CAPABILITIES=all`\n\nin the container (default excludes graphics libraries)`10_nvidia.json`\n\nequivalent) is present. Use `eglinfo`\n\nto list NVIDIA EGL devices`icd.d/`\n\n) isn’t emptyWithout these, applications will see \"no NVIDIA implementation available.\"\n\nThis is the most critical lesson.\n\n**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.\n\nAlways verify from the output side:\n\n| Check Method | CPU Fallback | GPU Rendering |\n|---|---|---|\n`GL_RENDERER` string |\n`SwiftShader` |\n`NVIDIA` |\n| Measured 3D scene fps | ~4 | 57–58 |\n\nThe 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.\n\nTesting \"how many streams per GPU\" yielded a surprise:\n\n| Item | Measured |\n|---|---|\n| Concurrent streams |\n4 (720p30, real-time) |\nGPU usage |\n26% |\n| First to saturate |\nCPU (16 vCPU) |\n\nThe GPU had 3x capacity left. Why? **The GPU only handles rendering.**\n\n| Task | Where |\n|---|---|\n| 3D Rendering | GPU |\n| Frame Capture | CPU / Transfer |\n| H.264 Encoding |\nCPU (if software) |\n| Audio Mixing, Muxing, Sending | CPU |\n\nSo, **NVENC availability directly impacts capacity.** Hardware encoding frees up CPU, allowing more streams. When choosing a GPU, consider vCPU count and encoder presence.\n\nCheap GPU clouds come in two types: **community** (individuals/businesses renting out excess GPUs) and **secure** (operated by providers).\n\nCommunity 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.\n\nHere’s how to use them and essential safeguards:\n\nAnother 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.**\n\n```\n$0.28/hour × 720 hours/month = $201.6/month (1 GPU)\n$201.6 ÷ 4 streams = $50.4/stream ≈ ¥7,600/stream (150 JPY/USD)\n```\n\nEasily overlooked costs:\n\nWhen renting a GPU for rendering, check in this order:\n\n`NVIDIA_DRIVER_CAPABILITIES=all`\n\n, EGL/Vulkan ICD, libglvnd`GL_RENDERER`\n\nand fps. \"It started\" isn’t proof`GL_RENDERER`\n\nand 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.", "url": "https://wpnews.pro/news/borrowed-an-h100-but-couldn-t-draw-a-single-frame-why-compute-gpus-and-rendering", "canonical_source": "https://dev.to/orca_forge/borrowed-an-h100-but-couldnt-draw-a-single-frame-why-compute-gpus-and-rendering-gpus-are-d9k", "published_at": "2026-08-29 00:56:41+00:00", "updated_at": "2026-08-29 01:48:35.766932+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-infrastructure", "ai-tools", "developer-tools"], "entities": ["NVIDIA", "H100", "MIG", "Chromium", "WebGL", "RTX 4000 Ada", "RTX 2000 Ada", "L4"], "alternates": {"html": "https://wpnews.pro/news/borrowed-an-h100-but-couldn-t-draw-a-single-frame-why-compute-gpus-and-rendering", "markdown": "https://wpnews.pro/news/borrowed-an-h100-but-couldn-t-draw-a-single-frame-why-compute-gpus-and-rendering.md", "text": "https://wpnews.pro/news/borrowed-an-h100-but-couldn-t-draw-a-single-frame-why-compute-gpus-and-rendering.txt", "jsonld": "https://wpnews.pro/news/borrowed-an-h100-but-couldn-t-draw-a-single-frame-why-compute-gpus-and-rendering.jsonld"}}