A GPU sits idle in a video-analytics box, apt reports OpenCL as installed, and the analytics stages still run on the CPU. Nothing errored. That silence is the problem — a mislayered OpenCL stack fails quietly, and everything downstream inherits the lie. Most teams standing up GPU video analytics on Ubuntu treat OpenCL setup as a one-line package install. Install a runtime, assume the ICD loader will resolve the right platform, move on to the workload. Then weeks later someone notices that cost-per-stream never dropped the way the plan said it would, and the debugging starts. The honest framing is simpler to state and harder to accept: OpenCL on Ubuntu is not one thing you install. It is three distinct layers you install separately and verify independently, and if any layer is missing or mismatched the whole stack degrades to CPU without telling you. What does “install OpenCL on Ubuntu” actually mean? OpenCL is a specification, not a shippable binary. What you install on Ubuntu is a collection of components that together implement that specification for a specific piece of hardware. When someone says “I installed OpenCL,” the useful question is always: which of the three layers did you install? The first layer is the vendor driver — the kernel module and low-level userspace that lets the operating system talk to the physical device. On an NVIDIA card this is the proprietary driver package; on AMD it is the AMDGPU stack; on Intel it is the graphics driver and compute runtime. Without this layer there is no GPU to target, regardless of what OpenCL packages you add. The second layer is the ICD loader — the Installable Client Driver mechanism. This is the ocl-icd (or khronos reference loader) library that exposes the single libOpenCL.so your application links against. The loader’s job is dispatch: at runtime it reads the ICD registry, discovers which vendor implementations are present, and routes your OpenCL calls to the right one. On Ubuntu the loader looks in /etc/OpenCL/vendors/ for .icd files, each a one-line pointer to a vendor’s implementation library. The third layer is the vendor runtime — the actual OpenCL implementation for your device, the thing the loader dispatches to. This ships with or alongside the vendor driver but is a logically separate component. It is what compiles your kernels and executes them on the GPU. The reason the layering matters is that each layer can be present, absent, or version-mismatched independently of the others. You can have a working driver and a working loader with no vendor .icd registered — the loader then reports zero platforms, and your application either errors or falls back to a CPU implementation if one is available. This is the single most common source of the “OpenCL is installed but nothing runs on the GPU” complaint we see. The three layers, and what breaks when one is missing Layer Ubuntu component (typical) What it does Symptom when missing/wrong Vendor driver NVIDIA proprietary / amdgpu / Intel graphics driver Kernel + low-level device access No GPU visible to any API; clinfo shows zero devices ICD loader ocl-icd-libopencl1 / opencl-headers Runtime dispatch to vendor implementations libOpenCL.so missing at link/load time; app fails to start Vendor runtime Vendor OpenCL runtime + its .icd file in /etc/OpenCL/vendors/ Compiles and executes kernels on the device Loader reports 0 platforms; silent CPU fallback The evidence class for that last row is an observed-pattern — across the video-analytics installs we have debugged, a missing or unreadable .icd file is the failure mode that most often produces green tests and CPU-bound throughput at the same time. It is not a benchmarked rate; it is where our attention goes first when a “working” install underperforms. The important structural point: only the top row produces a loud failure. A missing driver means no device, and clinfo says so plainly. But a missing vendor .icd — with driver and loader both present — produces a stack that looks healthy to a casual check and quietly does the wrong thing. That asymmetry is why verification cannot be optional. How do you verify an OpenCL install with clinfo? clinfo is the reference diagnostic. It walks the ICD loader’s discovery path, enumerates every platform and device the loader can reach, and prints their properties. Running it is the boundary between “I think OpenCL is installed” and “I have confirmed the GPU platform is visible.” Install it with sudo apt install clinfo and run it bare. Read the output against this checklist rather than skimming for the absence of errors: Number of platforms is at least 1. Zero platforms means the loader found no registered vendor .icd — driver and runtime layers are the suspects, not the loader. The platform name matches your GPU vendor — “NVIDIA CUDA”, “AMD Accelerated Parallel Processing”, or “Intel(R) OpenCL”. If the only platform is a CPU implementation (for example a POCL or Intel CPU-only platform), your GPU runtime is not registered. At least one device of type CL_DEVICE_TYPE_GPU appears under that platform. A platform can be present with only a CPU device — that still leads to CPU execution. The device name is your actual card, and the reported global memory roughly matches its spec. A wildly wrong memory figure signals a version-mismatched runtime. If clinfo reports zero platforms while nvidia-smi or rocminfo shows a healthy device, the fault is almost always the vendor .icd file — check that /etc/OpenCL/vendors/ contains the vendor’s .icd and that the library it points to actually exists on disk. This is the layered-verification discipline that makes the difference between a stack you can trust and one you are guessing about. The same verify-each-layer logic underpins the transcoding-focused walkthrough in our companion piece on installing and verifying OpenCL for GPU compute on transcoding workloads, which covers the encode-path variant of the same install. Why do video-analytics stages silently fall back to CPU? This is the failure that costs money, because it does not announce itself. A video-analytics pipeline is a chain of stages — decode, resize, colour-convert, inference pre/post-processing, sometimes classical CV operators via OpenCV’s OpenCL backend (T-API). Many of those stages are written to prefer the GPU but tolerate the CPU. When the OpenCL platform is not visible, the tolerant stages quietly execute their CPU code path. Frameworks make this worse by design, and for good reasons. OpenCV’s T-API is built to degrade gracefully — if no usable OpenCL device is found, cv::ocl::useOpenCL() returns false and the operations run on the CPU with identical results, just slower. FFmpeg’s OpenCL filters behave similarly at the pipeline level. Graceful degradation is the right engineering choice for portability, but it means the only signal you get from a broken OpenCL stack is a performance number that is worse than it should be — and if you never established what “should be” looks like, you have no baseline to notice against. That is the connection to profiling economics. A correctly layered OpenCL stack lets a GPU Performance Audit measure the real workload economics — actual GPU utilisation, actual cost-per-analytics-hour. A mislayered one produces numbers that reflect a broken runtime, not the workload. You end up debugging a profile that is measuring your misconfiguration. Getting the install right is the precondition for the profile-first decision, not a side quest before it. This is the same underutilisation pattern that a GPU performance audit exists to detect and fix — a verified OpenCL install is what makes that detection meaningful rather than an artifact of a broken stack. Common install pitfalls: NVIDIA vs AMD vs Intel The three-layer model is universal, but where each layer comes from differs by vendor, and each vendor has a signature failure. Vendor Driver source Runtime + ICD source Signature pitfall NVIDIA Proprietary driver package Bundled with the driver / CUDA toolkit .icd present but nvidia-opencl component skipped during a minimal driver install; clinfo shows CUDA platform absent while nvidia-smi is healthy AMD amdgpu kernel driver ROCm OpenCL runtime or the Mesa clover/rusticl stack Two competing runtimes registered at once; loader dispatches to the wrong one, kernels compile but behave oddly Intel Intel graphics driver Intel Compute Runtime (intel-opencl-icd) Package installed but user not in the render group, so the device is invisible at the permission layer None of these is exotic. They share one root cause: the assumption that installing “the OpenCL package” installs all three layers coherently for your specific device. It rarely does. On a headless analytics server the graphics-driver dependency chain that would pull the runtime on a desktop is often absent, so the runtime layer has to be installed deliberately. A worked example, with explicit assumptions: suppose an analytics node has an NVIDIA GPU, the proprietary driver is installed and nvidia-smi reports the card correctly, and someone ran apt install ocl-icd-libopencl1. That gives driver plus loader — two of three layers. If the NVIDIA OpenCL runtime component was not installed and no /etc/OpenCL/vendors/nvidia.icd exists, clinfo reports zero platforms. The OpenCV pipeline calls cv::ocl::useOpenCL(), gets false, and runs entirely on CPU. Throughput is a fraction of expected, nothing errors, and the cost-per-stream figure the audit projected never materialises. The fix is one layer, not a rebuild — register the vendor runtime and re-verify with clinfo. FAQ How does installing OpenCL on Ubuntu actually work? Installing OpenCL on Ubuntu means assembling three separate components: the vendor driver that talks to the device, the ICD loader (ocl-icd) that dispatches calls, and the vendor runtime that compiles and executes kernels. It is not a single package. In practice you install each layer for your specific GPU and then verify the whole stack with clinfo before trusting it. What are the distinct layers of an OpenCL stack on Ubuntu and why does the layering matter? The layers are the vendor driver, the ICD loader, and the vendor runtime (registered via a .icd file in /etc/OpenCL/vendors/). Each can be present, absent, or version-mismatched independently. The layering matters because a missing runtime layer with a healthy driver and loader produces a stack that looks installed but silently falls back to CPU. How do I verify an OpenCL install with clinfo and confirm the GPU platform is actually visible? Run clinfo and check four things: at least one platform is reported, the platform name matches your GPU vendor, at least one device is of type CL_DEVICE_TYPE_GPU, and the device name and memory match your actual card. Zero platforms while nvidia-smi or rocminfo shows a healthy device points to a missing or broken vendor .icd file. Why do video-analytics stages silently fall back to CPU even when OpenCL appears installed? Frameworks like OpenCV’s T-API and FFmpeg’s OpenCL filters are designed to degrade gracefully — if no usable OpenCL device is found they run the CPU code path with identical results, just slower. When the vendor runtime layer is missing the loader reports no GPU platform, and those tolerant stages execute on the CPU without any error. The only visible signal is worse-than-expected throughput. How does a correct OpenCL install affect the reliability of GPU workload profiling and cost-per-analytics-hour figures? A verified install is the precondition for trustworthy profiling: without it, GPU utilisation and cost-per-analytics-hour figures measure a misconfigured stack rather than the workload. A correctly layered stack lets a GPU Performance Audit measure real workload economics; a mislayered one produces numbers that reflect a broken runtime, so any decision built on them is unsound. What are the common OpenCL install pitfalls on Ubuntu for NVIDIA versus AMD versus Intel GPUs? On NVIDIA, the runtime component is sometimes skipped during a minimal driver install, leaving no CUDA platform even though nvidia-smi is healthy. On AMD, two competing runtimes (ROCm and Mesa) can register at once and the loader dispatches to the wrong one. On Intel, the intel-opencl-icd package installs but the user is not in the render group, so the device stays invisible at the permission layer. The temptation, once clinfo finally prints a GPU device, is to treat the install as finished and move straight to load. It is not finished — it is now measurable. That is the whole point of doing the layering deliberately: a verified stack is the only foundation on which a profile means anything. If you want to see what a correctly installed stack lets you decide, the stage-economics analysis of GPU versus CPU work in an inference pipeline shows the kind of workload reasoning that only holds up when the runtime underneath it is honest.