This commit is contained in:
elwrcl committed 2026-06-06 13:25:15 +03:00
1 parent 04d4dc8b09
commit 818cab85dc
12511 files changed
+6156641

No files matched your search

+105
View File
@@ -0,0 +1,105 @@
Auxiliary surface compression
=============================
Most lossless image compression on Intel hardware, be that CCS, MCS, or HiZ,
works by way of some chunk of auxiliary data (often a surface) which is used
together with the main surface to provide compression. Even though this means
more memory is allocated, the scheme allows us to reduce our over-all memory
bandwidth since the auxiliary data is much smaller than the main surface.
The simplest example of this is single-sample fast clears
(:c:enumerator:`isl_aux_usage.ISL_AUX_USAGE_CCS_D`) on Ivy Bridge through
Broadwell and later. For this scheme, the auxiliary surface stores a single
bit for each cache-line-pair in the main surface. If that bit is set, then the
entire cache line pair contains only the clear color as provided in the
``RENDER_SURFACE_STATE`` for the image. If the bit is unset, then it's not
clear and you should look at the main surface. Since a cache line is 64B, this
yields a scale-down factor of 1:1024.
Even the simple fast-clear scheme saves us bandwidth in two places. The first
is when we go to clear the surface. If we're doing a full-surface clear or
clearing to the same color that was used to clear before, we don't have to
touch the main surface at all. All we have to do is record the clear color and
smash the aux data to ``0xff``. The hardware then knows to ignore whatever is
in the main surface and look at the clear color instead. The second is when we
go to render. Say we're doing some color blending. Instead of the blend unit
having to read back actual surface contents to blend with, it looks at the
clear bit and blends with the clear color recorded with the surface state
instead. Depending on the geometry and cache utilization, this can save as
much as one whole read of the surface worth of bandwidth.
The difficulty with a scheme like this comes when we want to do something else
with that surface. What happens if the sampler doesn't support this fast-clear
scheme (it doesn't on IVB)? In that case, we have to do a *resolve* where we
run a special pipeline that reads the auxiliary data and applies it to the main
surface. In the case of fast clears, this means that, for every 1 bit in the
auxiliary surface, the corresponding pair of cache lines in the main surface
gets filled with the clear color. At the end of the resolve operation, the
main surface contents are the actual contents of the surface.
Types of surface compression
----------------------------
Intel hardware has several different compression schemes that all work along
similar lines:
.. c:autoenum:: isl_aux_usage
:file: src/intel/isl/isl.h
:members:
.. c:autofunction:: isl_aux_usage_has_fast_clears
.. c:autofunction:: isl_aux_usage_has_compression
.. c:autofunction:: isl_aux_usage_has_hiz
.. c:autofunction:: isl_aux_usage_has_mcs
.. c:autofunction:: isl_aux_usage_has_ccs
Creating auxiliary surfaces
---------------------------
Each type of data compression requires some type of auxiliary data on the side.
For most, this involves a second auxiliary surface. ISL provides helpers for
creating each of these types of surfaces:
.. c:autofunction:: isl_surf_get_hiz_surf
.. c:autofunction:: isl_surf_get_mcs_surf
.. c:autofunction:: isl_surf_supports_ccs
.. c:autofunction:: isl_surf_get_ccs_surf
Compression state tracking
--------------------------
All of the Intel auxiliary surface compression schemes share a common concept
of a main surface which may or may not contain correct up-to-date data and some
auxiliary data which says how to interpret it. The main surface is divided
into blocks of some fixed size and some smaller block in the auxiliary data
controls how that main surface block is to be interpreted. We then have to do
resolves depending on the different HW units which need to interact with a
given surface.
To help drivers keep track of what all is going on and when resolves need to be
inserted, ISL provides a finite state machine which tracks the current state of
the main surface and auxiliary data and their relationship to each other. The
states are encoded with the :c:enum:`isl_aux_state` enum. ISL also provides
helper functions for operating the state machine and determining what aux op
(if any) is required to get to the right state for a given operation.
.. c:autoenum:: isl_aux_state
.. c:autofunction:: isl_aux_state_has_valid_primary
.. c:autofunction:: isl_aux_state_has_valid_aux
.. c:autoenum:: isl_aux_op
.. c:autofunction:: isl_aux_prepare_access
.. c:autofunction:: isl_aux_state_transition_aux_op
.. c:autofunction:: isl_aux_state_transition_write
+172
View File
@@ -0,0 +1,172 @@
Single-sampled Color Compression
================================
Starting with Ivy Bridge, Intel graphics hardware provides a form of color
compression for single-sampled surfaces. In its initial form, this provided an
acceleration of render target clear operations that, in the common case, allows
you to avoid almost all of the bandwidth of a full-surface clear operation. On
Sky Lake, single-sampled color compression was extended to allow for the
compression color values from actual rendering and not just the initial clear.
From here on, the older Ivy Bridge form of color compression will be called
"fast-clears" and term "color compression" will be reserved for the more
powerful Sky Lake form.
The documentation for Ivy Bridge through Broadwell overloads the term MCS for
referring both to the *multisample control surface* used for multisample
compression and the control surface used for fast-clears. In ISL, the
:c:enumerator:`isl_aux_usage.ISL_AUX_USAGE_MCS` enum always refers to
multisample color compression while the
:c:enumerator:`isl_aux_usage.ISL_AUX_USAGE_CCS_D` and
:c:enumerator:`isl_aux_usage.ISL_AUX_USAGE_CCS_E` enums always refer to
single-sampled color compression. Throughout this chapter and the rest of the
ISL documentation, we will use the term "color control surface", abbreviated
CCS, to denote the control surface used for both fast-clears and color
compression. While this is still an overloaded term, Ivy Bridge fast-clears
are much closer to Sky Lake color compression than they are to multisample
compression.
CCS data
--------
Fast clears and CCS are possibly the single most poorly documented aspect of
surface layout/setup for Intel graphics hardware (with HiZ coming in a neat
second). All the documentation really says is that you can use an MCS buffer on
single-sampled surfaces (we will call it the CCS in this case). It also
provides some documentation on how to program the hardware to perform clear
operations, but that's it. How big is this buffer? What does it contain?
Those question are left as exercises to the reader. Almost everything we know
about the contents of the CCS is gleaned from reverse-engineering of the
hardware. The best bit of documentation we have ever had comes from the
display section of the Sky Lake PRM Vol 12 section on planes (p. 159):
The Color Control Surface (CCS) contains the compression status of the
cache-line pairs. The compression state of the cache-line pair is
specified by 2 bits in the CCS. Each CCS cache-line represents an area
on the main surface of 16x16 sets of 128 byte Y-tiled cache-line-pairs.
CCS is always Y tiled.
While this is technically for color compression and not fast-clears, it
provides a good bit of insight into how color compression and fast-clears
operate. Each cache-line pair, in the main surface corresponds to 1 or 2 bits
in the CCS. The primary difference, as far as the current discussion is
concerned, is that fast-clears use only 1 bit per cache-line pair whereas color
compression uses 2 bits.
What is a cache-line pair? Both the X and Y tiling formats are arranged as an
8x8 grid of cache lines. (See the :doc:`chapter on tiling <tiling>` for more
details.) In either case, a cache-line pair is a pair of cache lines whose
starting addresses differ by 512 bytes or 8 cache lines. This results in the
two cache lines being vertically adjacent when the main surface is X-tiled and
horizontally adjacent when the main surface is Y-tiled. For an X-tiled surface
this forms an area of 64B x 2rows and for a Y-tiled surface this forms an area
of 32B x 4rows. In either case, it is guaranteed that, regardless of surface
format, each 2x2 subspan coming out of a shader will land entirely within one
cache-line pair.
What is the correspondence between bits and cache-line pairs? The best model I
(Faith) know of is to consider the CCS as having a 1-bit color format for
fast-clears and a 2-bit format for color compression and a special tiling
format. The CCS tiling formats operate on a 1 or 2-bit granularity rather than
the byte granularity of most tiling formats.
The following table represents the bit-layouts that yield the CCS tiling format
on different hardware generations. Bits 0-11 correspond to the regular swizzle
of bytes within a 4KB page whereas the negative bits represent the address of
the particular 1 or 2-bit portion of a byte. (Note: The Haswell data was
gathered on a dual-channel system so bit-6 swizzling was enabled. It's unclear
how this affects the CCS layout.)
============ ======== =========== =========== ====================== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== ===========
Generation Tiling 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3
============ ======== =========== =========== ====================== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== ===========
Ivy Bridge X or Y :math:`u_6` :math:`u_5` :math:`u_4` :math:`v_7` :math:`v_6` :math:`v_5` :math:`v_4` :math:`v_2` :math:`v_3` :math:`v_1` :math:`v_0` :math:`u_3` :math:`u_2` :math:`u_1` :math:`u_0`
Haswell X :math:`u_6` :math:`u_5` :math:`v_3 \oplus u_1` :math:`v_7` :math:`v_6` :math:`v_5` :math:`v_4` :math:`v_2` :math:`v_3` :math:`v_1` :math:`v_0` :math:`u_4` :math:`u_3` :math:`u_2` :math:`u_0`
Haswell Y :math:`u_6` :math:`u_5` :math:`v_2 \oplus u_1` :math:`v_7` :math:`v_6` :math:`v_5` :math:`v_4` :math:`v_2` :math:`v_3` :math:`v_1` :math:`v_0` :math:`u_4` :math:`u_3` :math:`u_2` :math:`u_0`
Broadwell X :math:`u_6` :math:`u_5` :math:`u_4` :math:`v_7` :math:`v_6` :math:`v_5` :math:`v_4` :math:`u_3` :math:`v_3` :math:`u_2` :math:`u_1` :math:`u_0` :math:`v_2` :math:`v_1` :math:`v_0`
Broadwell Y :math:`u_6` :math:`u_5` :math:`u_4` :math:`v_7` :math:`v_6` :math:`v_5` :math:`v_4` :math:`v_2` :math:`v_3` :math:`u_3` :math:`u_2` :math:`u_1` :math:`v_1` :math:`v_0` :math:`u_0`
Sky Lake Y :math:`u_6` :math:`u_5` :math:`u_4` :math:`v_6` :math:`v_5` :math:`v_4` :math:`v_3` :math:`v_2` :math:`v_1` :math:`u_3` :math:`u_2` :math:`u_1` :math:`v_0` :math:`u_0`
============ ======== =========== =========== ====================== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== ===========
CCS surface layout
------------------
Starting with Broadwell, fast-clears and color compression can be used on
mipmapped and array surfaces. When considered from a higher level, the CCS is
laid out like any other surface. The Broadwell and Sky Lake PRMs describe
this as follows:
Broadwell PRM Vol 7, "MCS Buffer for Render Target(s)" (p. 676):
Mip-mapped and arrayed surfaces are supported with MCS buffer layout with
these alignments in the RT space: Horizontal Alignment = 256 and Vertical
Alignment = 128.
Broadwell PRM Vol 2d, "RENDER_SURFACE_STATE" (p. 279):
For non-multisampled render target's auxiliary surface, MCS, QPitch must be
computed with Horizontal Alignment = 256 and Surface Vertical Alignment =
128. These alignments are only for MCS buffer and not for associated render
target.
Sky Lake PRM Vol 7, "MCS Buffer for Render Target(s)" (p. 632):
Mip-mapped and arrayed surfaces are supported with MCS buffer layout with
these alignments in the RT space: Horizontal Alignment = 128 and Vertical
Alignment = 64.
Sky Lake PRM Vol. 2d, "RENDER_SURFACE_STATE" (p. 435):
For non-multisampled render target's CCS auxiliary surface, QPitch must be
computed with Horizontal Alignment = 128 and Surface Vertical Alignment
= 256. These alignments are only for CCS buffer and not for associated
render target.
Empirical evidence seems to confirm this. On Sky Lake, the vertical alignment
is always one cache line. The horizontal alignment, however, varies by main
surface format: 1 cache line for 32bpp, 2 for 64bpp and 4 cache lines for
128bpp formats. This nicely corresponds to the alignment of 128x64 pixels in
the primary color surface. The second PRM citation about Sky Lake CCS above
gives a vertical alignment of 256 rather than 64. With a little
experimentation, this additional alignment appears to only apply to QPitch and
not to the miplevels within a slice.
On Broadwell, each miplevel in the CCS is aligned to a cache-line pair
boundary: horizontal when the primary surface is X-tiled and vertical when
Y-tiled. For a 32bpp format, this works out to an alignment of 256x128 main
surface pixels regardless of X or Y tiling. On Sky Lake, the alignment is
a single cache line which works out to an alignment of 128x64 main surface
pixels.
TODO: More than just 32bpp formats on Broadwell!
Once armed with the above alignment information, we can lay out the CCS surface
itself. The way ISL does CCS layout calculations is by a very careful and
subtle application of its normal surface layout code.
Above, we described the CCS data layout as mapping of address bits. In
ISL, this is represented by :c:enumerator:`isl_tiling.ISL_TILING_CCS`. The
logical and physical tile dimensions corresponding to the above mapping.
We also have special :c:enum:`isl_format` enums for CCS. These formats are 1
bit-per-pixel on Ivy Bridge through Broadwell and 2 bits-per-pixel on Skylake
and above to correspond to the 1 and 2-bit values represented in the CCS data.
They have a block size (similar to a block compressed format such as BC or
ASTC) which says what area (in surface elements) in the main surface is covered
by a single CCS element (1 or 2-bit). Because this depends on the main surface
tiling and format, we have several different CCS formats.
Once the appropriate :c:enum:`isl_format` has been selected, computing the
size and layout of a CCS surface is as simple as passing the same surface
creation parameters to :c:func:`isl_surf_init_s` as were used to create the
primary surface only with :c:enumerator:`isl_tiling.ISL_TILING_CCS` and the
correct CCS format. This not only results in a correctly sized surface but
most other ISL helpers for things such as computing offsets into surfaces work
correctly as well.
CCS on Tigerlake and above
--------------------------
Starting with Tigerlake, CCS is no longer done via a surface and, instead, the
term CCS gets overloaded once again (gotta love it!) to now refer to a form of
universal compression which can be applied to almost any surface. Nothing in
this chapter applies to any hardware with a graphics IP version 12 or above.
+242
View File
@@ -0,0 +1,242 @@
Surface Formats
===============
A surface format describes the encoding of color information into the actual
data stored in memory. Surface formats in isl are specified via the
:c:enum:`isl_format` enum. A complete list of surface formats is included at
the end of this chapter.
In general, a surface format definition consists of two parts: encoding and
layout.
Data Encoding
-------------
There are several different ways that one can encode a number (or vector) into
a binary form, and each makes different trade-offs. By default, most color
values lie in the range [0, 1], so one of the most common encodings for color
data is unsigned normalized where the range of an unsigned integer of a
particular size is mapped linearly onto the interval [0, 1]. While normalized
is certainly the most common representation for color data, not all data is
color data, and not all values are nicely bounded. The possible data encodings
are specified by :c:enum:`isl_base_type`:
.. c:autoenum:: isl_base_type
:file: src/intel/isl/isl.h
:members:
Data Layout
-----------
The different data layouts fall into two categories: array and packed. When an
array layout is used, the components are stored sequentially in an array of the
given encoding. For instance, if the data is encoded in an 8-bit RGBA array
format the data is stored in an array of type :c:type:`uint8_t` where the blue
component of the ``i``'th color value is accessed as:
.. code-block:: C
uint8_t r = ((uint8_t *)data)[i * 4 + 0];
uint8_t g = ((uint8_t *)data)[i * 4 + 1];
uint8_t b = ((uint8_t *)data)[i * 4 + 2];
uint8_t a = ((uint8_t *)data)[i * 4 + 3];
Array formats are popular because of their simplicity. However, they are
limited to formats where all components have the same size and fit in
a standard C data type.
Packed formats, on the other hand, are encoded with the entire color value
packed into a single 8, 16, or 32-bit value. The components are specified by
which bits they occupy within that value. For instance, with the popular
``RGB565`` format, each :c:type:`vec3` takes up 16 bits and the
``i``'th color value is accessed as:
.. code-block:: C
uint8_t r = (*(uint16_t *)data >> 0) & 0x1f;
uint8_t g = (*(uint16_t *)data >> 5) & 0x3f;
uint8_t b = (*(uint16_t *)data >> 11) & 0x1f;
Packed formats are useful because they allow you to specify formats with uneven
component sizes such as ``RGBA1010102`` or where the components are
smaller than 8 bits such as ``RGB565`` discussed above. It does,
however, come with the restriction that the entire vector must fit within 8,
16, or 32 bits.
One has to be careful when reasoning about packed formats because it is easy to
get the color order wrong. With array formats, the channel ordering is usually
implied directly from the format name with ``RGBA8888`` storing the
formats as in the first example and ``BGRA8888`` storing them in the BGRA
ordering. Packed formats, however, are not as simple because some
specifications choose to use a MSB to LSB ordering and others LSB to MSB. One
must be careful to pay attention to the enum in question in order to avoid
getting them backwards.
From an API perspective, both types of formats are available. In Vulkan, the
formats that are of the form ``VK_FORMAT_xxx_PACKEDn`` are packed
formats where the entire color fits in ``n`` bits and formats without the
``_PACKEDn`` suffix are array formats. In GL, if you specify one of the
base types such as :c:enumerator:`GL_FLOAT` you get an array format but if you
specify a packed type such as :c:enumerator:`GL_UNSIGNED_INT_8_8_8_8_REV` you
get a packed format.
The following table provides a summary of the bit orderings of different packed
format specifications. The bit ordering is relative to the reading of the enum
name from left to right.
===================== ==============
Component Left → Right
===================== ==============
GL MSB → LSB
Vulkan MSB → LSB
mesa_format LSB → MSB
Intel surface format LSB → MSB
===================== ==============
Understanding sRGB
------------------
The sRGB colorspace is one of the least tractable concepts in the entire world
of surfaces and formats. Most texture formats are stored in a linear
colorspace where the floating-point value corresponds linearly to intensity
values. The sRGB color space, on the other hand, is non-linear and provides
greater precision in the lower-intensity (darker) end of the spectrum. The
relationship between linear and sRGB is governed by the following continuous
bijection:
.. math::
c_l =
\begin{cases}
\frac{c_s}{12.92} &\text{if } c_s \le 0.04045 \\\\
\left(\frac{c_s + 0.055}{1.055}\right)^{2.4} &\text{if } c_s > 0.04045
\end{cases}
where :math:`c_l` is the linear color and :math:`c_s` is the color in sRGB.
It is important to note that, when an alpha channel is present, the alpha
channel is always stored in the linear colorspace.
The key to understanding sRGB is to think about it starting from the physical
display. All displays work natively in sRGB. On older displays, there isn't
so much a conversion operation as a fact of how the hardware works. All
display hardware has a natural gamma curve required to get from linear to the
signal level required to generate the correct color. On older CRT displays,
the gamma curve of your average CRT is approximately the sRGB curve. More
modern display hardware has support for additional gamma curves to try and get
accurate colors but, for the sake of compatibility, everything still operates
in sRGB. When an image is sent to the X server, X passes the pixels on to the
display verbatim without doing any conversions. (Fun fact: When dealing with
translucent windows, X blends in the wrong colorspace.) This means that the
image into which you are rendering will always be interpreted as if it were in
the sRGB colorspace.
When sampling from a texture, the value returned to the shader is in the linear
colorspace. The conversion from sRGB happens as part of sampling. In OpenGL,
thanks mostly to history, there are various knobs for determining when you
should or should not encode or decode sRGB. In 2007, :ext:`GL_EXT_texture_sRGB`
added support for sRGB texture formats and was included in OpenGL 2.1. In
2010, :ext:`GL_EXT_texture_sRGB_decode` added a flag to allow you to disable
texture decoding so that the shader received the data still in the sRGB
colorspace. Then, in 2012, :ext:`GL_ARB_texture_view` came along and made
:ext:`GL_EXT_texture_sRGB_decode` simultaneously obsolete and very confusing.
Now, thanks to the combination of extensions, you can upload a texture as
linear, create an sRGB view of it and ask that sRGB not be decoded. What
format is it in again?
The situation with render targets is a bit different. Historically, you got
your render target from the window system (which is always sRGB) and the spec
said nothing whatsoever about encoding. All render targets were sRGB because
that's how monitors worked and application writers were expected to understand
that their final rendering needed to be in sRGB. However, with the advent of
:ext:`GL_EXT_framebuffer_object` this was no longer true. Also, sRGB was causing
problems with blending because GL was blind to the fact that the output was
sRGB and blending was occurring in the wrong colorspace. In 2006, a set of
:ext:`GL_EXT_framebuffer_sRGB` extensions added support (on both the GL and
window-system sides) for detecting whether a particular framebuffer was in sRGB
and instructing GL to do the conversion into the sRGB colorspace as the final
step prior to writing out to the render target. Enabling sRGB also implied
that blending would occur in the linear colorspace prior to sRGB conversion and
would therefore be more accurate. When sRGB was added to the OpenGL ES spec in
3.1, they added the query for sRGB but did not add the flag to allow you to
turn it on and off.
In Vulkan, this is all much more straightforward. Your format is sRGB or it
isn't. If you have an sRGB image and you don't want sRGB decoding to happen
when you sample from it, you simply create a :c:struct:`VkImageView` that has
the appropriate linear format and the data will be treated as linear and not
converted. Similarly for render targets, blending always happens in the same
colorspace as the shader output and you determine whether or not you want sRGB
conversion by the format of the :c:struct:`VkImageView` used as the render
target.
Surface Format Introspection API
--------------------------------
ISL provides an API for introspecting the :c:enum:`isl_format` enum and
getting various bits of information about a format. ISL provides helpers for
introspecting both the data layout of an :c:enum:`isl_format` and the
capabilities of that format for a particular piece of Intel hardware.
Format Layout Introspection
^^^^^^^^^^^^^^^^^^^^^^^^^^^
To get the layout of a given :c:enum:`isl_format`, call
:c:func:`isl_format_get_layout`:
.. c:autofunction:: isl_format_get_layout
.. c:autostruct:: isl_format_layout
:members:
.. c:autostruct:: isl_channel_layout
:members:
There are also quite a few helpers for many of the common cases that allow you
to avoid using :c:struct:`isl_format_layout` manually. There are a lot of
them so we won't include a full list here. Look at isl.h for more details.
Hardware Format Support Introspection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is provided by means of a table located in isl_format.c. Looking at the
table directly is often useful for understanding HW support for various
formats. However, for the purposes of code cleanliness, the table is not
exposed directly and, instead, hardware support information is exposed via
a set of helper functions:
.. c:autofunction:: isl_format_supports_rendering
.. c:autofunction:: isl_format_supports_alpha_blending
.. c:autofunction:: isl_format_supports_sampling
.. c:autofunction:: isl_format_supports_filtering
.. c:autofunction:: isl_format_supports_vertex_fetch
.. c:autofunction:: isl_format_supports_typed_writes
:file: src/intel/isl/isl_format.c
.. c:autofunction:: isl_format_supports_typed_reads
.. c:autofunction:: isl_format_supports_ccs_d
.. c:autofunction:: isl_format_supports_ccs_e
.. c:autofunction:: isl_format_supports_multisampling
.. c:autofunction:: isl_formats_are_ccs_e_compatible
Surface Format Enums
--------------------
Everything in ISL is done in terms of the :c:enum:`isl_format` enum. However,
for the sake of interacting with other parts of Mesa, we provide a helper for
converting a :c:enum:`pipe_format` to an :c:enum:`isl_format`:
.. c:autofunction:: isl_format_for_pipe_format
The :c:enum:`isl_format` enum is as follows:
.. c:autoenum:: isl_format
:members:
+74
View File
@@ -0,0 +1,74 @@
Hierarchical Depth (HiZ)
========================
TODO: Add detailed docs like we have for CCS
HiZ/stencil on Sandy Bridge
---------------------------
Properly enabling HiZ on Sandy Bridge requires certain special considerations.
From the Sandy Bridge PRM Vol. 2, Pt. 1, 7.5.3 "Hierarchical Depth Buffer" (p.
312):
The hierarchical depth buffer does not support the LOD field, it is assumed
by hardware to be zero. A separate hierarchical depth buffer is required
for each LOD used, and the corresponding buffer’s state delivered to
hardware each time a new depth buffer state with modified LOD is delivered.
The ``3DSTATE_STENCIL_BUFFER`` packet for separate stencil (required for HiZ)
on sandy bridge also lacks an LOD field. Empirically, the hardware doesn't
pull the stencil LOD from ``3DSTATE_DEPTH_BUFFER``, it's just always 0 like
with HiZ.
As stated in the PRM, this means we need a separate HiZ or stencil buffer for
each LOD. However, it's not quite as simple as that. If you ignore layered
rendering, things are pretty straightforward: you need one HiZ surface for each
main surface slice. With layered rendering, however, we have to be a bit more
clever because we need a "real" array surface at each LOD. ISL solves this
with a special miptree layout for layered rendering
:c:enumerator:`isl_dim_layout.ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ` which lays
out the surface as a miptree of layered images instead of an array of miptrees.
See the docs for
:c:enumerator:`isl_dim_layout.ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ` for a nice
description along with an ASCII art diagram of the layout.
Also, neither ``3DSTATE_STENCIL_BUFFER`` nor ``3DSTATE_HIER_DEPTH_BUFFER`` have
their own surface dimensions or layout information on Sandy Bridge. They're
just an address and a surface pitch. Instead, all that other information is
pulled from ``3DSTATE_DEPTH_BUFFER``. When you combine this with the lack of
LOD, this means that, technically, we have a full-sized single-LOD stencil or
HiZ surface at each miplevel of which only the upper left-hand corner of each
array slice ever gets used. The net effect of this is that, in
:c:enumerator:`isl_dim_layout.ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ`, all LODs
share the same QPitch even though it's horribly wasteful. This is actually
pretty convenient for ISL because we only have the one
:c:member:`isl_surf.array_pitch_el_rows` field.
Due to difficulties with plumbing relocation deltas through ISL's
depth/stencil/hiz emit interface, we can't handle this all automatically in
ISL. Instead, it's left up to the driver to do this offsetting. ISL does
provide helpers for computing the offsets and they work fine with
:c:enumerator:`isl_dim_layout.ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ` so all that's
really required is to call the ISL helper and add the computed offset to the
HiZ or stencil buffer address. The following is an excerpt from BLORP where we
do this as an example:
.. code-block:: c
struct blorp_address hiz_address = params->depth.aux_addr;
#if GFX_VER == 6
/* Sandy bridge hardware does not technically support mipmapped HiZ.
* However, we have a special layout that allows us to make it work
* anyway by manually offsetting to the specified miplevel.
*/
assert(info.hiz_surf->dim_layout == ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ);
uint32_t offset_B;
isl_surf_get_image_offset_B_tile_sa(info.hiz_surf,
info.view->base_level, 0, 0,
&offset_B, NULL, NULL);
hiz_address.offset += offset_B;
#endif
info.hiz_address =
blorp_emit_reloc(batch, dw + isl_dev->ds.hiz_offset / 4,
hiz_address, 0);
+23
View File
@@ -0,0 +1,23 @@
Intel Surface Layout (ISL)
==========================
The Intel Surface Layout library (**ISL**) is a subproject in Mesa for doing
surface layout calculations for Intel graphics drivers. It was originally
written by Lina Versace and is now maintained by Faith Ekstrand and Nanley
Chery.
.. toctree::
:maxdepth: 2
units
formats
tiling
aux-surf-comp
ccs
hiz
The core representation of a surface in ISL is :c:struct:`isl_surf`.
.. c:autostruct:: isl_surf
:file: src/intel/isl/isl.h
:members:
+512
View File
@@ -0,0 +1,512 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="800"
height="402"
viewBox="0 0 800 401.99999"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="tiling-basic.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="236.80681"
inkscape:cy="190.0918"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1379"
inkscape:window-height="1132"
inkscape:window-x="479"
inkscape:window-y="232"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid3336"
originx="-9"
originy="-330.00001" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-9,-320.36214)">
<rect
style="fill:#fbff00;fill-opacity:0.4;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
id="rect4152"
width="400"
height="400"
x="10"
y="321.36209" />
<rect
style="fill:#aff48e;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4154"
width="371"
height="331.00006"
x="10"
y="321.36209" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
d="m 110,321.36214 0,400"
id="path4140"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
d="m 210,321.36214 0,400 0,0"
id="path4142"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
d="m 310,321.36214 0,400"
id="path4144"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
d="m 10,421.36214 400,0 0,0"
id="path4146"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
d="m 10,521.36214 400,0"
id="path4148"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
d="m 10,621.36214 400,0"
id="path4150"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="51"
y="382.36209"
id="text4156"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158"
x="51"
y="382.36209">0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="151"
y="382.36209"
id="text4156-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-6"
x="151"
y="382.36209">1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="251"
y="382.36209"
id="text4156-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-5"
x="251"
y="382.36209">2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="351"
y="382.36209"
id="text4156-35"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-62"
x="351"
y="382.36209">3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="51"
y="482.36209"
id="text4156-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-1"
x="51"
y="482.36209">4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="151"
y="482.36209"
id="text4156-2"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-7"
x="151"
y="482.36209">5</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="251"
y="482.36209"
id="text4156-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-9"
x="251"
y="482.36209">6</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="351"
y="482.36209"
id="text4156-36"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0"
x="351"
y="482.36209">7</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="51"
y="582.36212"
id="text4156-6"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-2"
x="51"
y="582.36212">8</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="149"
y="582.36212"
id="text4156-61"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-8"
x="149"
y="582.36212">9</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="241"
y="582.36212"
id="text4156-79"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-20"
x="241"
y="582.36212">10</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="341"
y="582.36212"
id="text4156-23"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-75"
x="341"
y="582.36212">11</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="41"
y="682.36212"
id="text4156-92"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-28"
x="41"
y="682.36212">12</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="141"
y="682.36212"
id="text4156-97"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-3"
x="141"
y="682.36212">13</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="241"
y="682.36212"
id="text4156-612"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-93"
x="241"
y="682.36212">14</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="341"
y="682.36212"
id="text4156-1"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-94"
x="341"
y="682.36212">15</tspan></text>
<rect
style="fill:#aff48e;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4290"
width="300"
height="240.00006"
x="509"
y="412.36209" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 6;stroke-dashoffset:0;stroke-opacity:1"
d="m 509,452.36216 300,0"
id="path4308"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 509,652.36216 0,-240 300,0"
id="path4310"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 6;stroke-dashoffset:0;stroke-opacity:1"
d="m 589,412.36216 0,240"
id="path4314"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 6;stroke-dashoffset:0;stroke-opacity:1"
d="m 669,412.36216 0,240"
id="path4316"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 6;stroke-dashoffset:0;stroke-opacity:1"
d="m 749,412.36216 0,240"
id="path4318"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 6;stroke-dashoffset:0;stroke-opacity:1"
d="m 509,492.36216 299.28572,0"
id="path4320"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 6;stroke-dashoffset:0;stroke-opacity:1"
d="m 509,532.36216 300,0"
id="path4322"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="541.27283"
y="442.10953"
id="text4156-36-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8"
x="541.27283"
y="442.10953">0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="620.51526"
y="441.85696"
id="text4156-36-7-4"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-5"
x="620.51526"
y="441.85696">1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="701.77789"
y="441.60452"
id="text4156-36-7-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-3"
x="701.77789"
y="441.60452">2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="524.71429"
y="480.9335"
id="text4156-36-7-06"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-32"
x="524.71429"
y="480.9335">128</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="604.80835"
y="481.35196"
id="text4156-36-7-061"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-55"
x="604.80835"
y="481.35196">129</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="525.31348"
y="521.60455"
id="text4156-36-7-5"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-69"
x="525.31348"
y="521.60455">256</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="605.9079"
y="521.85699"
id="text4156-36-7-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-7"
x="605.9079"
y="521.85699">257</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="685.15027"
y="521.60455"
id="text4156-36-7-45"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-2"
x="685.15027"
y="521.60455">258</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="684.30328"
y="481.35196"
id="text4156-36-7-061-5"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-55-4"
x="684.30328"
y="481.35196">130</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="766.14288"
y="434.50491"
id="text4156-36-7-0-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-3-4"
x="766.14288"
y="434.50491">...</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="766.14288"
y="474.50491"
id="text4156-36-7-0-7-4"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-3-4-3"
x="766.14288"
y="474.50491">...</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="766.14288"
y="514.50494"
id="text4156-36-7-0-7-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-3-4-7"
x="766.14288"
y="514.50494">...</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="533.28577"
y="563.79071"
id="text4156-36-7-0-7-8"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-3-4-6"
x="533.28577"
y="563.79071">...</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="616.14288"
y="564.50494"
id="text4156-36-7-0-7-88"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-3-4-4"
x="616.14288"
y="564.50494">...</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="696.14288"
y="564.50494"
id="text4156-36-7-0-7-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4158-0-8-3-4-1"
x="696.14288"
y="564.50494">...</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 111,322.36216 808.77664,411.352"
id="path4510"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 11,422.36216 509.7868,651.352"
id="path4512"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

+323
View File
@@ -0,0 +1,323 @@
Tiling
======
The naive view of an image in memory is that the pixels are stored one after
another in memory usually in an X-major order. An image that is arranged in
this way is called "linear". Linear images, while easy to reason about, can
have very bad cache locality. Graphics operations tend to act on pixels that
are close together in 2-D euclidean space. If you move one pixel to the right
or left in a linear image, you only move a few bytes to one side or the other
in memory. However, if you move one pixel up or down you can end up kilobytes
or even megabytes away.
Tiling (sometimes referred to as swizzling) is a method of re-arranging the
pixels of a surface so that pixels which are close in 2-D euclidean space are
likely to be close in memory.
Basics
------
The basic idea of a tiled image is that the image is first divided into
two-dimensional blocks or tiles. Each tile takes up a chunk of contiguous
memory and the tiles are arranged like pixels in linear surface. This is best
demonstrated with a specific example. Suppose we have a RGBA8888 X-tiled
surface on Intel graphics. Then the surface is divided into 128x8 pixel tiles
each of which is 4KB of memory. Within each tile, the pixels are laid out like
a 128x8 linear image. The tiles themselves are laid out row-major in memory
like giant pixels. This means that, as long as you don't leave your 128x8
tile, you can move in both dimensions without leaving the same 4K page in
memory.
.. image:: tiling-basic.svg
:alt: Example of an X-tiled image
You can, however do even better than this. Suppose that same image is,
instead, Y-tiled. Then the surface is divided into 32x32 pixel tiles each of
which is 4KB of memory. Within a tile, each 64B cache line corresponds to 4x4
pixel region of the image (you can think of it as a tile within a tile). This
means that very small deviations don't even leave the cache line. This added
bit of pixel shuffling is known to have a substantial performance impact in
most real-world applications.
Intel graphics has several different tiling formats that we'll discuss in
detail in later sections. The most commonly used as of the writing of this
chapter is Y-tiling. In all tiling formats the basic principal is the same:
The image is divided into tiles of a particular size and, within those tiles,
the data is re-arranged (or swizzled) based on a particular pattern. A tile
size will always be specified in bytes by rows and the actual X-dimension of
the tile in elements depends on the size of the element in bytes.
Bit-6 Swizzling
^^^^^^^^^^^^^^^
On some older hardware, there is an additional address swizzle that is applied
on top of the tiling format. This has been removed starting with Broadwell
because, as it says in the Broadwell PRM Vol 5 "Tiling Algorithm" (p. 17):
Address Swizzling for Tiled-Surfaces is no longer used because the main
memory controller has a more effective address swizzling algorithm.
Whether or not swizzling is enabled depends on the memory configuration of the
system. Generally, systems with dual-channel RAM have swizzling enabled and
single-channel do not. Supposedly, this swizzling allows for better balancing
between the two memory channels and increases performance. Because it depends
on the memory configuration which may change from one boot to the next, it
requires a run-time check.
The best documentation for bit-6 swizzling can be found in the Haswell PRM Vol.
5 "Memory Views" in the section entitled "Address Swizzling for Tiled-Y
Surfaces". It exists on older platforms but the docs get progressively worse
the further you go back.
ISL Representation
------------------
The structure of any given tiling format is represented by ISL using the
:c:enum:`isl_tiling` enum and the :c:struct:`isl_tile_info` structure:
.. c:autoenum:: isl_tiling
:file: src/intel/isl/isl.h
:members:
.. c:autofunction:: isl_tiling_get_info
:file: src/intel/isl/isl.c
.. c:autostruct:: isl_tile_info
:members:
The ``isl_tile_info`` structure has two different sizes for a tile: a logical
size in surface elements and a physical size in bytes. In order to determine
the proper logical size, the bits-per-block of the underlying format has to be
passed into ``isl_tiling_get_info``. The proper way to compute the size of an
image in bytes given a width and height in elements is as follows:
.. code-block:: c
uint32_t width_tl = DIV_ROUND_UP(width_el * (format_bpb / tile_info.format_bpb),
tile_info.logical_extent_el.w);
uint32_t height_tl = DIV_ROUND_UP(height_el, tile_info.logical_extent_el.h);
uint32_t row_pitch = width_tl * tile_info.phys_extent_el.w;
uint32_t size = height_tl * tile_info.phys_extent_el.h * row_pitch;
It is very important to note that there is no direct conversion between
:c:member:`isl_tile_info.logical_extent_el` and
:c:member:`isl_tile_info.phys_extent_B`. It is tempting to assume that the
logical and physical heights are the same and simply divide the width of
:c:member:`isl_tile_info.phys_extent_B` by the size of the format (which is
what the PRM does) to get :c:member:`isl_tile_info.logical_extent_el` but
this is not at all correct. Some tiling formats have logical and physical
heights that differ and so no such calculation will work in general. The
easiest case study for this is W-tiling. From the Sky Lake PRM Vol. 2d,
"RENDER_SURFACE_STATE" (p. 427):
If the surface is a stencil buffer (and thus has Tile Mode set to
TILEMODE_WMAJOR), the pitch must be set to 2x the value computed based on
width, as the stencil buffer is stored with two rows interleaved.
What does this mean? Why are we multiplying the pitch by two? What does it
mean that "the stencil buffer is stored with two rows interleaved"? The
explanation for all these questions is that a W-tile (which is only used for
stencil) has a logical size of 64el x 64el but a physical size of 128B
x 32rows. In memory, a W-tile has the same footprint as a Y-tile (128B
x 32rows) but every pair of rows in the stencil buffer is interleaved into
a single row of bytes yielding a two-dimensional area of 64el x 64el. You can
consider this as its own tiling format or as a modification of Y-tiling. The
interpretation in the PRMs vary by hardware generation; on Sandy Bridge they
simply said it was Y-tiled but by Sky Lake there is almost no mention of
Y-tiling in connection with stencil buffers and they are always W-tiled. This
mismatch between logical and physical tile sizes are also relevant for
hierarchical depth buffers as well as single-channel MCS and CCS buffers.
X-tiling
--------
The simplest tiling format available on Intel graphics (which has been
available since gen4) is X-tiling. An X-tile is 512B x 8rows and, within the
tile, the data is arranged in an X-major linear fashion. You can also look at
X-tiling as being an 8x8 cache line grid where the cache lines are arranged
X-major as follows:
======= ======= ======= ======= ======= ======= ======= =======
`0x000` `0x040` `0x080` `0x0c0` `0x100` `0x140` `0x180` `0x1c0`
`0x200` `0x240` `0x280` `0x2c0` `0x300` `0x340` `0x380` `0x3c0`
`0x400` `0x440` `0x480` `0x4c0` `0x500` `0x540` `0x580` `0x5c0`
`0x600` `0x640` `0x680` `0x6c0` `0x700` `0x740` `0x780` `0x7c0`
`0x800` `0x840` `0x880` `0x8c0` `0x900` `0x940` `0x980` `0x9c0`
`0xa00` `0xa40` `0xa80` `0xac0` `0xb00` `0xb40` `0xb80` `0xbc0`
`0xc00` `0xc40` `0xc80` `0xcc0` `0xd00` `0xd40` `0xd80` `0xdc0`
`0xe00` `0xe40` `0xe80` `0xec0` `0xf00` `0xf40` `0xf80` `0xfc0`
======= ======= ======= ======= ======= ======= ======= =======
Each cache line represents a piece of a single row of pixels within the image.
The memory locations of two vertically adjacent pixels within the same X-tile
always differs by 512B or 8 cache lines.
As mentioned above, X-tiling is slower than Y-tiling (though still faster than
linear). However, until Sky Lake, the display scan-out hardware could only do
X-tiling so we have historically used X-tiling for all window-system buffers
(because X or a Wayland compositor may want to put it in a plane).
Bit-6 Swizzling
^^^^^^^^^^^^^^^
When bit-6 swizzling is enabled, bits 9 and 10 are XORed in with bit 6 of the
tiled address:
.. code-block:: c
addr[6] ^= addr[9] ^ addr[10];
Y-tiling
--------
The Y-tiling format, also available since gen4, is substantially different from
X-tiling and performs much better in practice. Each Y-tile is an 8x8 grid of cache lines arranged Y-major as follows:
======= ======= ======= ======= ======= ======= ======= =======
`0x000` `0x200` `0x400` `0x600` `0x800` `0xa00` `0xc00` `0xe00`
`0x040` `0x240` `0x440` `0x640` `0x840` `0xa40` `0xc40` `0xe40`
`0x080` `0x280` `0x480` `0x680` `0x880` `0xa80` `0xc80` `0xe80`
`0x0c0` `0x2c0` `0x4c0` `0x6c0` `0x8c0` `0xac0` `0xcc0` `0xec0`
`0x100` `0x300` `0x500` `0x700` `0x900` `0xb00` `0xd00` `0xf00`
`0x140` `0x340` `0x540` `0x740` `0x940` `0xb40` `0xd40` `0xf40`
`0x180` `0x380` `0x580` `0x780` `0x980` `0xb80` `0xd80` `0xf80`
`0x1c0` `0x3c0` `0x5c0` `0x7c0` `0x9c0` `0xbc0` `0xdc0` `0xfc0`
======= ======= ======= ======= ======= ======= ======= =======
Each 64B cache line within the tile is laid out as 4 rows of 16B each:
====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======
`0x00` `0x01` `0x02` `0x03` `0x04` `0x05` `0x06` `0x07` `0x08` `0x09` `0x0a` `0x0b` `0x0c` `0x0d` `0x0e` `0x0f`
`0x10` `0x11` `0x12` `0x13` `0x14` `0x15` `0x16` `0x17` `0x18` `0x19` `0x1a` `0x1b` `0x1c` `0x1d` `0x1e` `0x1f`
`0x20` `0x21` `0x22` `0x23` `0x24` `0x25` `0x26` `0x27` `0x28` `0x29` `0x2a` `0x2b` `0x2c` `0x2d` `0x2e` `0x2f`
`0x30` `0x31` `0x32` `0x33` `0x34` `0x35` `0x36` `0x37` `0x38` `0x39` `0x3a` `0x3b` `0x3c` `0x3d` `0x3e` `0x3f`
====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======
Y-tiling is widely regarded as being substantially faster than X-tiling so it
is generally preferred. However, prior to Sky Lake, Y-tiling was not available
for scanout so X tiling was used for any sort of window-system buffers.
Starting with Sky Lake, we can scan out from Y-tiled buffers.
Bit-6 Swizzling
^^^^^^^^^^^^^^^
When bit-6 swizzling is enabled, bit 9 is XORed in with bit 6 of the tiled
address:
.. code-block:: c
addr[6] ^= addr[9];
W-tiling
--------
W-tiling is a new tiling format added on Sandy Bridge for use in stencil
buffers. W-tiling is similar to Y-tiling in that it's arranged as an 8x8
Y-major grid of cache lines. The bytes within each cache line are arranged as
follows:
====== ====== ====== ====== ====== ====== ====== ======
`0x00` `0x01` `0x04` `0x05` `0x10` `0x11` `0x14` `0x15`
`0x02` `0x03` `0x06` `0x07` `0x12` `0x13` `0x16` `0x17`
`0x08` `0x09` `0x0c` `0x0d` `0x18` `0x19` `0x1c` `0x1d`
`0x0a` `0x0b` `0x0e` `0x0f` `0x1a` `0x1b` `0x1e` `0x1f`
`0x20` `0x21` `0x24` `0x25` `0x30` `0x31` `0x34` `0x35`
`0x22` `0x23` `0x26` `0x27` `0x32` `0x33` `0x36` `0x37`
`0x28` `0x29` `0x2c` `0x2d` `0x38` `0x39` `0x3c` `0x3d`
`0x2a` `0x2b` `0x2e` `0x2f` `0x3a` `0x3b` `0x3e` `0x3f`
====== ====== ====== ====== ====== ====== ====== ======
While W-tiling has been required for stencil all the way back to Sandy Bridge,
the docs are somewhat confused as to whether stencil buffers are W or Y-tiled.
This seems to stem from the fact that the hardware seems to implement W-tiling
as a sort of modified Y-tiling. One example of this is the somewhat odd
requirement that W-tiled buffers have their pitch multiplied by 2. From the
Sky Lake PRM Vol. 2d, "RENDER_SURFACE_STATE" (p. 427):
If the surface is a stencil buffer (and thus has Tile Mode set to
TILEMODE_WMAJOR), the pitch must be set to 2x the value computed based on
width, as the stencil buffer is stored with two rows interleaved.
The last phrase holds the key here: "the stencil buffer is stored with two rows
interleaved". More accurately, a W-tiled buffer can be viewed as a Y-tiled
buffer with each set of 4 W-tiled lines interleaved to form 2 Y-tiled lines. In
ISL, we represent a W-tile as a tiling with a logical dimension of 64el x 64el
but a physical size of 128B x 32rows. This cleanly takes care of the pitch
issue above and seems to nicely model the hardware.
Tile4
-----
The tile4 format, introduced on Xe-HP, is somewhat similar to Y but with more
internal shuffling. Each tile4 tile is an 8x8 grid of cache lines arranged
as follows:
======= ======= ======= ======= ======= ======= ======= =======
`0x000` `0x040` `0x080` `0x0a0` `0x200` `0x240` `0x280` `0x2a0`
`0x100` `0x140` `0x180` `0x1a0` `0x300` `0x340` `0x380` `0x3a0`
`0x400` `0x440` `0x480` `0x4a0` `0x600` `0x640` `0x680` `0x6a0`
`0x500` `0x540` `0x580` `0x5a0` `0x700` `0x740` `0x780` `0x7a0`
`0x800` `0x840` `0x880` `0x8a0` `0xa00` `0xa40` `0xa80` `0xaa0`
`0x900` `0x940` `0x980` `0x9a0` `0xb00` `0xb40` `0xb80` `0xba0`
`0xc00` `0xc40` `0xc80` `0xca0` `0xe00` `0xe40` `0xe80` `0xea0`
`0xd00` `0xd40` `0xd80` `0xda0` `0xf00` `0xf40` `0xf80` `0xfa0`
======= ======= ======= ======= ======= ======= ======= =======
Each 64B cache line within the tile is laid out the same way as for a Y-tile,
as 4 rows of 16B each:
====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======
`0x00` `0x01` `0x02` `0x03` `0x04` `0x05` `0x06` `0x07` `0x08` `0x09` `0x0a` `0x0b` `0x0c` `0x0d` `0x0e` `0x0f`
`0x10` `0x11` `0x12` `0x13` `0x14` `0x15` `0x16` `0x17` `0x18` `0x19` `0x1a` `0x1b` `0x1c` `0x1d` `0x1e` `0x1f`
`0x20` `0x21` `0x22` `0x23` `0x24` `0x25` `0x26` `0x27` `0x28` `0x29` `0x2a` `0x2b` `0x2c` `0x2d` `0x2e` `0x2f`
`0x30` `0x31` `0x32` `0x33` `0x34` `0x35` `0x36` `0x37` `0x38` `0x39` `0x3a` `0x3b` `0x3c` `0x3d` `0x3e` `0x3f`
====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======
Tiling as a bit pattern
-----------------------
There is one more important angle on tiling that should be discussed before we
finish. Every tiling can be described by three things:
1. A logical width and height in elements
2. A physical width in bytes and height in rows
3. A mapping from logical elements to physical bytes within the tile
We have spent a good deal of time on the first two because this is what you
really need for doing surface layout calculations. However, there are cases in
which the map from logical to physical elements is critical. One example is
W-tiling where we have code to do W-tiled encoding and decoding in the shader
for doing stencil blits because the hardware does not allow us to render to
W-tiled surfaces.
There are many ways to mathematically describe the mapping from logical
elements to physical bytes. In the PRMs they give a very complicated set of
formulas involving lots of multiplication, modulus, and sums that show you how
to compute the mapping. With a little creativity, you can easily reduce those
to a set of bit shifts and ORs. By far the simplest formulation, however, is
as a mapping from the bits of the texture coordinates to bits in the address.
Suppose that :math:`(u, v)` is location of a 1-byte element within a tile. If
you represent :math:`u` as :math:`u_n u_{n-1} \cdots u_2 u_1 u_0` where
:math:`u_0` is the LSB and :math:`u_n` is the MSB of :math:`u` and similarly
:math:`v = v_m v_{m-1} \cdots v_2 v_1 v_0`, then the bits of the address within
the tile are given by the table below:
=========================================== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== ===========
Tiling 11 10 9 8 7 6 5 4 3 2 1 0
=========================================== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== ===========
:c:enumerator:`isl_tiling.ISL_TILING_X` :math:`v_2` :math:`v_1` :math:`v_0` :math:`u_8` :math:`u_7` :math:`u_6` :math:`u_5` :math:`u_4` :math:`u_3` :math:`u_2` :math:`u_1` :math:`u_0`
:c:enumerator:`isl_tiling.ISL_TILING_Y0` :math:`u_6` :math:`u_5` :math:`u_4` :math:`v_4` :math:`v_3` :math:`v_2` :math:`v_1` :math:`v_0` :math:`u_3` :math:`u_2` :math:`u_1` :math:`u_0`
:c:enumerator:`isl_tiling.ISL_TILING_W` :math:`u_5` :math:`u_4` :math:`u_3` :math:`v_5` :math:`v_4` :math:`v_3` :math:`v_2` :math:`u_2` :math:`v_1` :math:`u_1` :math:`v_0` :math:`u_0`
:c:enumerator:`isl_tiling.ISL_TILING_4` :math:`v_4` :math:`v_3` :math:`u_6` :math:`v_2` :math:`u_5` :math:`u_4` :math:`v_1` :math:`v_0` :math:`u_3` :math:`u_2` :math:`u_1` :math:`u_0`
=========================================== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== =========== ===========
Constructing the mapping this way makes a lot of sense when you think about
hardware. It may seem complex on paper but "simple" things such as addition
are relatively expensive in hardware while interleaving bits in a well-defined
pattern is practically free. For a format that has more than one byte per
element, you simply chop bits off the bottom of the pattern, hard-code them to
0, and adjust bit indices as needed. For a 128-bit format, for instance, the
Y-tiled pattern becomes :math:`u_2 u_1 u_0 v_4 v_3 v_2 v_1 v_0`. The Sky Lake
PRM Vol. 5 in the section "2D Surfaces" contains an expanded version of the
above table (which we will not repeat here) that also includes the bit patterns
for the Ys and Yf tiling formats.
+81
View File
@@ -0,0 +1,81 @@
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: ``_el`` for elements,
``_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
``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 ``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 compression
block height. Since the old surface state code tries to store things in
hardware units, everyone who ever reads ``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
:c: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
:c:member:`isl_surf.samples`. The exact layout of the samples depends on
the value of :c:member:`isl_surf.msaa_layout`. If the layout is
:c:enumerator:`isl_msaa_layout.ISL_MSAA_LAYOUT_ARRAY` then each logical array in
the surface corresponds to :c:member:`isl_surf.samples` actual slices
in the resulting surface, one per array slice. If the layout is
:c:enumerator:`isl_msaa_layout.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 :c:member:`isl_surf.phys_level0_sa`
which gives the dimensions of the base miplevel of the surface in samples. The
type of :c:member:`isl_surf.phys_level0_sa` is :c: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.