# Alyssa's driver survival guide So you've decided you have what it takes to work on Asahi. It's dangerous to go alone: take this. # Where to clone? Where to submit patches? Mesa upstream is the `main` branch of https://gitlab.freedesktop.org/mesa/mesa/. For Asahi, we merge as much upstream as possible, but upstream Mesa does not yet work with our kernel driver. So, write your patches on top of the `main` branch of https://gitlab.freedesktop.org/asahi/mesa and submit the MR there. That branch is periodically rebased on upstream main, and commits merged there get merged upstream in bulk. That repository is monitored, so there's no need to tell us that you've opened the merge request. You'll want to get comfortable with git, especially with interactive rebases. For hacking on Vulkan, AGXV lives in the `agxv/main` branch of that `asahi/mesa` repository, so if you're working on Vulkan, checkout that branch and submit MRs targetting that branch instead. # Building In general, use a normal Linux system. Debian testing, Fedora, or Arch are all fine. Debian stable is sometimes too old to build tip-of-tree Mesa. YMMV with other distros. Asahi does not depend on LLVM, unless you're building OpenCL support with Rusticl. So usually you'll want to build as: mkdir build && cd build meson ~/mesa -Dgallium-drivers=asahi -Dvulkan-drivers= -Dllvm=disabled ninja Then, inside of your build directory, run meson devenv to get a shell that sets up a development environment, using your new mesa. (Try running `DISPLAY=:0 glxinfo | grep git` and confirm the commit hash matches the tip of your changes. Haven't commited yet? Now's a good time.) That works if you're building Mesa on the same system you're testing on, which you probably are for Asahi. If you're working on AGXV, you'll want `-Dvulkan-drivers=asahi-experimental` to build the Vulkan driver (only works on the AGXV branch). # Getting around Mesa Mesa is fairly well documentted [1]. You don't need to read all the docs, since lots of it is specific to particular drivers or APIs. It's helpful to know about the environment variables Mesa respects [2], including those specific to Asahi [3],[4]. There's some general hardware and driver documentation for Asahi [5]. If you're working on the compiler, you may be interested in the NIR reference. If you're working on the GL driver, there is documentation for Gallium [8], but ignore everything related to TGSI since we use NIR instead. If you're working on the VK driver, there's excellent documentation on Vulkan too [9]. There's also an annotated source tree [10], which may be helpful for understanding how Mesa is organized. [1] https://docs.mesa3d.org/ [2] https://docs.mesa3d.org/envvars.html [3] https://docs.mesa3d.org/envvars.html#envvar-ASAHI_MESA_DEBUG [4] https://docs.mesa3d.org/envvars.html#envvar-AGX_MESA_DEBUG [5] https://docs.mesa3d.org/drivers/asahi.html [7] https://docs.mesa3d.org/nir/index.html [8] https://docs.mesa3d.org/gallium/index.html [9] https://docs.mesa3d.org/vulkan/index.html [10] https://docs.mesa3d.org/sourcetree.html # Hardware documentation Sadly, Apple does not publish documentation for their GPUs. Our driver projects have produced some documentations to fill the gaps, which you can consult in lieu of a specification. Dougall Johnson maintains instruction set documentation [7]. Inside Mesa, this is encoded in some Python that generates C code linked with the compiler [8]. For the hardware data structures (i.e. everything other than the instruction set and kernel-visible stuff), we maintain an XML description [9] using the "GenXML" system (see our `gen_pack.py` file). [7] https://dougallj.github.io/applegpu/docs.html [8] https://gitlab.freedesktop.org/mesa/mesa/-/blob/main/src/asahi/compiler/agx_opcodes.py [9] https://gitlab.freedesktop.org/mesa/mesa/-/blob/main/src/asahi/lib/cmdbuf.xml # Code style In general, we try to follow the Mesa code style [1]. To make this as easy for you as possible, we enforce the use of clang-format. The required `.clang-format` files are already in the Mesa tree (e.g. src/asahi/.clang-format). All you need to do is setup your editor to autoformat code with clang-format. See the clang-format documentation [1] for how to do so in common editors. For vim, I personally use the following configuration in my vimrc which works ok: ``` function! Formatonsave() setlocal formatprg=clang-format let winsaved = winsaveview() execute 'normal gggqG' call winrestview(winsaved) endfunction " https://vi.stackexchange.com/questions/27942/solving-issue-with-clang-format-vim-py-saving-new-buffer autocmd BufWritePre */asahi/*.h,*/asahi/*.c,*/asahi/*.cc,*/asahi/*.cpp call Formatonsave() ``` Do pay attention to the proper form for multiline comments (`/* Text` on the first line and bare `*/` on the last line, somehow different from both the kernel and my natural style). clang-format has a quirk related to designated initializers: you need to use trailing commas to avoid the formatting getting butchered. The proper form looks like: ``` struct foo bar = { .baz = 1, .quux = 2, /* notice the trailing comma here! */ }; ``` For inputting static data tables, you'll want to use `/* clang-format off */`. See `src/panfrost/lib/pan_clear.c` as an example. This escape hatch is seldom necessary otherwise. Other than that, clang-format usually does the right thing for Mesa's C. [1] https://docs.mesa3d.org/codingstyle.html [2] https://clang.llvm.org/docs/ClangFormat.html # Testing the compiler If you're working on one of the compilers, it can be useful to run your modified compiler against a large set of real world shaders. For this, you'll want to download shader-db[3] and read its README on how to use it. For Asahi, see the specific notes at [4]. Those driver-specific links also explain the magic environment variables needed for disassembling shaders, which is invaluable when working on the compiler. # Testing any changes Everything gets tested via the OpenGL ES conformance tests, otherwise known as the drawElement Quality Program (dEQP). For this, clone https://github.com/KhronosGroup/VK-GL-CTS and follow https://github.com/KhronosGroup/VK-GL-CTS/blob/main/external/openglcts/README.md to setup the tests. You probably want to set `DEQP_TARGET` to "surfaceless", something like: ``` $ git clone https://github.com/KhronosGroup/VK-GL-CTS $ cd VK-GL-CTS $ python external/fetch_sources.py $ mkdir build $ cd build $ cmake .. -DDEQP_TARGET=surfaceless -Gninja $ ninja ``` Then to run individual tests: ``` $ cd VK-GL-CTS/build/external/openglcts/modules/ $ EGL_PLATFORM=surfaceless ./glcts --deqp-surface-type=pbuffer --deqp-gl-config-name=rgba8888d24s8ms0 --deqp-surface-width=256 --deqp-surface-height=256 --deqp-log-shader-sources=disable -n dEQP-GLES2.functional.prerequisite.read_pixels ``` where the last argument (`dEQP-GLES2.functional.prerequisite.read_pixels`) is the name of the test you're trying to run. This accepts wildcards, e.g. `dEQP-GLES2.functional.texture.format.*`. For a complete list of tests, look in `VK-GL-CTS/external/openglcts/data/mustpass/gles/aosp_mustpass/master/`, you can grep this for specific features. Vulkan is much less verbose: ``` $ cd VK-GL-CTS/build/external/vulkancts/modules $ ./deqp-vk -n dEQP-VK.glsl.* ``` However, this is not an efficient way of running the conformance tests. For that, you want anholt's `deqp-runner` [6]. Clone and read the linked readme for how to set that one up. You'll want to point it at your build. I have aliases to run dEQP for different APIs. For example, I have a script `run-deqp2` that contains: ``` EGL_PLATFORM=surfaceless deqp-runner run --deqp ~/build-sl/modules/gles2/deqp-gles2 --output output --jobs 8 --renderer-check G13 --caselist /home/alyssa/VK-GL-CTS/external/openglcts/data/mustpass/gles/aosp_mustpass/master/gles2-master.txt --skips ~/mesa/.gitlab-ci/all-skips.txt -- --deqp-surface-type=pbuffer --deqp-gl-config-name=rgba8888d24s8ms0 --deqp-surface-width=256 --deqp-surface-height=256 ``` ...where the `--renderer-check G13` ensures it's running on the GPU driver for the G13 (i.e. the Apple M1). Replace with the appropriate model number for your hardware (G14 for M2, stuff like T860 or G52 for Malis). Otherwise you can ~~steal~~ adapt as needed. Asahi is a conformant OpenGL ES 3.1 driver so there should be no fails running dEQP-GLES2, dEQP-GLES3, or dEQP-GLES31. You will want to run dEQP with deqp-runner on the tip-of-tree first, and then run after with your changes to see whether you have fixed or regressed any tests. (If you regressed any tests, run them individually as explained above and debug your changes until they pass again.) AGXV is very much work-in-progress, so expect lots of fails and try to fix them! # Piglit (advanced) dEQP is only good for GLES and Vulkan. For desktop OpenGL, we have the Piglit test suite [7] and the `piglit-runner` utility bundled with `deqp-runner`. Similar notes apply as for dEQP. You probably don't need to worry about Piglit unless you're working on desktop GL functionality, usually dEQP suffices and is a lot more convenient to use. # Submitting patches Read the upstream docs [8], they apply 100% to Asahi. Note that running `meson test` is probably unnecessary, you can get away running only `meson test --suite=asahi` as applicable, which is a lot faster. Honestly I only run the unit tests I'm working on myself and so far it's been ok (and they run in CI too)... dEQP is much more important. [3] https://gitlab.freedesktop.org/mesa/shader-db [4] https://docs.mesa3d.org/drivers/asahi.html#drm-shim-linux-only [5] https://docs.mesa3d.org/drivers/panfrost.html#drm-shim [6] https://gitlab.freedesktop.org/anholt/deqp-runner [7] https://piglit.freedesktop.org/ [8] https://docs.mesa3d.org/submittingpatches.html # Getting ahold of me The best place is IRC. We hang out on OFTC in `#asahi-gpu`. For general Mesa development, `#dri-devel`. Even when I'm disconnected, I read the backlogs from `#asahi-gpu` (but not `#dri-devel`), so don't ask to ask or wait for me to be around -- just ask. Who knows, maybe someone else will answer before me :-) Asahi Lina (`lina`) is always a safe bet as well. Please do not direct message me. Ask your question in the public channel, that way everyone gets to benefit from the answer. Maybe someone else had your question too but didn't know to ask it. Please do not attempt to contact me outside of these channels. It's easy to find my email but I generally ignore unsolicited email.