forked from Qortal/Brooklyn
82 lines
4.7 KiB
ReStructuredText
82 lines
4.7 KiB
ReStructuredText
Units
|
|
=====
|
|
|
|
Almost every variable, function parameter, or struct field in ISL that carries
|
|
a numeric value has explicit units associated with it. The units used in ISL
|
|
are as follows:
|
|
|
|
* Pixels (px)
|
|
* Samples (sa)
|
|
* Elements (el)
|
|
* Tiles (tl)
|
|
* Bytes (B)
|
|
* Rows of some other unit size (<unit>_rows)
|
|
|
|
These units are fundamental to ISL because they allow us to specify information
|
|
about a surface in a canonical way that isn't dependent on hardware generation.
|
|
Each field in an ISL data structure that stores any sort of dimension has a
|
|
suffix that declares the units for that particular value: ":c:expr:`_el`" for
|
|
elements, ":c:expr:`_sa`" for samples, etc. If the units of the particular
|
|
field aren't quite what is wanted by the hardware, we do the conversion when we
|
|
emit :c:expr:`RENDER_SURFACE_STATE`.
|
|
|
|
This is one of the primary differences between ISL and the old miptree code and
|
|
one of the core design principles of ISL. In the old miptree code, we tried to
|
|
keep everything in the same units as the hardware expects but this lead to
|
|
unnecessary complications as the hardware evolved. One example of this
|
|
difference is QPitch which specifies the distance between array slices. On
|
|
Broadwell and earlier, QPitch field in :c:expr:`RENDER_SURFACE_STATE` was in
|
|
rows of samples. For block-compressed images, this meant it had to be
|
|
a multiple of the block height. On Skylake, it changed to always being in rows
|
|
of elements so you have to divide the pitch in samples by the compresssion
|
|
block height. Since the old surface state code tries to store things in
|
|
hardware units, everyone who ever reads :cpp:expr:`brw_mipmap_tree::qpitch` has
|
|
to change their interpretation based on hardware generation and whether or not
|
|
the surface was block-compressed. In ISL, we have
|
|
:cpp:member:`isl_surf::array_pitch_el_rows` which, as the name says, is in rows
|
|
of elements. On Broadwell and earlier, we have to multiply by the block size
|
|
of the texture when we finally fill out the hardware packet. However, the
|
|
consistency of always being in rows of elements makes any other users of the
|
|
field much simpler because they never have to look at hardware generation or
|
|
whether or not the image is block-compressed.
|
|
|
|
**Pixels** are the most straightforward unit and are where everything starts. A
|
|
pixel simply corresponds to a single pixel (or texel if you prefer) in the
|
|
surface. For multisampled surfaces, a pixel may contain one or more samples.
|
|
For compressed textures, a compression block may contain one or more pixels.
|
|
When initially creating a surface, everything passed to isl_surf_init is
|
|
implicitly in terms of pixels because this is what all of the APIs use.
|
|
|
|
The next unit in ISL's repertoire is **samples**. In a multisampled surface,
|
|
each pixel corresponds to some number of samples given by
|
|
:cpp:member:`isl_surf::samples`. The exact layout of the samples depends on
|
|
the value of :cpp:member:`isl_surf::msaa_layout`. If the layout is
|
|
:cpp:enumerator:`ISL_MSAA_LAYOUT_ARRAY` then each logical array in the surface
|
|
corresponds to :cpp:member:`isl_surf::samples` actual slices
|
|
in the resulting surface, one per array slice. If the layout is
|
|
:cpp:enumerator:`ISL_MSAA_LAYOUT_INTERLEAVED` then each pixel corresponds to a
|
|
2x1, 2x2, 4x2, or 4x4 grid of samples. In order to aid in calculations, one of
|
|
the first things ISL does is to compute :cpp:member:`isl_surf::phys_level0_sa`
|
|
which gives the dimensions of the base miplevel of the surface in samples. The
|
|
type of :cpp:member:`isl_surf::phys_level0_sa` is :cpp:struct:`isl_extent4d`
|
|
which allows us to express both the array and interleaved cases. Most of the
|
|
calculations of how the different miplevels and array slices are laid out is
|
|
done in terms of samples.
|
|
|
|
Next, we have surface **elements**. An element is the basic unit of actual
|
|
surface memory. For multisampled textures, an element is equal to a single
|
|
sample. For block compressed textures, an element corresponds to an entire
|
|
compression block. The conversion from samples to elements is given by dividing
|
|
by the block width and block height of the surface format. This is true
|
|
regardless of whether or not the surface is multisampled; for multisampled
|
|
compressed textures (these exist for certain auxiliary formats), the block
|
|
width and block height are expressed in samples. Pixels cannot be converted
|
|
directly to elements or vice versa; any conversion between pixels and elements
|
|
*must* go through samples.
|
|
|
|
The final surface unit is **tiles**. A tile is a large rectangular block of
|
|
surface data that all fits in a single contiguous block of memory (usually a 4K
|
|
or 64K page, depending on tile format). Tiles are used to provide an
|
|
arrangement of the data in memory that yields better cache performance. The
|
|
size of a tile is always specified in surface elements.
|