diff --git a/docs/drivers/kosmickrisp.rst b/docs/drivers/kosmickrisp.rst new file mode 100644 index 00000000000..85967093bfb --- /dev/null +++ b/docs/drivers/kosmickrisp.rst @@ -0,0 +1,97 @@ +KosmicKrisp +########### + +KosmicKrisp is a Vulkan conformant implementation for macOS on Apple Silicon +hardware. It is implemented on top of Metal 4, which requires macOS 26 and up. + +No iOS support is present as of now. However, iOS was taken into consideration +during development to support A14 Bionic GPUs and upwards. + +Building +******** + +The following build instructions assume Homebrew as the package manager to +install dependencies. Homebrew homepage https://brew.sh/ +Homebrew install command line: + +.. code-block:: sh + + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + +Terminal restart is recommended after Homebrew installation. + +Requirements +============ + +- Xcode and Xcode command line tools +- Homebrew packages + - meson (1.9.1+, can also be installed as a Python package) + - cmake + - pkg-config + - libclc + - llvm + - spirv-llvm-translator + +Due to potential conflicts, Homebrew will not add `llvm` to the path. To add +`llvm` to future terminal instances: + +.. code-block:: sh + + echo 'export PATH="/opt/homebrew/opt/llvm/bin:$PATH"' >> ~/.zshrc + +To add `llvm` to current terminal instance: + +.. code-block:: sh + + export PATH="/opt/homebrew/opt/llvm/bin:$PATH" + +- Python +- Python packages + - mako + - packaging + - pyyaml + - meson (1.9.1+, if not installed through Homebrew) + +Since Homebrew manages the Python environment, it is encouraged to create a +Python virtual environment and install all packages in that environment. To +create a Python virtual environment (e.g. ``$HOME/venv_mesa``): + +.. code-block:: sh + + python3 -m venv $HOME/venv_mesa + +To enable a Python virtual environment: + +.. code-block:: sh + + source $HOME/venv_mesa/bin/activate + +Build instructions +================== + +Out of tree build directory is recommended. + +Once all requirements have been installed, the following command line can be +used to create a debug build: + +.. code-block:: sh + + meson setup --buildtype=debug -Dplatforms=macos -Dvulkan-drivers=kosmickrisp -Dgallium-drivers= -Dopengl=false -Dzstd=disabled + +Metal workarounds +***************** + +Different workarounds are applied throughout the project to avoid issues such +as: + +- Metal API and Vulkan API discrepancies +- Metal bugs +- MSL compiler bugs +- MSL compiler crashes + +These workarounds can be found in: + +.. toctree:: + :maxdepth: 1 + + kosmickrisp/workarounds diff --git a/docs/drivers/kosmickrisp/workarounds.rst b/docs/drivers/kosmickrisp/workarounds.rst new file mode 100644 index 00000000000..8b0910cbe65 --- /dev/null +++ b/docs/drivers/kosmickrisp/workarounds.rst @@ -0,0 +1,135 @@ +KosmicKrisp workarounds +####################### + +This file documents the relevant issues found in either Metal, the MSL +compiler or any other component we have no control over that needed to be +worked around to accomplish Vulkan conformance. + +All workarounds must be documented here and no code comment info should be +provided other than the name ``KK_WORKAROUND_#``. + +Once a workaround was removed from the code, the code comment will be +removed but the documentation here will be kept. + +Template +======== + +Use the following template to create documentation for a new workaround: + +.. code-block:: + + KK_WORKAROUND_# + --------------- + | macOS version: + | Metal ticket: + | Metal ticket status: + | CTS test failure/crash: + | Comments: + | Log: + +``macOS version`` needs to have the OS version with which it was found. + +``Metal ticket`` needs to be either the Metal ticket number with the GitLab +handle of the user that reported the ticket or ``Unreported``. + +``Metal ticket status`` needs to be either ``Fixed in macOS # (Build hash)``, + +``Waiting resolution`` or empty if unreported. If Apple reported that the issue +was fixed, but no user has verified the fix, append ``[Untested]``. +``CTS test failure/crash`` (remove ``failure`` or ``crash`` based on test +behavior) needs to be the name of the test or test family the issue can be +reproduced with. + +``Comments`` needs to include as much information on the issue and how the +workaround fixes it. + +``Log`` needs to have the dates (yyyy-mm-dd, the only correct date format) with +info on what was updated. + +Workarounds +=========== + +KK_WORKAROUND_3 +--------------- +| macOS version: 15.4.x +| Metal ticket: FB20113490 (@aitor) +| Metal ticket status: Waiting resolution +| CTS test failure: ``dEQP-VK.subgroups.ballot_other.*.subgroupballotfindlsb`` +| Comments: + +``simd_is_first`` does not seem to behave as documented in the MSL +specification. The following code snippet misbehaves: + +.. code-block:: c + + if (simd_is_first()) + temp = 3u; + else + temp = simd_ballot(true); /* <- This will return all active threads... */ + +The way to fix this is by changing the conditional to: + +.. code-block:: c + + if (simd_is_first() && (ulong)simd_ballot(true)) + temp = 3u; + else + temp = (ulong)simd_ballot(true); + +| Log: +| 2025-09-09: Workaround implemented and reported to Apple + +KK_WORKAROUND_2 +--------------- +| macOS version: 15.4.x +| Metal ticket: Not reported +| Metal ticket status: +| CTS test crash: ``dEQP-VK.graphicsfuzz.cov-nested-loops-never-change-array-element-one`` and ``dEQP-VK.graphicsfuzz.disc-and-add-in-func-in-loop`` +| Comments: + +We need to loop to infinite since MSL compiler crashes if we have something +like (simplified version): + +.. code-block:: c + + while (true) { + if (some_conditional) { + break_loop = true; + } else { + break_loop = false; + } + if (break_loop) { + break; + } + } + +The issue I believe is that ``some_conditional`` wouldn't change the value no +matter in which iteration we are (something like fetching the same value from +a buffer) and the MSL compiler doesn't seem to like that much to the point it +crashes. + +The implemented solution is to change the ``while(true)`` loop with +``for (uint64_t no_crash = 0u; no_crash < UINT64_MAX; ++no_crash)``, which +tricks the MSL compiler into believing we are not doing an infinite loop +(wink wink). + +| Log: +| 2025-09-08: Workaround implemented + +KK_WORKAROUND_1 +--------------- +| macOS version: 15.4.x +| Metal ticket: FB17604106 (@aitor) +| Metal ticket status: [Untested] Fixed in macOS 26 Beta (25A5279m) +| CTS test crash: ``dEQP-VK.glsl.indexing.tmp_array.vec3_dynamic_loop_write_dynamic_loop_read_fragment`` +| Comments: + +Uninitialized local scratch variable causes the MSL compiler to crash. +Initialize scratch to avoid issue. + +| Log: +| 2025-05-14: Workaround implemented and reported to Apple +| 2025-06-14: Apple reported back saying it is now fixed in macOS 26 Beta (Build 25A5279m) + + + diff --git a/docs/index.rst b/docs/index.rst index 36b6acd2192..f6b3b808642 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -83,6 +83,7 @@ Linux, FreeBSD, and other operating systems. drivers/asahi drivers/d3d12 drivers/freedreno + drivers/kosmickrisp drivers/lima drivers/llvmpipe drivers/nvk diff --git a/src/kosmickrisp/compiler/nir_to_msl.c b/src/kosmickrisp/compiler/nir_to_msl.c index 3fd3f375ffd..6f6198a73dd 100644 --- a/src/kosmickrisp/compiler/nir_to_msl.c +++ b/src/kosmickrisp/compiler/nir_to_msl.c @@ -111,6 +111,7 @@ emit_local_vars(struct nir_to_msl_ctx *ctx, nir_shader *shader) shader->info.shared_size); } if (shader->scratch_size) { + /* KK_WORKAROUND_1 */ P_IND(ctx, "uchar scratch[%d] = {0};\n", shader->scratch_size); } if (BITSET_TEST(shader->info.system_values_read, @@ -1355,16 +1356,7 @@ intrinsic_to_msl(struct nir_to_msl_ctx *ctx, nir_intrinsic_instr *instr) P(ctx, ");\n"); break; case nir_intrinsic_elect: - /* If we don't add && "(ulong)simd_ballot(true)"" the following CTS tests - * fail: - * dEQP-VK.subgroups.ballot_other.graphics.subgroupballotfindlsb - * dEQP-VK.subgroups.ballot_other.compute.subgroupballotfindlsb - * Weird Metal bug: - * if (simd_is_first()) - * temp = 3u; - * else - * temp = simd_ballot(true); <- This will return all active threads... - */ + /* KK_WORKAROUND_3 */ P(ctx, "simd_is_first() && (ulong)simd_ballot(true);\n"); break; case nir_intrinsic_read_first_invocation: @@ -1789,27 +1781,7 @@ cf_node_to_metal(struct nir_to_msl_ctx *ctx, nir_cf_node *node) case nir_cf_node_loop: { nir_loop *loop = nir_cf_node_as_loop(node); assert(!nir_loop_has_continue_construct(loop)); - /* We need to loop to infinite since MSL compiler crashes if we have - something like (simplified version): - * // clang-format off - * while (true) { - * if (some_conditional) { - * break_loop = true; - * } else { - * break_loop = false; - * } - * if (break_loop) { - * break; - * } - * } - * // clang-format on - * The issue I believe is that some_conditional wouldn't change the value - * no matter in which iteration we are (something like fetching the same - * value from a buffer) and the MSL compiler doesn't seem to like that - * much to the point it crashes. - * With this for loop now, we trick the MSL compiler into believing we are - * not doing an infinite loop (wink wink) - */ + /* KK_WORKAROUND_2 */ P_IND(ctx, "for (uint64_t no_crash = 0u; no_crash < %" PRIu64 "; ++no_crash) {\n",