mesa-clc: vendor as full-fork recipe (path=source, patches baked)

This commit is contained in:
2026-08-01 04:44:05 +03:00
parent f8e4789a2b
commit 406ee9fbeb
12522 changed files with 6035591 additions and 3 deletions
@@ -0,0 +1,72 @@
NIR ALU Instructions
====================
ALU instructions represent simple operations, such as addition, multiplication,
comparison, etc., that take a certain number of arguments and return a result
that only depends on the arguments. ALU instructions in NIR must be pure in
the sense that they have no side effect and that identical inputs yields an
identical output. A good rule of thumb is that only things which can be
constant folded should be ALU operations. If it can't be constant folded, then
it should probably be an intrinsic instead.
Each ALU instruction has an opcode, which is a member of the :c:enum:`nir_op`
enum, that describes what it does as well as how many arguments it takes.
Associated with each opcode is an metadata structure,
:c:struct:`nir_op_info`, which shows how many arguments the opcode takes,
information about data types, and algebraic properties such as associativity
and commutativity. The info structure for each opcode may be accessed through
a global :c:var:`nir_op_infos` array thats indexed by the opcode.
ALU operations are typeless, meaning that they're only defined to convert
a certain bit-pattern input to another bit-pattern output. The only concrete
notion of types for a NIR SSA value or register is that each value has a number
of vector components and a bit-size. How that data is interpreted is entirely
controlled by the opcode. NIR doesn't have opcodes for ``intBitsToFloat()``
and friends because they are implicit.
Even though ALU operations are typeless, each opcode also has an "ALU type"
metadata for each of the sources and the destination which can be
floating-point, boolean, integer, or unsigned integer. The ALU type mainly
helps back-ends which want to handle all conversion instructions, for instance,
in a single switch case. They're also important when a back-end requests the
absolute value, negate, and saturate modifiers (not used by core NIR). In that
case, modifiers are interpreted with respect to the ALU type on the source or
destination of the instruction. In addition, if an operation takes a boolean
argument, then the argument may be assumed to be either ``0`` for false or
``~0`` (a.k.a ``-1``) for true even if it is not a 1-bit value. If an
operations result has a boolean type, then it may only produce only ``0`` or ``~0``.
Most of the common ALU ops in NIR operate per-component, meaning that the
operation is defined by what it does on a single scalar value and, when
performed on vectors, it performs the same operation on each component. Things
like add, multiply, etc. fall into this category. Per-component operations
naturally scale to as many components as necessary. Non-per-component ALU ops
are things like :nir:alu-op:`vec4` or :nir:alu-op:`pack_64_2x32` where any
given component in the result value may be a combination of any component in
any source. These ops have a number of destination components and a number of
components required by each source which is fixed by the opcode.
While most instruction types in NIR require vector sizes to perfectly match on
inputs and outputs, ALU instruction sources have an additional
:c:member:`nir_alu_src.swizzle` field which allows them to act on vectors
which are not the native vector size of the instruction. This is ideal for
hardware with a native data type of :nir:alu-op:`vec4` but also means that ALU
instructions are often used (and required) for packing/unpacking vectors for
use in other instruction types like intrinsics or texture ops.
.. c:autostruct:: nir_op_info
:file: src/compiler/nir/nir.h
:members:
.. c:autovar:: nir_op_infos
.. c:autostruct:: nir_alu_instr
:members:
.. c:autostruct:: nir_alu_src
:members:
NIR ALU Opcode Reference:
-------------------------
.. nir:alu-opcodes::
@@ -0,0 +1,15 @@
NIR Intermediate Representation (NIR)
=====================================
The NIR Intermediate Representation (NIR) is the optimizing compiler stack that
sits at the core of most Mesa drivers' shader compilers. It consists of a set
of enums and data structures that make up the IR as well as a suite of helper
functions, optimization passes, and lowering passes for building a compiler
stack.
.. toctree::
:maxdepth: 2
alu
tex
unit-testing
@@ -0,0 +1,83 @@
NIR Texture Instructions
========================
Even though texture instructions *could* be supported as intrinsics, the vast
number of combinations mean that doing so is practically impossible. Instead,
NIR has a dedicated texture instruction. There are several texture operations:
.. c:autoenum:: nir_texop
:file: src/compiler/nir/nir.h
:members:
As with other instruction types, there is still an array of sources, except
that each source also has a *type* associated with it. There are various
source types, each corresponding to a piece of information that the different
texture operations require.
.. c:autoenum:: nir_tex_src_type
:members:
Of particular interest are the texture/sampler deref/index/handle source types.
First, note that textures and samplers are specified separately in NIR. While
not required for OpenGL, this is required for Vulkan and OpenCL. Some
OpenGL [ES] drivers have to deal with hardware that does not have separate
samplers and textures. While not recommended, an OpenGL-only driver may assume
that the texture and sampler derefs will always point to the same resource, if
needed. Note that this pretty well paints your compiler into a corner and
makes any future port to Vulkan or OpenCL harder, so such assumptions should
really only be made if targeting OpenGL ES 2.0 era hardware.
Also, like a lot of other resources, there are multiple ways to represent a
texture in NIR. It can be referenced by a variable dereference, an index, or a
bindless handle. When using an index or a bindless handle, the texture type
information is generally not available. To handle this, various information
from the type is redundantly stored in the :c:struct:`nir_tex_instr` itself.
.. c:autostruct:: nir_tex_instr
:members:
.. c:autostruct:: nir_tex_src
:members:
Texture instruction helpers
---------------------------
There are a number of helper functions for working with NIR texture
instructions. They are documented here in no particular order.
.. c:autofunction:: nir_tex_instr_create
.. c:autofunction:: nir_tex_instr_need_sampler
.. c:autofunction:: nir_tex_instr_result_size
.. c:autofunction:: nir_tex_instr_dest_size
.. c:autofunction:: nir_tex_instr_is_query
.. c:autofunction:: nir_tex_instr_has_implicit_derivative
.. c:autofunction:: nir_tex_instr_src_type
.. c:autofunction:: nir_tex_instr_src_size
.. c:autofunction:: nir_tex_instr_src_index
.. c:autofunction:: nir_tex_instr_add_src
.. c:autofunction:: nir_tex_instr_remove_src
Texture instruction lowering
----------------------------
Because most hardware only supports some subset of all possible GLSL/SPIR-V
texture operations, NIR provides a quite powerful lowering pass which is able
to implement more complex texture operations in terms of simpler ones.
.. c:autofunction:: nir_lower_tex
.. c:autostruct:: nir_lower_tex_options
:members:
.. c:autoenum:: nir_lower_tex_packing
:members:
@@ -0,0 +1,80 @@
Writing and running NIR unit tests
==================================
NIR uses `gtest <https://github.com/google/googletest>`__
for unit testing lowering and optimization passes. Tests
should declare a class to use for all test cases:
.. code:: c++
class nir_my_pass_test : public nir_test {
protected:
nir_my_pass_test();
void run_pass(nir_reference_shader expected);
/* Resources used by the test */
}
nir_my_pass_test::nir_my_pass_test()
: nir_test::nir_test("nir_my_pass_test")
{
/* Create resources used by the test */
}
void nir_my_pass_test::run_pass(nir_reference_shader expected)
{
nir_validate_shader(b->shader, "before nir_my_pass");
NIR_PASS(_, b->shader, nir_my_pass);
check_nir_string(expected);
}
With this setup, the individual test cases can use ``nir_builder``
to initialize a shader, run the pass that should be tested on it
and compare it against a string, containing the expected pass
output:
.. code:: c++
TEST_F(nir_my_pass_test, basic)
{
run_pass(NIR_REFERENCE_SHADER(R"(
shader: MESA_SHADER_COMPUTE
name: nir_my_pass_test
workgroup_size: 1, 1, 1
subgroup_size: 0
decl_function main () (entrypoint)
impl main {
block b0: // preds:
}
)"));
}
The expected string can be managed using the
``bin/nir-test-runner.py`` script which builds and runs NIR
unit tests. The output of the tests are compared against the
expectations. The runner can then optionally update the
expectations.
.. code::
user@distro:~/mesa$ python bin/nir-test-runner.py -Bbuild
INFO: autodetecting backend as ninja
INFO: calculating backend command to run: /usr/bin/ninja -C /home/konstantin/dev/mesa/build
ninja: Entering directory `/home/konstantin/dev/mesa/build'
[1/1] Generating src/git_sha1.h with a custom command
diff --git a/src/compiler/nir/tests/opt_loop_tests.cpp b/src/compiler/nir/tests/opt_loop_tests.cpp
index 05d3c6357c6..0d4810c5f85 100644
--- a/src/compiler/nir/tests/opt_loop_tests.cpp
+++ b/src/compiler/nir/tests/opt_loop_tests.cpp
@@ -136,6 +136,7 @@ TEST_F(nir_opt_loop_test, opt_loop_merge_terminators_break_in_then)
check_nir_string(NIR_REFERENCE_SHADER(R"(
shader: MESA_SHADER_FRAGMENT
name: nir_opt_loop_test
+ subgroup_size: 0
decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
Apply the changes listed above? [Y/n]y