lol
1{ stdenv, lib, fetchurl, fetchpatch, buildPackages
2, meson, pkg-config, ninja
3, intltool, bison, flex, file, python3Packages, wayland-scanner
4, expat, libdrm, xorg, wayland, wayland-protocols, openssl
5, llvmPackages_16, libffi, libomxil-bellagio, libva-minimal
6, libelf, libvdpau
7, libglvnd, libunwind, lm_sensors
8, vulkan-loader, glslang
9, galliumDrivers ?
10 if stdenv.isLinux then
11 [
12 "d3d12" # WSL emulated GPU (aka Dozen)
13 "nouveau" # Nvidia
14 "radeonsi" # new AMD (GCN+)
15 "r300" # very old AMD
16 "r600" # less old AMD
17 "swrast" # software renderer (aka LLVMPipe)
18 "svga" # VMWare virtualized GPU
19 "virgl" # QEMU virtualized GPU (aka VirGL)
20 "zink" # generic OpenGL over Vulkan, experimental
21 ] ++ lib.optionals (stdenv.isAarch64 || stdenv.isAarch32) [
22 "etnaviv" # Vivante GPU designs (mostly NXP/Marvell SoCs)
23 "freedreno" # Qualcomm Adreno (all Qualcomm SoCs)
24 "lima" # ARM Mali 4xx
25 "panfrost" # ARM Mali Midgard and up (T/G series)
26 "vc4" # Broadcom VC4 (Raspberry Pi 0-3)
27 ] ++ lib.optionals stdenv.isAarch64 [
28 "tegra" # Nvidia Tegra SoCs
29 "v3d" # Broadcom VC5 (Raspberry Pi 4)
30 ] ++ lib.optionals stdenv.hostPlatform.isx86 [
31 "iris" # new Intel, could work on non-x86 with PCIe cards, but doesn't build as of 22.3.4
32 "crocus" # Intel legacy, x86 only
33 "i915" # Intel extra legacy, x86 only
34 ]
35 else [ "auto" ]
36, vulkanDrivers ?
37 if stdenv.isLinux then
38 [
39 "amd" # AMD (aka RADV)
40 "microsoft-experimental" # WSL virtualized GPU (aka DZN/Dozen)
41 "swrast" # software renderer (aka Lavapipe)
42 ]
43 ++ lib.optionals (stdenv.hostPlatform.isAarch -> lib.versionAtLeast stdenv.hostPlatform.parsed.cpu.version "6") [
44 # QEMU virtualized GPU (aka VirGL)
45 # Requires ATOMIC_INT_LOCK_FREE == 2.
46 "virtio-experimental"
47 ]
48 ++ lib.optionals stdenv.isAarch64 [
49 "broadcom" # Broadcom VC5 (Raspberry Pi 4, aka V3D)
50 "freedreno" # Qualcomm Adreno (all Qualcomm SoCs)
51 "imagination-experimental" # PowerVR Rogue (currently N/A)
52 "panfrost" # ARM Mali Midgard and up (T/G series)
53 ]
54 ++ lib.optionals stdenv.hostPlatform.isx86 [
55 "intel" # Intel (aka ANV), could work on non-x86 with PCIe cards, but doesn't build
56 "intel_hasvk" # Intel Haswell/Broadwell, "legacy" Vulkan driver (https://www.phoronix.com/news/Intel-HasVK-Drop-Dead-Code)
57 ]
58 else [ "auto" ]
59, eglPlatforms ? [ "x11" ] ++ lib.optionals stdenv.isLinux [ "wayland" ]
60, vulkanLayers ? lib.optionals (!stdenv.isDarwin) [ "device-select" "overlay" "intel-nullhw" ] # No Vulkan support on Darwin
61, OpenGL, Xplugin
62, withValgrind ? lib.meta.availableOn stdenv.hostPlatform valgrind-light && !valgrind-light.meta.broken, valgrind-light
63, enableGalliumNine ? stdenv.isLinux
64, enableOSMesa ? stdenv.isLinux
65, enableOpenCL ? stdenv.isLinux && stdenv.isx86_64
66, enablePatentEncumberedCodecs ? true
67, jdupes
68, rustc
69, spirv-llvm-translator
70, zstd
71, directx-headers
72, udev
73}:
74
75/** Packaging design:
76 - The basic mesa ($out) contains headers and libraries (GLU is in libGLU now).
77 This or the mesa attribute (which also contains GLU) are small (~ 2 MB, mostly headers)
78 and are designed to be the buildInput of other packages.
79 - DRI drivers are compiled into $drivers output, which is much bigger and
80 depends on LLVM. These should be searched at runtime in
81 "/run/opengl-driver{,-32}/lib/*" and so are kind-of impure (given by NixOS).
82 (I suppose on non-NixOS one would create the appropriate symlinks from there.)
83 - libOSMesa is in $osmesa (~4 MB)
84*/
85
86let
87 version = "23.1.9";
88 hash = "sha256-KVuifCgUbtCSFOjOea+hZZ7fnRQt7MPJH4BFUtZPdRA=";
89
90 # Release calendar: https://www.mesa3d.org/release-calendar.html
91 # Release frequency: https://www.mesa3d.org/releasing.html#schedule
92 branch = lib.versions.major version;
93
94 withLibdrm = lib.meta.availableOn stdenv.hostPlatform libdrm;
95
96 llvmPackages = llvmPackages_16;
97 # Align all the Mesa versions used. Required to prevent explosions when
98 # two different LLVMs are loaded in the same process.
99 # FIXME: these should really go into some sort of versioned LLVM package set
100 rust-bindgen' = buildPackages.rust-bindgen.override {
101 rust-bindgen-unwrapped = buildPackages.rust-bindgen.unwrapped.override {
102 clang = buildPackages.llvmPackages_15.clang;
103 };
104 };
105 spirv-llvm-translator' = spirv-llvm-translator.override {
106 inherit (llvmPackages) llvm;
107 };
108
109 haveWayland = lib.elem "wayland" eglPlatforms;
110 haveZink = lib.elem "zink" galliumDrivers;
111 haveDozen = (lib.elem "d3d12" galliumDrivers) || (lib.elem "microsoft-experimental" vulkanDrivers);
112self = stdenv.mkDerivation {
113 pname = "mesa";
114 inherit version;
115
116 src = fetchurl {
117 urls = [
118 "https://archive.mesa3d.org/mesa-${version}.tar.xz"
119 "https://mesa.freedesktop.org/archive/mesa-${version}.tar.xz"
120 "ftp://ftp.freedesktop.org/pub/mesa/mesa-${version}.tar.xz"
121 "ftp://ftp.freedesktop.org/pub/mesa/${version}/mesa-${version}.tar.xz"
122 "ftp://ftp.freedesktop.org/pub/mesa/older-versions/${branch}.x/${version}/mesa-${version}.tar.xz"
123 ];
124 inherit hash;
125 };
126
127 # TODO:
128 # revive ./dricore-gallium.patch when it gets ported (from Ubuntu), as it saved
129 # ~35 MB in $drivers; watch https://launchpad.net/ubuntu/+source/mesa/+changelog
130 patches = [
131 # fixes pkgsMusl.mesa build
132 ./musl.patch
133
134 ./opencl.patch
135 ./disk_cache-include-dri-driver-path-in-cache-key.patch
136 ];
137
138 postPatch = ''
139 patchShebangs .
140
141 # The drirc.d directory cannot be installed to $drivers as that would cause a cyclic dependency:
142 substituteInPlace src/util/xmlconfig.c --replace \
143 'DATADIR "/drirc.d"' '"${placeholder "out"}/share/drirc.d"'
144 substituteInPlace src/util/meson.build --replace \
145 "get_option('datadir')" "'${placeholder "out"}/share'"
146 substituteInPlace src/amd/vulkan/meson.build --replace \
147 "get_option('datadir')" "'${placeholder "out"}/share'"
148 '';
149
150 outputs = [ "out" "dev" "drivers" ]
151 ++ lib.optional enableOSMesa "osmesa"
152 ++ lib.optional stdenv.isLinux "driversdev"
153 ++ lib.optional enableOpenCL "opencl"
154 # the Dozen drivers depend on libspirv2dxil, but link it statically, and
155 # libspirv2dxil itself is pretty chonky, so relocate it to its own output
156 # in case anything wants to use it at some point
157 ++ lib.optional haveDozen "spirv2dxil";
158
159 # FIXME: this fixes rusticl/iris segfaulting on startup, _somehow_.
160 # Needs more investigating.
161 separateDebugInfo = true;
162
163 preConfigure = ''
164 PATH=${llvmPackages.libllvm.dev}/bin:$PATH
165 '';
166
167 # TODO: Figure out how to enable opencl without having a runtime dependency on clang
168 mesonFlags = [
169 "--sysconfdir=/etc"
170 "--datadir=${placeholder "drivers"}/share" # Vendor files
171
172 # Don't build in debug mode
173 # https://gitlab.freedesktop.org/mesa/mesa/blob/master/docs/meson.html#L327
174 "-Db_ndebug=true"
175
176 "-Ddisk-cache-key=${placeholder "drivers"}"
177 "-Ddri-search-path=${libglvnd.driverLink}/lib/dri"
178
179 "-Dplatforms=${lib.concatStringsSep "," eglPlatforms}"
180 "-Dgallium-drivers=${lib.concatStringsSep "," galliumDrivers}"
181 "-Dvulkan-drivers=${lib.concatStringsSep "," vulkanDrivers}"
182
183 "-Ddri-drivers-path=${placeholder "drivers"}/lib/dri"
184 "-Dvdpau-libs-path=${placeholder "drivers"}/lib/vdpau"
185 "-Domx-libs-path=${placeholder "drivers"}/lib/bellagio"
186 "-Dva-libs-path=${placeholder "drivers"}/lib/dri"
187 "-Dd3d-drivers-path=${placeholder "drivers"}/lib/d3d"
188
189 "-Dgallium-nine=${lib.boolToString enableGalliumNine}" # Direct3D in Wine
190 "-Dosmesa=${lib.boolToString enableOSMesa}" # used by wine
191 "-Dmicrosoft-clc=disabled" # Only relevant on Windows (OpenCL 1.2 API on top of D3D12)
192
193 # To enable non-mesa gbm backends to be found (e.g. Nvidia)
194 "-Dgbm-backends-path=${libglvnd.driverLink}/lib/gbm:${placeholder "out"}/lib/gbm"
195
196 # meson auto_features enables these features, but we do not want them
197 "-Dandroid-libbacktrace=disabled"
198
199 ] ++ lib.optionals stdenv.isLinux [
200 "-Dglvnd=true"
201
202 # Enable RT for Intel hardware
203 # https://gitlab.freedesktop.org/mesa/mesa/-/issues/9080
204 (lib.mesonEnable "intel-clc" (stdenv.buildPlatform == stdenv.hostPlatform))
205 ] ++ lib.optionals enableOpenCL [
206 # Clover, old OpenCL frontend
207 "-Dgallium-opencl=icd"
208 "-Dopencl-spirv=true"
209
210 # Rusticl, new OpenCL frontend
211 "-Dgallium-rusticl=true" "-Drust_std=2021"
212 "-Dclang-libdir=${llvmPackages.clang-unwrapped.lib}/lib"
213 ] ++ lib.optionals (!withValgrind) [
214 "-Dvalgrind=disabled"
215 ] ++ lib.optional enablePatentEncumberedCodecs
216 "-Dvideo-codecs=h264dec,h264enc,h265dec,h265enc,vc1dec"
217 ++ lib.optional (vulkanLayers != []) "-D vulkan-layers=${builtins.concatStringsSep "," vulkanLayers}";
218
219 buildInputs = with xorg; [
220 expat glslang llvmPackages.libllvm libglvnd xorgproto
221 libX11 libXext libxcb libXt libXfixes libxshmfence libXrandr
222 libffi libvdpau libelf libXvMC
223 libpthreadstubs openssl /*or another sha1 provider*/
224 zstd libunwind
225 python3Packages.python # for shebang
226 ] ++ lib.optionals haveWayland [ wayland wayland-protocols ]
227 ++ lib.optionals stdenv.isLinux [ libomxil-bellagio libva-minimal udev lm_sensors ]
228 ++ lib.optionals enableOpenCL [ llvmPackages.libclc llvmPackages.clang llvmPackages.clang-unwrapped spirv-llvm-translator' ]
229 ++ lib.optional withValgrind valgrind-light
230 ++ lib.optional haveZink vulkan-loader
231 ++ lib.optional haveDozen directx-headers;
232
233 depsBuildBuild = [ pkg-config ]
234 ++ lib.optional enableOpenCL buildPackages.stdenv.cc;
235
236 nativeBuildInputs = [
237 meson pkg-config ninja
238 intltool bison flex file
239 python3Packages.python python3Packages.mako python3Packages.ply
240 jdupes glslang
241 ] ++ lib.optionals enableOpenCL [ rust-bindgen' rustc ]
242 ++ lib.optional haveWayland wayland-scanner;
243
244 propagatedBuildInputs = with xorg; [
245 libXdamage libXxf86vm
246 ] ++ lib.optional withLibdrm libdrm
247 ++ lib.optionals stdenv.isDarwin [ OpenGL Xplugin ];
248
249 doCheck = false;
250
251 postInstall = ''
252 # Some installs don't have any drivers so this directory is never created.
253 mkdir -p $drivers $osmesa
254 '' + lib.optionalString stdenv.isLinux ''
255 mkdir -p $drivers/lib
256
257 if [ -n "$(shopt -s nullglob; echo "$out/lib/libxatracker"*)" -o -n "$(shopt -s nullglob; echo "$out/lib/libvulkan_"*)" ]; then
258 # move gallium-related stuff to $drivers, so $out doesn't depend on LLVM
259 mv -t $drivers/lib \
260 $out/lib/libpowervr_rogue* \
261 $out/lib/libxatracker* \
262 $out/lib/libvulkan_*
263 fi
264
265 if [ -n "$(shopt -s nullglob; echo "$out"/lib/lib*_mesa*)" ]; then
266 # Move other drivers to a separate output
267 mv -t $drivers/lib $out/lib/lib*_mesa*
268 fi
269
270 # Update search path used by glvnd
271 for js in $drivers/share/glvnd/egl_vendor.d/*.json; do
272 substituteInPlace "$js" --replace '"libEGL_' '"'"$drivers/lib/libEGL_"
273 done
274
275 # Update search path used by Vulkan (it's pointing to $out but
276 # drivers are in $drivers)
277 for js in $drivers/share/vulkan/icd.d/*.json; do
278 substituteInPlace "$js" --replace "$out" "$drivers"
279 done
280 '' + lib.optionalString enableOpenCL ''
281 # Move OpenCL stuff
282 mkdir -p $opencl/lib
283 mv -t "$opencl/lib/" \
284 $out/lib/gallium-pipe \
285 $out/lib/lib*OpenCL*
286
287 # We construct our own .icd files that contain absolute paths.
288 mkdir -p $opencl/etc/OpenCL/vendors/
289 echo $opencl/lib/libMesaOpenCL.so > $opencl/etc/OpenCL/vendors/mesa.icd
290 echo $opencl/lib/libRusticlOpenCL.so > $opencl/etc/OpenCL/vendors/rusticl.icd
291 '' + lib.optionalString enableOSMesa ''
292 # move libOSMesa to $osmesa, as it's relatively big
293 mkdir -p $osmesa/lib
294 mv -t $osmesa/lib/ $out/lib/libOSMesa*
295 '' + lib.optionalString (vulkanLayers != []) ''
296 mv -t $drivers/lib $out/lib/libVkLayer*
297 for js in $drivers/share/vulkan/{im,ex}plicit_layer.d/*.json; do
298 substituteInPlace "$js" --replace '"libVkLayer_' '"'"$drivers/lib/libVkLayer_"
299 done
300 '' + lib.optionalString haveDozen ''
301 mkdir -p $spirv2dxil/{bin,lib}
302 mv -t $spirv2dxil/lib $out/lib/libspirv_to_dxil*
303 mv -t $spirv2dxil/bin $out/bin/spirv2dxil
304 '';
305
306 postFixup = lib.optionalString stdenv.isLinux ''
307 # set the default search path for DRI drivers; used e.g. by X server
308 substituteInPlace "$dev/lib/pkgconfig/dri.pc" --replace "$drivers" "${libglvnd.driverLink}"
309 [ -f "$dev/lib/pkgconfig/d3d.pc" ] && substituteInPlace "$dev/lib/pkgconfig/d3d.pc" --replace "$drivers" "${libglvnd.driverLink}"
310
311 # remove pkgconfig files for GL/EGL; they are provided by libGL.
312 rm -f $dev/lib/pkgconfig/{gl,egl}.pc
313
314 # Move development files for libraries in $drivers to $driversdev
315 mkdir -p $driversdev/include
316 mv $dev/include/xa_* $dev/include/d3d* -t $driversdev/include || true
317 mkdir -p $driversdev/lib/pkgconfig
318 for pc in lib/pkgconfig/{xatracker,d3d}.pc; do
319 if [ -f "$dev/$pc" ]; then
320 substituteInPlace "$dev/$pc" --replace $out $drivers
321 mv $dev/$pc $driversdev/$pc
322 fi
323 done
324
325 # Don't depend on build python
326 patchShebangs --host --update $out/bin/*
327
328 # NAR doesn't support hard links, so convert them to symlinks to save space.
329 jdupes --hard-links --link-soft --recurse "$drivers"
330
331 # add RPATH so the drivers can find the moved libgallium and libdricore9
332 # moved here to avoid problems with stripping patchelfed files
333 for lib in $drivers/lib/*.so* $drivers/lib/*/*.so*; do
334 if [[ ! -L "$lib" ]]; then
335 patchelf --set-rpath "$(patchelf --print-rpath $lib):$drivers/lib" "$lib"
336 fi
337 done
338 # add RPATH here so Zink can find libvulkan.so
339 ${lib.optionalString haveZink ''
340 patchelf --add-rpath ${vulkan-loader}/lib $drivers/lib/dri/zink_dri.so
341 ''}
342 '';
343
344 env.NIX_CFLAGS_COMPILE = toString (lib.optionals stdenv.isDarwin [ "-fno-common" ] ++ lib.optionals enableOpenCL [
345 "-UPIPE_SEARCH_DIR"
346 "-DPIPE_SEARCH_DIR=\"${placeholder "opencl"}/lib/gallium-pipe\""
347 ]);
348
349 passthru = {
350 inherit (libglvnd) driverLink;
351 inherit llvmPackages;
352
353 libdrm = if withLibdrm then libdrm else null;
354
355 tests = lib.optionalAttrs stdenv.isLinux {
356 devDoesNotDependOnLLVM = stdenv.mkDerivation {
357 name = "mesa-dev-does-not-depend-on-llvm";
358 buildCommand = ''
359 echo ${self.dev} >>$out
360 '';
361 disallowedRequisites = [ llvmPackages.llvm self.drivers ];
362 };
363 };
364 };
365
366 meta = with lib; {
367 description = "An open source 3D graphics library";
368 longDescription = ''
369 The Mesa project began as an open-source implementation of the OpenGL
370 specification - a system for rendering interactive 3D graphics. Over the
371 years the project has grown to implement more graphics APIs, including
372 OpenGL ES (versions 1, 2, 3), OpenCL, OpenMAX, VDPAU, VA API, XvMC, and
373 Vulkan. A variety of device drivers allows the Mesa libraries to be used
374 in many different environments ranging from software emulation to
375 complete hardware acceleration for modern GPUs.
376 '';
377 homepage = "https://www.mesa3d.org/";
378 changelog = "https://www.mesa3d.org/relnotes/${version}.html";
379 license = licenses.mit; # X11 variant, in most files
380 platforms = platforms.mesaPlatforms;
381 maintainers = with maintainers; [ primeos vcunat ]; # Help is welcome :)
382
383 # https://gitlab.freedesktop.org/mesa/mesa/-/issues/8634
384 broken = stdenv.isDarwin;
385 };
386};
387
388in self