mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-10-31 19:08:03 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
@@ -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
|
||||
@@ -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.
|
||||
@@ -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:
|
||||
@@ -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);
|
||||
@@ -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:
|
||||
@@ -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 |
@@ -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.
|
||||
@@ -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.
|
||||
Reference in new issue
Block a user