17ec681f3SmrgSurface Formats
27ec681f3Smrg===============
37ec681f3Smrg
47ec681f3SmrgA surface format describes the encoding of color information into the actual
57ec681f3Smrgdata stored in memory.  Surface formats in isl are specified via the
67ec681f3Smrg:cpp:enum:`isl_format` enum.  A complete list of surface formats is included at
77ec681f3Smrgthe end of this chapter.
87ec681f3Smrg
97ec681f3SmrgIn general, a surface format definition consists of two parts: encoding and
107ec681f3Smrglayout.
117ec681f3Smrg
127ec681f3SmrgData Encoding
137ec681f3Smrg-------------
147ec681f3Smrg
157ec681f3SmrgThere are several different ways that one can encode a number (or vector) into
167ec681f3Smrga binary form, and each makes different trade-offs.  By default, most color
177ec681f3Smrgvalues lie in the range [0, 1], so one of the most common encodings for color
187ec681f3Smrgdata is unsigned normalized where the range of an unsigned integer of a
197ec681f3Smrgparticular size is mapped linearly onto the interval [0, 1]. While normalized
207ec681f3Smrgis certainly the most common representation for color data, not all data is
217ec681f3Smrgcolor data, and not all values are nicely bounded.  The possible data encodings
227ec681f3Smrgare specified by :cpp:enum:`isl_base_type`:
237ec681f3Smrg
247ec681f3Smrg.. doxygenenum:: isl_base_type
257ec681f3Smrg
267ec681f3SmrgData Layout
277ec681f3Smrg-----------
287ec681f3Smrg
297ec681f3SmrgThe different data layouts fall into two categories: array and packed.  When an
307ec681f3Smrgarray layout is used, the components are stored sequentially in an array of the
317ec681f3Smrggiven encoding.  For instance, if the data is encoded in an 8-bit RGBA array
327ec681f3Smrgformat the data is stored in an array of type :c:type:`uint8_t` where the blue
337ec681f3Smrgcomponent of the :c:expr:`i`'th color value is accessed as:
347ec681f3Smrg
357ec681f3Smrg.. code-block:: C
367ec681f3Smrg
377ec681f3Smrg   uint8_t r = ((uint8_t *)data)[i * 4 + 0];
387ec681f3Smrg   uint8_t g = ((uint8_t *)data)[i * 4 + 1];
397ec681f3Smrg   uint8_t b = ((uint8_t *)data)[i * 4 + 2];
407ec681f3Smrg   uint8_t a = ((uint8_t *)data)[i * 4 + 3];
417ec681f3Smrg
427ec681f3SmrgArray formats are popular because of their simplicity.  However, they are
437ec681f3Smrglimited to formats where all components have the same size and fit in
447ec681f3Smrga standard C data type.
457ec681f3Smrg
467ec681f3SmrgPacked formats, on the other hand, are encoded with the entire color value
477ec681f3Smrgpacked into a single 8, 16, or 32-bit value.  The components are specified by
487ec681f3Smrgwhich bits they occupy within that value.  For instance, with the popular
497ec681f3Smrg:c:expr:`RGB565` format, each :c:type:`vec3` takes up 16 bits and the
507ec681f3Smrg:c:expr:`i`'th color value is accessed as:
517ec681f3Smrg
527ec681f3Smrg.. code-block:: C
537ec681f3Smrg
547ec681f3Smrg   uint8_t r = (*(uint16_t *)data >> 0) & 0x1f;
557ec681f3Smrg   uint8_t g = (*(uint16_t *)data >> 5) & 0x3f;
567ec681f3Smrg   uint8_t b = (*(uint16_t *)data >> 11) & 0x1f;
577ec681f3Smrg
587ec681f3SmrgPacked formats are useful because they allow you to specify formats with uneven
597ec681f3Smrgcomponent sizes such as :c:expr:`RGBA1010102` or where the components are
607ec681f3Smrgsmaller than 8 bits such as :c:expr:`RGB565` discussed above.  It does,
617ec681f3Smrghowever, come with the restriction that the entire vector must fit within 8,
627ec681f3Smrg16, or 32 bits.
637ec681f3Smrg
647ec681f3SmrgOne has to be careful when reasoning about packed formats because it is easy to
657ec681f3Smrgget the color order wrong.  With array formats, the channel ordering is usually
667ec681f3Smrgimplied directly from the format name with :c:expr:`RGBA8888` storing the
677ec681f3Smrgformats as in the first example and :c:expr:`BGRA8888` storing them in the BGRA
687ec681f3Smrgordering.  Packed formats, however, are not as simple because some
697ec681f3Smrgspecifications choose to use a MSB to LSB ordering and others LSB to MSB.  One
707ec681f3Smrgmust be careful to pay attention to the enum in question in order to avoid
717ec681f3Smrggetting them backwards.
727ec681f3Smrg
737ec681f3SmrgFrom an API perspective, both types of formats are available.  In Vulkan, the
747ec681f3Smrgformats that are of the form :c:enumerator:`VK_FORMAT_xxx_PACKEDn` are packed
757ec681f3Smrgformats where the entire color fits in :c:expr:`n` bits and formats without the
767ec681f3Smrg:c:expr:`_PACKEDn` suffix are array formats.  In GL, if you specify one of the
777ec681f3Smrgbase types such as :c:enumerator:`GL_FLOAT` you get an array format but if you
787ec681f3Smrgspecify a packed type such as :c:enumerator:`GL_UNSIGNED_INT_8_8_8_8_REV` you
797ec681f3Smrgget a packed format.
807ec681f3Smrg
817ec681f3SmrgThe following table provides a summary of the bit orderings of different packed
827ec681f3Smrgformat specifications.  The bit ordering is relative to the reading of the enum
837ec681f3Smrgname from left to right.
847ec681f3Smrg
857ec681f3Smrg=====================  ==============
867ec681f3SmrgComponent               Left → Right
877ec681f3Smrg=====================  ==============
887ec681f3SmrgGL                       MSB → LSB
897ec681f3SmrgVulkan                   MSB → LSB
907ec681f3Smrgmesa_format              LSB → MSB
917ec681f3SmrgIntel surface format     LSB → MSB
927ec681f3Smrg=====================  ==============
937ec681f3Smrg
947ec681f3SmrgUnderstanding sRGB
957ec681f3Smrg------------------
967ec681f3Smrg
977ec681f3SmrgThe sRGB colorspace is one of the least tractable concepts in the entire world
987ec681f3Smrgof surfaces and formats.  Most texture formats are stored in a linear
997ec681f3Smrgcolorspace where the floating-point value corresponds linearly to intensity
1007ec681f3Smrgvalues.  The sRGB color space, on the other hand, is non-linear and provides
1017ec681f3Smrggreater precision in the lower-intensity (darker) end of the spectrum.  The
1027ec681f3Smrgrelationship between linear and sRGB is governed by the following continuous
1037ec681f3Smrgbijection:
1047ec681f3Smrg
1057ec681f3Smrg.. math::
1067ec681f3Smrg
1077ec681f3Smrg   c_l =
1087ec681f3Smrg   \begin{cases}
1097ec681f3Smrg   \frac{c_s}{12.92}                            &\text{if } c_s \le 0.04045 \\\\
1107ec681f3Smrg   \left(\frac{c_s + 0.055}{1.055}\right)^{2.4} &\text{if } c_s > 0.04045
1117ec681f3Smrg   \end{cases}
1127ec681f3Smrg
1137ec681f3Smrgwhere :math:`c_l` is the linear color and :math:`c_s` is the color in sRGB.
1147ec681f3SmrgIt is important to note that, when an alpha channel is present, the alpha
1157ec681f3Smrgchannel is always stored in the linear colorspace.
1167ec681f3Smrg
1177ec681f3SmrgThe key to understanding sRGB is to think about it starting from the physical
1187ec681f3Smrgdisplay.  All displays work natively in sRGB.  On older displays, there isn't
1197ec681f3Smrgso much a conversion operation as a fact of how the hardware works.  All
1207ec681f3Smrgdisplay hardware has a natural gamma curve required to get from linear to the
1217ec681f3Smrgsignal level required to generate the correct color.  On older CRT displays,
1227ec681f3Smrgthe gamma curve of your average CRT is approximately the sRGB curve.  More
1237ec681f3Smrgmodern display hardware has support for additional gamma curves to try and get
1247ec681f3Smrgaccurate colors but, for the sake of compatibility, everything still operates
1257ec681f3Smrgin sRGB.  When an image is sent to the X server, X passes the pixels on to the
1267ec681f3Smrgdisplay verbatim without doing any conversions.  (Fun fact: When dealing with
1277ec681f3Smrgtranslucent windows, X blends in the wrong colorspace.)  This means that the
1287ec681f3Smrgimage into which you are rendering will always be interpreted as if it were in
1297ec681f3Smrgthe sRGB colorspace.
1307ec681f3Smrg
1317ec681f3SmrgWhen sampling from a texture, the value returned to the shader is in the linear
1327ec681f3Smrgcolorspace.  The conversion from sRGB happens as part of sampling. In OpenGL,
1337ec681f3Smrgthanks mostly to history, there are various knobs for determining when you
1347ec681f3Smrgshould or should not encode or decode sRGB.  In 2007, GL_EXT_texture_sRGB added
1357ec681f3Smrgsupport for sRGB texture formats and was included in OpenGL 2.1.  In 2010,
1367ec681f3SmrgGL_EXT_texture_sRGB_decode added a flag to allow you to disable texture
1377ec681f3Smrgdecoding so that the shader received the data still in the sRGB colorspace.
1387ec681f3SmrgThen, in 2012, GL_ARB_texture_view came along and made
1397ec681f3SmrgGL_EXT_texture_sRGB_decode` simultaneously obsolete and very confusing.  Now,
1407ec681f3Smrgthanks to the combination of extensions, you can upload a texture as linear,
1417ec681f3Smrgcreate an sRGB view of it and ask that sRGB not be decoded.  What format is it
1427ec681f3Smrgin again?
1437ec681f3Smrg
1447ec681f3SmrgThe situation with render targets is a bit different.  Historically, you got
1457ec681f3Smrgyour render target from the window system (which is always sRGB) and the spec
1467ec681f3Smrgsaid nothing whatsoever about encoding.  All render targets were sRGB because
1477ec681f3Smrgthat's how monitors worked and application writers were expected to understand
1487ec681f3Smrgthat their final rendering needed to be in sRGB.  However, with the advent of
1497ec681f3SmrgEXT_framebuffer_object this was no longer true.  Also, sRGB was causing
1507ec681f3Smrgproblems with blending because GL was blind to the fact that the output was
1517ec681f3SmrgsRGB and blending was occurring in the wrong colorspace. In 2006, a set of
1527ec681f3SmrgEXT_framebuffer_sRGB extensions added support (on both the GL and window-system
1537ec681f3Smrgsides) for detecting whether a particular framebuffer was in sRGB and
1547ec681f3Smrginstructing GL to do the conversion into the sRGB colorspace as the final step
1557ec681f3Smrgprior to writing out to the render target.  Enabling sRGB also implied that
1567ec681f3Smrgblending would occur in the linear colorspace prior to sRGB conversion and
1577ec681f3Smrgwould therefore be more accurate.  When sRGB was added to the OpenGL ES spec in
1587ec681f3Smrg3.1, they added the query for sRGB but did not add the flag to allow you to
1597ec681f3Smrgturn it on and off.
1607ec681f3Smrg
1617ec681f3SmrgIn Vulkan, this is all much more straightforward.  Your format is sRGB or it
1627ec681f3Smrgisn't.  If you have an sRGB image and you don't want sRGB decoding to happen
1637ec681f3Smrgwhen you sample from it, you simply create a c:struct:`VkImageView` that has
1647ec681f3Smrgthe appropriate linear format and the data will be treated as linear and not
1657ec681f3Smrgconverted.  Similarly for render targets, blending always happens in the same
1667ec681f3Smrgcolorspace as the shader output and you determine whether or not you want sRGB
1677ec681f3Smrgconversion by the format of the c:struct:`VkImageView` used as the render
1687ec681f3Smrgtarget.
1697ec681f3Smrg
1707ec681f3SmrgSurface Format Introspection API
1717ec681f3Smrg--------------------------------
1727ec681f3Smrg
1737ec681f3SmrgISL provides an API for introspecting the :cpp:enum:`isl_format` enum and
1747ec681f3Smrggetting various bits of information about a format.  ISL provides helpers for
1757ec681f3Smrgintrospecting both the data layout of an cpp:enum:`isl_format` and the
1767ec681f3Smrgcapabilities of that format for a particular piece of Intel hardware.
1777ec681f3Smrg
1787ec681f3SmrgFormat Layout Introspection
1797ec681f3Smrg^^^^^^^^^^^^^^^^^^^^^^^^^^^
1807ec681f3Smrg
1817ec681f3SmrgTo get the layout of a given :cpp:enum:`isl_format`, call
1827ec681f3Smrg:cpp:func:`isl_format_get_layout`:
1837ec681f3Smrg
1847ec681f3Smrg.. doxygenfunction:: isl_format_get_layout
1857ec681f3Smrg
1867ec681f3Smrg.. doxygenstruct:: isl_format_layout
1877ec681f3Smrg   :members:
1887ec681f3Smrg
1897ec681f3Smrg.. doxygenstruct:: isl_channel_layout
1907ec681f3Smrg   :members:
1917ec681f3Smrg
1927ec681f3SmrgThere are also quite a few helpers for many of the common cases that allow you
1937ec681f3Smrgto avoid using :cpp:struct:`isl_format_layout` manually.  There are a lot of
1947ec681f3Smrgthem so we won't include a full list here.  Look at isl.h for more details.
1957ec681f3Smrg
1967ec681f3SmrgHardware Format Support Introspection
1977ec681f3Smrg^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1987ec681f3Smrg
1997ec681f3SmrgThis is provided by means of a table located in isl_format.c.  Looking at the
2007ec681f3Smrgtable directly is often useful for understanding HW support for various
2017ec681f3Smrgformats.  However, for the purposes of code cleanliness, the table is not
2027ec681f3Smrgexposed directly and, instead, hardware support information is exposed via
2037ec681f3Smrga set of helper functions:
2047ec681f3Smrg
2057ec681f3Smrg.. doxygenfunction:: isl_format_supports_rendering
2067ec681f3Smrg.. doxygenfunction:: isl_format_supports_alpha_blending
2077ec681f3Smrg.. doxygenfunction:: isl_format_supports_sampling
2087ec681f3Smrg.. doxygenfunction:: isl_format_supports_filtering
2097ec681f3Smrg.. doxygenfunction:: isl_format_supports_vertex_fetch
2107ec681f3Smrg.. doxygenfunction:: isl_format_supports_typed_writes
2117ec681f3Smrg.. doxygenfunction:: isl_format_supports_typed_reads
2127ec681f3Smrg.. doxygenfunction:: isl_format_supports_ccs_d
2137ec681f3Smrg.. doxygenfunction:: isl_format_supports_ccs_e
2147ec681f3Smrg.. doxygenfunction:: isl_format_supports_multisampling
2157ec681f3Smrg.. doxygenfunction:: isl_formats_are_ccs_e_compatible
2167ec681f3Smrg
2177ec681f3SmrgSurface Format Enums
2187ec681f3Smrg--------------------
2197ec681f3Smrg
2207ec681f3SmrgEverything in ISL is done in terms of the :cpp:enum:`isl_format` enum. However,
2217ec681f3Smrgfor the sake of interacting with other parts of Mesa, we provide a helper for
2227ec681f3Smrgconverting a :cpp:enum:`pipe_format` to an :cpp:enum:`isl_format`:
2237ec681f3Smrg
2247ec681f3Smrg.. doxygenfunction:: isl_format_for_pipe_format
2257ec681f3Smrg
2267ec681f3SmrgThe :cpp:enum:`isl_format` enum is as follows:
2277ec681f3Smrg
2287ec681f3Smrg.. doxygenenum:: isl_format
229