Track 03 · Graphics

An open graphics stack, from kernel to colour.

The open graphics stack is not a compromise any more. Mesa implements Vulkan and OpenGL for AMD, Intel and — since NVK — NVIDIA hardware; Wayland gives you a predictable presentation path; and colour management is a solved problem if you configure it once and verify it with a measurement.

vertex stage fragment stage sRGB display SCENE FRAMEBUFFER OUTPUT linear working space → tone map → display transform
Every stage has a defined colour space, and every hand-off is documented.
MesaVulkan & OpenGL
WaylandPresentation path
LinearWorking space
OCIOColour transforms

Architecture

Six layers, each replaceable

Knowing which layer owns a bug is most of the work. A flickering window, a wrong colour and a missing extension live in three different places.

The open graphics stack from hardware upwards, with the open implementation and the symptom that points at each layer.
LayerOpen implementationResponsibilitySymptom when it breaks
KernelDRM / KMS in the Linux kernelMemory management, modesetting, fencesNo output, GPU resets, wrong resolution at boot
Userspace driverMesa — RADV, ANV, NVKCommand submission, shader compilationApplication crashes, missing extensions
APIVulkan, OpenGL, OpenCLThe contract your code targetsValidation errors, undefined behaviour
PresentationWayland compositor — Sway, KWin, MutterBuffer sharing, vsync, frame pacingTearing, stutter, wrong scaling
ToolkitGTK, Qt, SDL, GLFWWindow, input and context creationInput quirks, HiDPI artefacts
ColourLittle CMS, OpenColorIO, ArgyllCMSTransforms between colour spacesEverything looks slightly wrong
Check

What driver am I on?

vulkaninfo --summary
glxinfo -B
drm_info | head -40
Check

Is it a validation bug?

VK_LOADER_DEBUG=warn \
VK_INSTANCE_LAYERS=\
VK_LAYER_KHRONOS_validation \
./your-app
Check

Which colour space?

wayland-info | grep -i colour
colormgr get-devices

Colour management

Do the maths in linear light

Averaging, blurring, blending and lighting are physically meaningful only in linear light. If you do them on sRGB-encoded values you get the classic dark, muddy edges. Convert to linear on the way in, stay linear while you work, and transform to the display only at the very end.

  1. Pick a working space

    Linear sRGB (Rec.709 primaries) for web and video work; ACEScg for compositing and VFX where wider gamut and scene-linear behaviour matter.

  2. Tag every input

    Textures, plates and renders must declare what they are. An untagged asset is a bug waiting to be discovered after delivery.

  3. Transform with a config, not by hand

    An OpenColorIO config centralises every conversion so the whole team and every render node agrees. Never bake a manual gamma tweak into an asset.

  4. Calibrate the display

    Measure with a colourimeter, generate an ICC profile, load it, and verify against a test chart. Repeat every few months, and after any driver change.

  5. Verify the round trip

    Render a known reference — a colour chart or a set of patches — compare the measured result with the expected value, and record the delta.

Common colour mistakes

  • Double gamma — decoding twice or not at all. Textures end up either washed out or crushed.
  • Working in sRGB — blending in an encoded space, which is the origin of the dark fringe around transparent edges.
  • Untagged assets — the transform is guessed, and different tools guess differently.
  • Uncalibrated display — you grade to the monitor's error rather than to the image, then the error is baked into the export.
  • 8-bit intermediate renders — banding that survives all the way to delivery. Use 16-bit or float for anything intermediate.

A minimal OCIO check

# Which configs are installed?
ls /usr/share/color/ocio/

# Force a config for a whole session
export OCIO=/usr/share/color/ocio/\
ocio://studio-config-latest
python3 -c "import PyOpenColorIO as ocio;\
 print(ocio.GetCurrentConfig().getName())"

Shading

Vulkan and GLSL without the folklore

Modern practice is explicit: you manage memory, synchronisation and pipeline state yourself, and in exchange you get predictable performance. SPIR-V is the portable intermediate representation, so your shader source compiles once and runs on RADV, ANV and NVK without per-vendor rewrites.

  • Prefer Vulkan for new work — explicit control, and every open userspace driver implements it properly.
  • Keep shaders small and inspectable — compile with optimisations off while debugging, and read the SPIR-V disassembly when something is odd.
  • Validate every run in development — the validation layers catch lifetime and synchronisation bugs that otherwise appear only on one vendor.
  • Profile, do not guess — use a real GPU profiler before rewriting a shader that was never the bottleneck.

Example

A fragment shader that respects colour space

#version 450

// Inputs arrive in linear light. Stay linear; do not
// apply gamma here — the display transform owns that.
layout(location = 0) in vec3 vLinear;
layout(location = 1) in vec2 vUv;
layout(location = 0) out vec4 outColour;

layout(set = 0, binding = 0) uniform sampler2D albedo;

// sRGB-encoded texture to linear light.
vec3 srgbToLinear(vec3 c) {
    return mix(c / 12.92,
               pow((c + 0.055) / 1.055, vec3(2.4)),
               step(vec3(0.04045), c));
}

void main() {
    vec3 base = srgbToLinear(texture(albedo, vUv).rgb);
    vec3 lit  = base * max(vLinear, vec3(0.0));
    outColour = vec4(lit, 1.0);   // still linear
}

Compile with glslangValidator -V shader.frag -o shader.spv and load the resulting SPIR-V module. The display transform — sRGB, PQ or an ICC profile — happens after tone mapping, never inside a material shader.

Compute

Portable GPU compute

If your compute kernel matters beyond one vendor's hardware, target a standard rather than a vendor runtime. The toolchains below are usable today on open drivers.

Standard

Vulkan compute

The same driver you already ship. Best portability across AMD, Intel and NVIDIA on Mesa, at the cost of more boilerplate.

Standard

OpenCL

Mature, widely implemented and well suited to data-parallel work outside a render loop. Clover and Rusticl provide open implementations.

Standard

SYCL & oneAPI

Single-source C++ that can target CPUs and GPUs. A pragmatic choice when you want one codebase across devices.

Platform

ROCm

AMD's open compute platform, with HIP for porting CUDA-style code. Excellent on supported cards; check the support matrix first.

Portability caveat

CUDA remains the most mature compute ecosystem, but it is proprietary and ties your project to one vendor. Choose it deliberately for a specific deployment, not by default — and keep the kernel logic separable so a portable path stays possible.

Toolchain

Open applications for real production

Blender

Full 3D pipeline: modelling, sculpting, animation, simulation, Cycles and EEVEE rendering, plus a Python API that makes batch work scriptable.

Krita

Built for painters: brush engines, wrap-around mode, animation and proper colour management. The strongest open alternative for digital painting.

GIMP

Photo retouching and compositing, with GEGL providing high bit-depth processing and a scriptable interface for repetitive tasks.

Inkscape

Vector work with a real SVG core. Round-trips cleanly to other tools because it stores standard SVG rather than a private format.

Godot

An MIT-licensed engine with Vulkan rendering, a readable scene format and no royalties. Good for tools and visualisation, not only games.

FreeCAD & OpenSCAD

Parametric modelling for enclosures and brackets. OpenSCAD's text-based models diff and review like source code, which suits engineering work.

Interchange

Formats that will still open in five years

Preferred open formats by use, with the reason to choose them.
UseFormatWhyAvoid
Intermediate renderOpenEXRFloat or half-float, linear, arbitrary channels and metadata8-bit PNG as a working format
Final still imagePNG / WebPLossless or efficient, universally readableUntagged 8-bit exports
GPU textureKTX2 with Basis UniversalGPU-ready container, transcodable, stays compressed in memoryShipping huge uncompressed PNGs
3D interchangeglTF 2.0Open, compact, PBR by convention, well supportedVendor-specific scene formats
VectorSVGStandard, text-based, diffableFlattened raster exports of logos
Colour transformOCIO configVersionable, shared by every tool in the pipelinePer-artist manual curves
Display profileICC v4Measured from your actual panelAssuming the factory profile is right

Honesty notes

Where open graphics still hurts

Pretending there are no gaps helps nobody. These are the friction points we hit regularly, and what we do about them.

  • New hardware arrives before the driver — a card can be on sale for months before the open driver supports every feature. Check before you buy, not after.
  • Feature parity is uneven — ray tracing, video encode and some extensions differ per vendor. Test your specific workload.
  • Colour pipelines are easy to misconfigure — tools disagree about defaults, so set the working space explicitly in every application.
  • Firmware is often a blob — the driver is open while the microcode is not. It is still far more inspectable than a closed driver stack.

Hardware selection for open stacks

PriorityWhat to look for
Driver maturityUpstream support in your Mesa version, not a vendor PPA
Colour depth10-bit output over DisplayPort or HDMI, verified in the compositor
Compute needsCheck the ROCm or oneAPI support matrix for your exact model
CalibrationA panel with usable OSD controls for gain and bias per channel
RepairabilityStandard fans, standard power connectors, published tear-downs

Verify, always

After every driver or kernel change, re-check the display profile and re-run your reference render. Silent colour regressions are the most expensive bugs in this discipline because nobody notices until delivery.

Next

Put all three tracks on one bench

A networked studio with a calibrated monitoring chain and a colour-managed render machine is the same project viewed three ways. Read how we work, then pick the weakest link in your own setup.