Graphics Shader
Shader are programs that run in GPU
For CPU there are two main ISA: x86_64 and ARM that most machines use. Thus you can compile your code to these two ISA, and run the program.
But for GPUs, each manufacturer has its own ISA and even more each of them have multiple generations of ISA being concurrently supported. E.g. NVIDIA has Lovelace, Ampere, Turning, etc, and same with AMD (RDNA3, RDNA2, etc.).
This means you have to compile your same program multiple times if you want it to run on all platforms. So, one approach is to use a shader language that the graphics driver compiles to machine code. But compiling GPU programs on runtime is not ideal. This is slow, is prone to bugs and demands the device driver to ship with compiler.
Another better approach is to use intermediate representation (e.g. SPIR-V, DXIL/DXBC, AIR). So, you compile your shader program to an intermediate representation (i.e. bytecode) which the device driver just-in-time compiles to to machine code and executes. But not all gpu drivers support the same bytecode. This depends on the GPU API that they implement.
Graphics API are specifications
OpenGL, Metal, Vulkan, DirectX11, DirectX12 are some of the well known APIs. It is the job/choice of the graphics driver to implement one or multiple of those APIs. In addition to these apis the gpu device usually has it own apis too.
Take the case of a Nvidia GPU. Their driver provides NVAPI that exposes all the capabilities of the GPU. In addition to that Nvidia drivers also provide the Vulkan, OpenGL and DirectX APIs. Since GPU do more than graphics, the driver may also provide other APIs such as CUDA or OpenCL for compute, Vulkan Video or NVDEC for video decoding.
Incontrast Apple only supports the Metal API. It used to support OpenGL but it is now deprecated.
There are many Shader IR
Now, in regards to the shader intermediate representation format. Different graphics api have their own intermediate representation (IR/Bytecode) format. Vulkan and OpenGL have SPIR-V which aims to be OS and device independent. Microsoft's DirectX API has DXIL, DXBC. Apple's Metal API has AIR. And to produce the bytecode, each API specifies a (slightly) different programming languages: Metal has MSL, OpenGL has GLSL, DirectX has HLSL. Vulkan doesn't introduce new high level langauge or support other high level shader language. Vulkan only understands SPIR-V so you can use any language (GLSL or HLSL) as long as you have a compiler that compiles your shader code to SPIR-V.
- Note about GPU ISAs and Compilers:
- Apple doesn't provide compiler for their ISA. You can only compile shaders written in MSL using Metal api. Their ISA is not open.
Nvidia's
nvcc
compiles cuda code to bytecode called PTX. Then the PTX code is JIT compiled by GPU driver and executed in the GPU. PTX is a low level virtual machine and ISA independent of gpu architecture within nvidia's gpus. Alternatively, you can compile cuda code to SASS which is even more lower level and tied to specific gpu architecture of nvidia. At the end SASS is converted by GPU driver to machine code that the GPU executes.See https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/#gpu-compilation for more details.
In the CUDA naming scheme, GPUs are named sm_xy, where x denotes the GPU generation number, and y the version in that generation. Additionally, to facilitate comparing GPU capabilities, CUDA attempts to choose its GPU names such that if x1y1 <= x2y2 then all non-ISA related capabilities of sm_x1y1 are included in those of sm_x2y2.
Code (sm_) Architecture Name 50, 52, 53 Maxwell 60, 61, 62 Pascal 70, 72 Volta 75 Turing 80, 86, 87 Ampere 89 Ada 90, 90a Hopper 100, 100a, 101, 101a, 120, 120a Blackwell
- Resource:
Bare minmum example:
yarn add @shopify/react-native-skia
import React from "react"; import { Canvas, Skia, Shader, Fill} from "@shopify/react-native-skia"; const source = Skia.RuntimeEffect.Make(` vec4 main(vec2 xy) { return vec4(1); } `)!; function App(): JSX.Element { return ( <Canvas style={{ flex: 1 }}> <Fill> <Shader source={source} /> </Fill> </Canvas> ); } export default App;