Skip to main content

Choosing a Portability Layer

Every page in this folder makes its own case, and none of them tells you which one to actually pick โ€” that decision depends on facts about your project that no single page can know. This page collects those facts into four questions, a decision table built from them, and one default answer for the common case of not having a second target yet.

The four questionsโ€‹

Answer these before comparing options, because each one eliminates a chunk of the table on its own:

  1. Which hardware must this run on? NVIDIA only, NVIDIA plus one other vendor, a browser, or a fixed embedded target all point at different answers before performance enters the conversation at all.
  2. What language does the team already write? A C++ team and a Python/PyTorch team face a different cost to adopt any given layer, independent of the layer's technical merits.
  3. How close to peak hardware performance must this actually get? A data-movement or orchestration path tolerates a generic backend fine; a kernel that dominates the runtime does not, per The Portability Problem.
  4. Does it need to interoperate with graphics or a browser? If a compute result feeds a render pass or has to run in a tab, that constraint dominates every other consideration โ€” see Vulkan and DirectX Compute and WebGPU.

The decision tableโ€‹

OptionTargetsLanguageEffort to port from CUDAPerformance ceilingEcosystem
CUDANVIDIA onlyCUDA C++โ€” (native)Highest, by constructionDeepest: cuBLAS/cuDNN/CUTLASS, every framework upstreams first
HIPNVIDIA + AMDC++, near-identical to CUDALow โ€” hipify handles API callsNear-native on AMD once rungs 3โ€“4 are addressedMature on AMD; rocBLAS/MIOpen track cuBLAS/cuDNN with a lag
SYCLNVIDIA + AMD + IntelStandard C++, single-sourceModerate โ€” rewrite around queues, no mechanical toolBackend-dependent; best on Intel, solid on the others via pluginsGrowing; strongest where Intel invests (oneAPI, DPC++)
OpenCLBroadest driver supportC dialect, separate-sourceModerateโ€“high โ€” different memory and compilation modelBelow CUDA/HIP; vendor driver quality variesMature but not growing; strongest in embedded/FPGA niches
OpenMP/OpenACC offloadNVIDIA + AMD + Intel (via compiler support)Existing Fortran/C/C++ plus pragmasLow for compute-bound loops, high for anything irregularBelow hand-written kernels; compiler-dependentStrong in traditional HPC, weak in ML
Vulkan/DirectX computeBroadest GPU driver supportGLSL/HLSL plus C++/C# host codeHigh โ€” different object model entirelyHigh when tuned, but ceremony discourages tuningDeep for graphics; sparse for pure compute
MetalApple onlyMSL (C++14 dialect) plus Swift/Objective-C/C++ hostHigh โ€” different API and memory modelHigh on Apple silicon specifically, via unified memoryMature for Apple's own stack (MPS, Core ML); nowhere else
WebGPUAnywhere a browser or wgpu/Dawn runsWGSLHigh โ€” smallest, most restricted shader language hereLowest ceiling of this table, by design (sandbox limits)Young but growing; the only browser-native option
TritonNVIDIA, growing AMD supportPython, compiled to a kernelLow for the kernels it targets (matmul-like, tile-based)Near-hand-tuned for the patterns it's designed aroundStrong and growing fast inside PyTorch's compiler stack

Reading down the "effort to port from CUDA" column repeats the same lesson The Portability Problem makes at length: API-level effort is low almost everywhere, and the real cost is always in the rows that table doesn't have columns for โ€” warp intrinsics, tuning, and library maturity.

By target hardwareโ€‹

The four-questions framing collapses fastest when the first question already has a near-unique answer:

If you must run onChoose
NVIDIA onlyCUDA
NVIDIA + AMDHIP
NVIDIA + AMD + IntelSYCL
AppleMetal
A browserWebGPU
Anything with a compute-capable driver, no other constraintVulkan or OpenCL
Existing Fortran/C++ HPC codeOpenMP offload

By team and languageโ€‹

A Python-first ML team already routes almost everything through PyTorch or JAX, and for that team the practical "portability layer" is the framework's own backend selection (CUDA, ROCm, MPS, XLA) plus Triton for hand-written kernels โ€” none of the C++ options in the table above are usually the right first move. A C++ team with existing CUDA code faces the opposite calculus: HIP and SYCL are both live options, and the choice between them tracks the hardware question above more than anything about the team itself.

Ecosystem maturityโ€‹

The library column in the decision table is where "portable" quietly stops meaning "as fast." A layer's API coverage is rarely the bottleneck โ€” its library maturity is. rocBLAS and MIOpen are real, tested, and used in production, but they still trail cuBLAS and cuDNN's tuning depth on the newest architectures; SYCL's library story is younger still outside Intel's own hardware. None of that is a reason to avoid these layers โ€” it's a reason to benchmark the specific operations your workload depends on, on the specific hardware you'll actually deploy to, rather than trusting a portability claim on a vendor's landing page.

The pragmatic defaultโ€‹

Write CUDA. Keep the algorithm and the host-side structure free of CUDA-specific assumptions where that costs nothing โ€” avoid hardcoding a warp size of 32 in code that doesn't need to, keep tuning constants in one place instead of scattered through the kernel โ€” and port with HIP the day a second vendor becomes a real, funded requirement rather than a hypothetical one. Adopting a portability layer before a second target exists usually costs more than it saves: it's ongoing tax paid against a backend nobody runs, for optionality that Ecosystem maturity above says you'll still have to re-benchmark from scratch the day you actually need it. This is the same position The Accelerator Landscape takes about CUDA's central role in the ecosystem โ€” restated here as the actionable version of that observation.

"Supports NVIDIA" means very different things

A portability layer's documentation claiming it "supports NVIDIA" can mean anything from a first-class, continuously-tested backend to a community-maintained plugin that hasn't been exercised against a recent CUDA release. Check the project's CI matrix โ€” which backends are actually built and tested on every commit โ€” not the marketing page, before assuming a listed backend is production-ready.

See alsoโ€‹

  • The Portability Problem โ€” why source and functional portability are solved and performance portability isn't, which is the premise this page's table depends on.
  • HIP and ROCm โ€” the near-mechanical translation path this page's default recommends reaching for second.
  • SYCL and oneAPI โ€” the single-source alternative, and home of the canonical CUDA/SYCL/OpenCL terminology table.
  • The Accelerator Landscape โ€” the hardware survey this page's decision table turns into an actionable choice.
  • GPU & Accelerators โ€” the section index and its three learning paths.