docs,nir: Document NIR texture instructions

Reviewed-by: Emma Anholt <emma@anholt.net>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Alyssa Rosenzweig <alyssa@collabora.com>
Reviewed-by: Connor Abbott <cwabbott0@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11775>
This commit is contained in:
Jason Ekstrand 2021-07-07 17:44:27 -05:00 committed by Marge Bot
parent 4465ca296d
commit fa717a202c
3 changed files with 274 additions and 34 deletions

View File

@ -11,3 +11,4 @@ stack.
:maxdepth: 2
alu
tex

67
docs/nir/tex.rst Normal file
View File

@ -0,0 +1,67 @@
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:
.. doxygenenum:: nir_texop
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.
.. doxygenenum:: nir_tex_src_type
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 :cpp:struct:`nir_tex_instr` itself.
.. doxygenstruct:: nir_tex_instr
:members:
.. doxygenstruct:: 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.
.. doxygenfunction:: nir_tex_instr_create
.. doxygenfunction:: nir_tex_instr_need_sampler
.. doxygenfunction:: nir_tex_instr_result_size
.. doxygenfunction:: nir_tex_instr_dest_size
.. doxygenfunction:: nir_tex_instr_is_query
.. doxygenfunction:: nir_tex_instr_has_implicit_derivative
.. doxygenfunction:: nir_tex_instr_src_type
.. doxygenfunction:: nir_tex_instr_src_size
.. doxygenfunction:: nir_tex_instr_src_index
.. doxygenfunction:: nir_tex_instr_add_src
.. doxygenfunction:: 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.
.. doxygenfunction:: nir_lower_tex
.. doxygenstruct:: nir_lower_tex_options
:members:
.. doxygenenum:: nir_lower_tex_packing

View File

@ -2010,40 +2010,135 @@ nir_intrinsic_can_reorder(nir_intrinsic_instr *instr)
bool nir_intrinsic_writes_external_memory(const nir_intrinsic_instr *instr);
/**
* \group texture information
*
* This gives semantic information about textures which is useful to the
* frontend, the backend, and lowering passes, but not the optimizer.
*/
/** Texture instruction source type */
typedef enum {
/** Texture coordinate
*
* Must have nir_tex_instr::coord_components components.
*/
nir_tex_src_coord,
/** Projector
*
* The texture coordinate (except for the array component, if any) is
* divided by this value before LOD computation and sampling.
*
* Must be a float scalar.
*/
nir_tex_src_projector,
nir_tex_src_comparator, /* shadow comparator */
/** Shadow comparator
*
* For shadow sampling, the fetched texel values are compared against the
* shadow comparator using the compare op specified by the sampler object
* and converted to 1.0 if the comparison succeeds and 0.0 if it fails.
* Interpolation happens after this conversion so the actual result may be
* anywhere in the range [0.0, 1.0].
*
* Only valid if nir_tex_instr::is_shadow and must be a float scalar.
*/
nir_tex_src_comparator,
/** Coordinate offset
*
* An integer value that is added to the texel address before sampling.
* This is only allowed with operations that take an explicit LOD as it is
* applied in integer texel space after LOD selection and not normalized
* coordinate space.
*/
nir_tex_src_offset,
/** LOD bias
*
* This value is added to the computed LOD before mip-mapping.
*/
nir_tex_src_bias,
/** Explicit LOD */
nir_tex_src_lod,
/** Min LOD
*
* The computed LOD is clamped to be at least as large as min_lod before
* mip-mapping.
*/
nir_tex_src_min_lod,
nir_tex_src_ms_index, /* MSAA sample index */
nir_tex_src_ms_mcs_intel, /* MSAA compression value */
/** MSAA sample index */
nir_tex_src_ms_index,
/** Intel-specific MSAA compression data */
nir_tex_src_ms_mcs_intel,
/** Explicit horizontal (X-major) coordinate derivative */
nir_tex_src_ddx,
/** Explicit vertical (Y-major) coordinate derivative */
nir_tex_src_ddy,
nir_tex_src_texture_deref, /* < deref pointing to the texture */
nir_tex_src_sampler_deref, /* < deref pointing to the sampler */
nir_tex_src_texture_offset, /* < dynamically uniform indirect offset */
nir_tex_src_sampler_offset, /* < dynamically uniform indirect offset */
nir_tex_src_texture_handle, /* < bindless texture handle */
nir_tex_src_sampler_handle, /* < bindless sampler handle */
nir_tex_src_plane, /* < selects plane for planar textures */
/** Texture variable dereference */
nir_tex_src_texture_deref,
/** Sampler variable dereference */
nir_tex_src_sampler_deref,
/** Texture index offset
*
* This is added to nir_tex_instr::texture_index. Unless
* nir_tex_instr::texture_non_uniform is set, this is guaranteed to be
* dynamically uniform.
*/
nir_tex_src_texture_offset,
/** Dynamically uniform sampler index offset
*
* This is added to nir_tex_instr::sampler_index. Unless
* nir_tex_instr::sampler_non_uniform is set, this is guaranteed to be
* dynamically uniform.
*/
nir_tex_src_sampler_offset,
/** Bindless texture handle
*
* This is, unfortunately, a bit overloaded at the moment. There are
* generally two types of bindless handles:
*
* 1. For GL_ARB_bindless bindless handles. These are part of the
* GL/Gallium-level API and are always a 64-bit integer.
*
* 2. HW-specific handles. GL_ARB_bindless handles may be lowered to
* these. Also, these are used by many Vulkan drivers to implement
* descriptor sets, especially for UPDATE_AFTER_BIND descriptors.
* The details of hardware handles (bit size, format, etc.) is
* HW-specific.
*
* Because of this overloading and the resulting ambiguity, we currently
* don't validate anything for these.
*/
nir_tex_src_texture_handle,
/** Bindless sampler handle
*
* See nir_tex_src_texture_handle,
*/
nir_tex_src_sampler_handle,
/** Plane index for multi-plane YCbCr textures */
nir_tex_src_plane,
nir_num_tex_src_types
} nir_tex_src_type;
/** A texture instruction source */
typedef struct {
/** Base source */
nir_src src;
/** Type of this source */
nir_tex_src_type src_type;
} nir_tex_src;
/** Texture instruction opcode */
typedef enum {
nir_texop_tex, /**< Regular texture look-up */
nir_texop_txb, /**< Texture look-up with LOD bias */
@ -2066,43 +2161,88 @@ typedef enum {
nir_texop_fragment_mask_fetch,/**< Multisample fragment mask texture fetch */
} nir_texop;
/** Represents a texture instruction */
typedef struct {
/** Base instruction */
nir_instr instr;
/** Dimensionality of the texture operation
*
* This will typically match the dimensionality of the texture deref type
* if a nir_tex_src_texture_deref is present. However, it may not if
* texture lowering has occurred.
*/
enum glsl_sampler_dim sampler_dim;
/** ALU type of the destination
*
* This is the canonical sampled type for this texture operation and may
* not exactly match the sampled type of the deref type when a
* nir_tex_src_texture_deref is present. For OpenCL, the sampled type of
* the texture deref will be GLSL_TYPE_VOID and this is allowed to be
* anything. With SPIR-V, the signedness of integer types is allowed to
* differ. For all APIs, the bit size may differ if the driver has done
* any sort of mediump or similar lowering since texture types always have
* 32-bit sampled types.
*/
nir_alu_type dest_type;
/** Texture opcode */
nir_texop op;
/** Destination */
nir_dest dest;
/** Array of sources
*
* This array has nir_tex_instr::num_srcs elements
*/
nir_tex_src *src;
unsigned num_srcs, coord_components;
bool is_array, is_shadow;
/** Number of sources */
unsigned num_srcs;
/** Number of components in the coordinate, if any */
unsigned coord_components;
/** True if the texture instruction acts on an array texture */
bool is_array;
/** True if the texture instruction performs a shadow comparison
*
* If this is true, the texture instruction must have a
* nir_tex_src_comparator.
*/
bool is_shadow;
/**
* If is_shadow is true, whether this is the old-style shadow that outputs 4
* components or the new-style shadow that outputs 1 component.
* If is_shadow is true, whether this is the old-style shadow that outputs
* 4 components or the new-style shadow that outputs 1 component.
*/
bool is_new_style_shadow;
/**
* If this texture instruction should return a sparse residency code. The
* code is in the last component of the result.
* True if this texture instruction should return a sparse residency code.
* The code is in the last component of the result.
*/
bool is_sparse;
/* gather component selector */
/** nir_texop_tg4 component selector
*
* This determines which RGBA component is gathered.
*/
unsigned component : 2;
/* Validation needs to know this for gradient component count */
/** Validation needs to know this for gradient component count */
unsigned array_is_lowered_cube : 1;
/* gather offsets */
/** Gather offsets */
int8_t tg4_offsets[4][2];
/* True if the texture index or handle is not dynamically uniform */
/** True if the texture index or handle is not dynamically uniform */
bool texture_non_uniform;
/* True if the sampler index or handle is not dynamically uniform */
/** True if the sampler index or handle is not dynamically uniform */
bool sampler_non_uniform;
/** The texture index
@ -2129,12 +2269,13 @@ typedef struct {
unsigned sampler_index;
} nir_tex_instr;
/*
* Returns true if the texture operation requires a sampler as a general rule,
* see the documentation of sampler_index.
/**
* Returns true if the texture operation requires a sampler as a general rule
*
* Note that the specific hw/driver backend could require to a sampler
* object/configuration packet in any case, for some other reason.
*
* @see nir_tex_instr::sampler_index.
*/
static inline bool
nir_tex_instr_need_sampler(const nir_tex_instr *instr)
@ -2152,6 +2293,12 @@ nir_tex_instr_need_sampler(const nir_tex_instr *instr)
}
}
/** Returns the number of components returned by this nir_tex_instr
*
* Useful for code building texture instructions when you don't want to think
* about how many components a particular texture op returns. This does not
* include the sparse residency code.
*/
static inline unsigned
nir_tex_instr_result_size(const nir_tex_instr *instr)
{
@ -2199,6 +2346,10 @@ nir_tex_instr_result_size(const nir_tex_instr *instr)
}
}
/**
* Returns the destination size of this nir_tex_instr including the sparse
* residency code, if any.
*/
static inline unsigned
nir_tex_instr_dest_size(const nir_tex_instr *instr)
{
@ -2206,7 +2357,8 @@ nir_tex_instr_dest_size(const nir_tex_instr *instr)
return nir_tex_instr_result_size(instr) + instr->is_sparse;
}
/* Returns true if this texture operation queries something about the texture
/**
* Returns true if this texture operation queries something about the texture
* rather than actually sampling it.
*/
static inline bool
@ -2233,6 +2385,11 @@ nir_tex_instr_is_query(const nir_tex_instr *instr)
}
}
/** Returns true if this texture instruction does implicit derivatives
*
* This is important as there are extra control-flow rules around derivatives
* and texture instructions which perform them implicitly.
*/
static inline bool
nir_tex_instr_has_implicit_derivative(const nir_tex_instr *instr)
{
@ -2246,6 +2403,7 @@ nir_tex_instr_has_implicit_derivative(const nir_tex_instr *instr)
}
}
/** Returns the ALU type of the given texture instruction source */
static inline nir_alu_type
nir_tex_instr_src_type(const nir_tex_instr *instr, unsigned src)
{
@ -2303,6 +2461,10 @@ nir_tex_instr_src_type(const nir_tex_instr *instr, unsigned src)
unreachable("Invalid texture source type");
}
/**
* Returns the number of components required by the given texture instruction
* source
*/
static inline unsigned
nir_tex_instr_src_size(const nir_tex_instr *instr, unsigned src)
{
@ -2337,6 +2499,10 @@ nir_tex_instr_src_size(const nir_tex_instr *instr, unsigned src)
return 1;
}
/**
* Returns the index of the texture instruction source with the given
* nir_tex_src_type or -1 if no such source exists.
*/
static inline int
nir_tex_instr_src_index(const nir_tex_instr *instr, nir_tex_src_type type)
{
@ -2347,10 +2513,12 @@ nir_tex_instr_src_index(const nir_tex_instr *instr, nir_tex_src_type type)
return -1;
}
/** Adds a source to a texture instruction */
void nir_tex_instr_add_src(nir_tex_instr *tex,
nir_tex_src_type src_type,
nir_src src);
/** Removes a source from a texture instruction */
void nir_tex_instr_remove_src(nir_tex_instr *tex, unsigned src_idx);
bool nir_tex_instr_has_explicit_tg4_offsets(nir_tex_instr *tex);
@ -3674,6 +3842,7 @@ nir_intrinsic_instr *nir_intrinsic_instr_create(nir_shader *shader,
nir_call_instr *nir_call_instr_create(nir_shader *shader,
nir_function *callee);
/** Creates a NIR texture instruction */
nir_tex_instr *nir_tex_instr_create(nir_shader *shader, unsigned num_srcs);
nir_phi_instr *nir_phi_instr_create(nir_shader *shader);
@ -4753,12 +4922,14 @@ bool nir_lower_compute_system_values(nir_shader *shader,
const nir_lower_compute_system_values_options *options);
enum PACKED nir_lower_tex_packing {
/** No packing */
nir_lower_tex_packing_none = 0,
/* The sampler returns up to 2 32-bit words of half floats or 16-bit signed
/**
* The sampler returns up to 2 32-bit words of half floats or 16-bit signed
* or unsigned ints based on the sampler type
*/
nir_lower_tex_packing_16,
/* The sampler returns 1 32-bit word of 4x8 unorm */
/** The sampler returns 1 32-bit word of 4x8 unorm */
nir_lower_tex_packing_8,
};
@ -4938,6 +5109,7 @@ typedef struct nir_lower_tex_options {
enum nir_lower_tex_packing lower_tex_packing[32];
} nir_lower_tex_options;
/** Lowers complex texture instructions to simpler ones */
bool nir_lower_tex(nir_shader *shader,
const nir_lower_tex_options *options);