Mesa (main): docs/isl: Add detailed documentation about isl formats

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jun 18 13:29:58 UTC 2021


Module: Mesa
Branch: main
Commit: 0f6ebd2b73207845be0f01d49c22b0a48c7ff367
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=0f6ebd2b73207845be0f01d49c22b0a48c7ff367

Author: Jason Ekstrand <jason at jlekstrand.net>
Date:   Mon Jun 14 23:44:05 2021 -0500

docs/isl: Add detailed documentation about isl formats

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11366>

---

 docs/isl/formats.rst | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++
 docs/isl/index.rst   |   1 +
 src/intel/isl/isl.h  | 116 ++++++++++++++++++++++++--
 3 files changed, 339 insertions(+), 6 deletions(-)

diff --git a/docs/isl/formats.rst b/docs/isl/formats.rst
new file mode 100644
index 00000000000..71a32158d8c
--- /dev/null
+++ b/docs/isl/formats.rst
@@ -0,0 +1,228 @@
+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
+:cpp: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 :cpp:enum:`isl_base_type`:
+
+.. doxygenenum:: isl_base_type
+
+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 :c:expr:`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
+:c:expr:`RGB565` format, each :c:type:`vec3` takes up 16 bits and the
+:c:expr:`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 :c:expr:`RGBA1010102` or where the components are
+smaller than 8 bits such as :c:expr:`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 :c:expr:`RGBA8888` storing the
+formats as in the first example and :c:expr:`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 :c:enumerator:`VK_FORMAT_xxx_PACKEDn` are packed
+formats where the entire color fits in :c:expr:`n` bits and formats without the
+:c:expr:`_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, GL_EXT_texture_sRGB added
+support for sRGB texture formats and was included in OpenGL 2.1.  In 2010,
+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, GL_ARB_texture_view came along and made
+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_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_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 :cpp:enum:`isl_format` enum and
+getting various bits of information about a format.  ISL provides helpers for
+introspecting both the data layout of an cpp: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 :cpp:enum:`isl_format`, call
+:cpp:func:`isl_format_get_layout`:
+
+.. doxygenfunction:: isl_format_get_layout
+
+.. doxygenstruct:: isl_format_layout
+   :members:
+
+.. doxygenstruct:: isl_channel_layout
+   :members:
+
+There are also quite a few helpers for many of the common cases that allow you
+to avoid using :cpp: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:
+
+.. doxygenfunction:: isl_format_supports_rendering
+.. doxygenfunction:: isl_format_supports_alpha_blending
+.. doxygenfunction:: isl_format_supports_sampling
+.. doxygenfunction:: isl_format_supports_filtering
+.. doxygenfunction:: isl_format_supports_vertex_fetch
+.. doxygenfunction:: isl_format_supports_typed_writes
+.. doxygenfunction:: isl_format_supports_typed_reads
+.. doxygenfunction:: isl_format_supports_ccs_d
+.. doxygenfunction:: isl_format_supports_ccs_e
+.. doxygenfunction:: isl_format_supports_multisampling
+.. doxygenfunction:: isl_formats_are_ccs_e_compatible
+
+Surface Format Enums
+--------------------
+
+Everything in ISL is done in terms of the :cpp:enum:`isl_format` enum. However,
+for the sake of interacting with other parts of Mesa, we provide a helper for
+converting a :cpp:enum:`pipe_format` to an :cpp:enum:`isl_format`:
+
+.. doxygenfunction:: isl_format_for_pipe_format
+
+The :cpp:enum:`isl_format` enum is as follows:
+
+.. doxygenenum:: isl_format
diff --git a/docs/isl/index.rst b/docs/isl/index.rst
index e3dbd694a19..74dbcda171d 100644
--- a/docs/isl/index.rst
+++ b/docs/isl/index.rst
@@ -10,6 +10,7 @@ Chery.
    :maxdepth: 2
 
    units
+   formats
 
 The core representation of a surface in ISL is :cpp:struct:`isl_surf`.
 
diff --git a/src/intel/isl/isl.h b/src/intel/isl/isl.h
index c2fb791c23d..2a03bc847dc 100644
--- a/src/intel/isl/isl.h
+++ b/src/intel/isl/isl.h
@@ -415,17 +415,113 @@ enum isl_format {
  * Numerical base type for channels of isl_format.
  */
 enum PACKED isl_base_type {
+   /** Data which takes up space but is ignored */
    ISL_VOID,
+
+   /** Data in a "raw" form and cannot be easily interpreted */
    ISL_RAW,
+
+   /**
+    * Unsigned normalized data
+    *
+    * Though stored as an integer, the data is interpreted as a floating-point
+    * number in the range [0, 1] where the conversion from the in-memory
+    * representation to float is given by \f$\frac{x}{2^{bits} - 1}\f$.
+    */
    ISL_UNORM,
+
+   /**
+    * Signed normalized data
+    *
+    * Though stored as an integer, the data is interpreted as a floating-point
+    * number in the range [-1, 1] where the conversion from the in-memory
+    * representation to float is given by
+    * \f$max\left(\frac{x}{2^{bits - 1} - 1}, -1\right)\f$.
+    */
    ISL_SNORM,
+
+   /**
+    * Unsigned floating-point data
+    *
+    * Unlike the standard IEEE floating-point representation, unsigned
+    * floating-point data has no sign bit. This saves a bit of space which is
+    * important if more than one float is required to represent a color value.
+    * As with IEEE floats, the high bits are the exponent and the low bits are
+    * the mantissa.  The available bit sizes for unsigned floats are as
+    * follows:
+    *
+    * \rst
+    * =====  =========  =========
+    * Bits   Mantissa   Exponent
+    * =====  =========  =========
+    *  11       6          5
+    *  10       5          5
+    * =====  =========  =========
+    * \endrst
+    *
+    * In particular, both unsigned floating-point formats are identical to
+    * IEEE float16 except that the sign bit and the bottom mantissa bits are
+    * removed.
+    */
    ISL_UFLOAT,
+
+   /** Signed floating-point data
+    *
+    * Signed floating-point data is represented as standard IEEE floats with
+    * the usual number of mantissa and exponent bits
+    *
+    * \rst
+    * =====  =========  =========
+    * Bits   Mantissa   Exponent
+    * =====  =========  =========
+    *  64      52         11
+    *  32      23          8
+    *  16      10          5
+    * =====  =========  =========
+    * \endrst
+    */
    ISL_SFLOAT,
+
+   /**
+    * Unsigned fixed-point data
+    *
+    * This is a 32-bit unsigned integer that is interpreted as a 16.16
+    * fixed-point value.
+    */
    ISL_UFIXED,
+
+   /**
+    * Signed fixed-point data
+    *
+    * This is a 32-bit signed integer that is interpreted as a 16.16
+    * fixed-point value.
+    */
    ISL_SFIXED,
+
+   /** Unsigned integer data */
    ISL_UINT,
+
+   /** Signed integer data */
    ISL_SINT,
+
+   /**
+    * Unsigned scaled data
+    *
+    * This is data which is stored as an unsigned integer but interpreted as a
+    * floating-point value by the hardware.  The re-interpretation is done via
+    * a simple unsigned integer to float cast.  This is typically used as a
+    * vertex format.
+    */
    ISL_USCALED,
+
+   /**
+    * Signed scaled data
+    *
+    * This is data which is stored as a signed integer but interpreted as a
+    * floating-point value by the hardware.  The re-interpretation is done via
+    * a simple signed integer to float cast.  This is typically used as a
+    * vertex format.
+    */
    ISL_SSCALED,
 };
 
@@ -1101,21 +1197,26 @@ struct isl_extent4d {
    union { uint32_t a, array_len; };
 };
 
+/**
+ * Describes a single channel of an isl_format
+ */
 struct isl_channel_layout {
-   enum isl_base_type type;
+   enum isl_base_type type; /**< Channel data encoding */
    uint8_t start_bit; /**< Bit at which this channel starts */
    uint8_t bits; /**< Size in bits */
 };
 
 /**
+ * Describes the layout of an isl_format
+ *
  * Each format has 3D block extent (width, height, depth). The block extent of
  * compressed formats is that of the format's compression block. For example,
- * the block extent of ISL_FORMAT_ETC2_RGB8 is (w=4, h=4, d=1).  The block
- * extent of uncompressed pixel formats, such as ISL_FORMAT_R8G8B8A8_UNORM, is
- * is (w=1, h=1, d=1).
+ * the block extent of `ISL_FORMAT_ETC2_RGB8` is `(w=4, h=4, d=1)`. The block
+ * extent of uncompressed pixel formats, such as `ISL_FORMAT_R8G8B8A8_UNORM`,
+ * is `(w=1, h=1, d=1)`.
  */
 struct isl_format_layout {
-   enum isl_format format;
+   enum isl_format format; /**< Format */
 
    uint16_t bpb; /**< Bits per block */
    uint8_t bw; /**< Block width, in pixels */
@@ -1135,7 +1236,7 @@ struct isl_format_layout {
       struct isl_channel_layout channels_array[7];
    };
 
-   /** Set if all channels have the same isl_base_type. Otherwise, ISL_BASE_VOID. */
+   /** Set if all channels have the same isl_base_type. Otherwise, ISL_VOID. */
    enum isl_base_type uniform_channel_type;
 
    enum isl_colorspace colorspace;
@@ -1569,6 +1670,9 @@ isl_device_init(struct isl_device *dev,
 isl_sample_count_mask_t ATTRIBUTE_CONST
 isl_device_get_sample_counts(struct isl_device *dev);
 
+/**
+ * \return The isl_format_layout for the given isl_format
+ */
 static inline const struct isl_format_layout * ATTRIBUTE_CONST
 isl_format_get_layout(enum isl_format fmt)
 {



More information about the mesa-commit mailing list