~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to docs/isl/formats.rst

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Surface Formats
2
 
===============
3
 
 
4
 
A surface format describes the encoding of color information into the actual
5
 
data stored in memory.  Surface formats in isl are specified via the
6
 
:cpp:enum:`isl_format` enum.  A complete list of surface formats is included at
7
 
the end of this chapter.
8
 
 
9
 
In general, a surface format definition consists of two parts: encoding and
10
 
layout.
11
 
 
12
 
Data Encoding
13
 
-------------
14
 
 
15
 
There are several different ways that one can encode a number (or vector) into
16
 
a binary form, and each makes different trade-offs.  By default, most color
17
 
values lie in the range [0, 1], so one of the most common encodings for color
18
 
data is unsigned normalized where the range of an unsigned integer of a
19
 
particular size is mapped linearly onto the interval [0, 1]. While normalized
20
 
is certainly the most common representation for color data, not all data is
21
 
color data, and not all values are nicely bounded.  The possible data encodings
22
 
are specified by :cpp:enum:`isl_base_type`:
23
 
 
24
 
.. doxygenenum:: isl_base_type
25
 
 
26
 
Data Layout
27
 
-----------
28
 
 
29
 
The different data layouts fall into two categories: array and packed.  When an
30
 
array layout is used, the components are stored sequentially in an array of the
31
 
given encoding.  For instance, if the data is encoded in an 8-bit RGBA array
32
 
format the data is stored in an array of type :c:type:`uint8_t` where the blue
33
 
component of the :c:expr:`i`'th color value is accessed as:
34
 
 
35
 
.. code-block:: C
36
 
 
37
 
   uint8_t r = ((uint8_t *)data)[i * 4 + 0];
38
 
   uint8_t g = ((uint8_t *)data)[i * 4 + 1];
39
 
   uint8_t b = ((uint8_t *)data)[i * 4 + 2];
40
 
   uint8_t a = ((uint8_t *)data)[i * 4 + 3];
41
 
 
42
 
Array formats are popular because of their simplicity.  However, they are
43
 
limited to formats where all components have the same size and fit in
44
 
a standard C data type.
45
 
 
46
 
Packed formats, on the other hand, are encoded with the entire color value
47
 
packed into a single 8, 16, or 32-bit value.  The components are specified by
48
 
which bits they occupy within that value.  For instance, with the popular
49
 
:c:expr:`RGB565` format, each :c:type:`vec3` takes up 16 bits and the
50
 
:c:expr:`i`'th color value is accessed as:
51
 
 
52
 
.. code-block:: C
53
 
 
54
 
   uint8_t r = (*(uint16_t *)data >> 0) & 0x1f;
55
 
   uint8_t g = (*(uint16_t *)data >> 5) & 0x3f;
56
 
   uint8_t b = (*(uint16_t *)data >> 11) & 0x1f;
57
 
 
58
 
Packed formats are useful because they allow you to specify formats with uneven
59
 
component sizes such as :c:expr:`RGBA1010102` or where the components are
60
 
smaller than 8 bits such as :c:expr:`RGB565` discussed above.  It does,
61
 
however, come with the restriction that the entire vector must fit within 8,
62
 
16, or 32 bits.
63
 
 
64
 
One has to be careful when reasoning about packed formats because it is easy to
65
 
get the color order wrong.  With array formats, the channel ordering is usually
66
 
implied directly from the format name with :c:expr:`RGBA8888` storing the
67
 
formats as in the first example and :c:expr:`BGRA8888` storing them in the BGRA
68
 
ordering.  Packed formats, however, are not as simple because some
69
 
specifications choose to use a MSB to LSB ordering and others LSB to MSB.  One
70
 
must be careful to pay attention to the enum in question in order to avoid
71
 
getting them backwards.
72
 
 
73
 
From an API perspective, both types of formats are available.  In Vulkan, the
74
 
formats that are of the form :c:enumerator:`VK_FORMAT_xxx_PACKEDn` are packed
75
 
formats where the entire color fits in :c:expr:`n` bits and formats without the
76
 
:c:expr:`_PACKEDn` suffix are array formats.  In GL, if you specify one of the
77
 
base types such as :c:enumerator:`GL_FLOAT` you get an array format but if you
78
 
specify a packed type such as :c:enumerator:`GL_UNSIGNED_INT_8_8_8_8_REV` you
79
 
get a packed format.
80
 
 
81
 
The following table provides a summary of the bit orderings of different packed
82
 
format specifications.  The bit ordering is relative to the reading of the enum
83
 
name from left to right.
84
 
 
85
 
=====================  ==============
86
 
Component               Left → Right
87
 
=====================  ==============
88
 
GL                       MSB → LSB
89
 
Vulkan                   MSB → LSB
90
 
mesa_format              LSB → MSB
91
 
Intel surface format     LSB → MSB
92
 
=====================  ==============
93
 
 
94
 
Understanding sRGB
95
 
------------------
96
 
 
97
 
The sRGB colorspace is one of the least tractable concepts in the entire world
98
 
of surfaces and formats.  Most texture formats are stored in a linear
99
 
colorspace where the floating-point value corresponds linearly to intensity
100
 
values.  The sRGB color space, on the other hand, is non-linear and provides
101
 
greater precision in the lower-intensity (darker) end of the spectrum.  The
102
 
relationship between linear and sRGB is governed by the following continuous
103
 
bijection:
104
 
 
105
 
.. math::
106
 
 
107
 
   c_l =
108
 
   \begin{cases}
109
 
   \frac{c_s}{12.92}                            &\text{if } c_s \le 0.04045 \\\\
110
 
   \left(\frac{c_s + 0.055}{1.055}\right)^{2.4} &\text{if } c_s > 0.04045
111
 
   \end{cases}
112
 
 
113
 
where :math:`c_l` is the linear color and :math:`c_s` is the color in sRGB.
114
 
It is important to note that, when an alpha channel is present, the alpha
115
 
channel is always stored in the linear colorspace.
116
 
 
117
 
The key to understanding sRGB is to think about it starting from the physical
118
 
display.  All displays work natively in sRGB.  On older displays, there isn't
119
 
so much a conversion operation as a fact of how the hardware works.  All
120
 
display hardware has a natural gamma curve required to get from linear to the
121
 
signal level required to generate the correct color.  On older CRT displays,
122
 
the gamma curve of your average CRT is approximately the sRGB curve.  More
123
 
modern display hardware has support for additional gamma curves to try and get
124
 
accurate colors but, for the sake of compatibility, everything still operates
125
 
in sRGB.  When an image is sent to the X server, X passes the pixels on to the
126
 
display verbatim without doing any conversions.  (Fun fact: When dealing with
127
 
translucent windows, X blends in the wrong colorspace.)  This means that the
128
 
image into which you are rendering will always be interpreted as if it were in
129
 
the sRGB colorspace.
130
 
 
131
 
When sampling from a texture, the value returned to the shader is in the linear
132
 
colorspace.  The conversion from sRGB happens as part of sampling. In OpenGL,
133
 
thanks mostly to history, there are various knobs for determining when you
134
 
should or should not encode or decode sRGB.  In 2007, GL_EXT_texture_sRGB added
135
 
support for sRGB texture formats and was included in OpenGL 2.1.  In 2010,
136
 
GL_EXT_texture_sRGB_decode added a flag to allow you to disable texture
137
 
decoding so that the shader received the data still in the sRGB colorspace.
138
 
Then, in 2012, GL_ARB_texture_view came along and made
139
 
GL_EXT_texture_sRGB_decode` simultaneously obsolete and very confusing.  Now,
140
 
thanks to the combination of extensions, you can upload a texture as linear,
141
 
create an sRGB view of it and ask that sRGB not be decoded.  What format is it
142
 
in again?
143
 
 
144
 
The situation with render targets is a bit different.  Historically, you got
145
 
your render target from the window system (which is always sRGB) and the spec
146
 
said nothing whatsoever about encoding.  All render targets were sRGB because
147
 
that's how monitors worked and application writers were expected to understand
148
 
that their final rendering needed to be in sRGB.  However, with the advent of
149
 
EXT_framebuffer_object this was no longer true.  Also, sRGB was causing
150
 
problems with blending because GL was blind to the fact that the output was
151
 
sRGB and blending was occurring in the wrong colorspace. In 2006, a set of
152
 
EXT_framebuffer_sRGB extensions added support (on both the GL and window-system
153
 
sides) for detecting whether a particular framebuffer was in sRGB and
154
 
instructing GL to do the conversion into the sRGB colorspace as the final step
155
 
prior to writing out to the render target.  Enabling sRGB also implied that
156
 
blending would occur in the linear colorspace prior to sRGB conversion and
157
 
would therefore be more accurate.  When sRGB was added to the OpenGL ES spec in
158
 
3.1, they added the query for sRGB but did not add the flag to allow you to
159
 
turn it on and off.
160
 
 
161
 
In Vulkan, this is all much more straightforward.  Your format is sRGB or it
162
 
isn't.  If you have an sRGB image and you don't want sRGB decoding to happen
163
 
when you sample from it, you simply create a c:struct:`VkImageView` that has
164
 
the appropriate linear format and the data will be treated as linear and not
165
 
converted.  Similarly for render targets, blending always happens in the same
166
 
colorspace as the shader output and you determine whether or not you want sRGB
167
 
conversion by the format of the c:struct:`VkImageView` used as the render
168
 
target.
169
 
 
170
 
Surface Format Introspection API
171
 
--------------------------------
172
 
 
173
 
ISL provides an API for introspecting the :cpp:enum:`isl_format` enum and
174
 
getting various bits of information about a format.  ISL provides helpers for
175
 
introspecting both the data layout of an cpp:enum:`isl_format` and the
176
 
capabilities of that format for a particular piece of Intel hardware.
177
 
 
178
 
Format Layout Introspection
179
 
^^^^^^^^^^^^^^^^^^^^^^^^^^^
180
 
 
181
 
To get the layout of a given :cpp:enum:`isl_format`, call
182
 
:cpp:func:`isl_format_get_layout`:
183
 
 
184
 
.. doxygenfunction:: isl_format_get_layout
185
 
 
186
 
.. doxygenstruct:: isl_format_layout
187
 
   :members:
188
 
 
189
 
.. doxygenstruct:: isl_channel_layout
190
 
   :members:
191
 
 
192
 
There are also quite a few helpers for many of the common cases that allow you
193
 
to avoid using :cpp:struct:`isl_format_layout` manually.  There are a lot of
194
 
them so we won't include a full list here.  Look at isl.h for more details.
195
 
 
196
 
Hardware Format Support Introspection
197
 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
198
 
 
199
 
This is provided by means of a table located in isl_format.c.  Looking at the
200
 
table directly is often useful for understanding HW support for various
201
 
formats.  However, for the purposes of code cleanliness, the table is not
202
 
exposed directly and, instead, hardware support information is exposed via
203
 
a set of helper functions:
204
 
 
205
 
.. doxygenfunction:: isl_format_supports_rendering
206
 
.. doxygenfunction:: isl_format_supports_alpha_blending
207
 
.. doxygenfunction:: isl_format_supports_sampling
208
 
.. doxygenfunction:: isl_format_supports_filtering
209
 
.. doxygenfunction:: isl_format_supports_vertex_fetch
210
 
.. doxygenfunction:: isl_format_supports_typed_writes
211
 
.. doxygenfunction:: isl_format_supports_typed_reads
212
 
.. doxygenfunction:: isl_format_supports_ccs_d
213
 
.. doxygenfunction:: isl_format_supports_ccs_e
214
 
.. doxygenfunction:: isl_format_supports_multisampling
215
 
.. doxygenfunction:: isl_formats_are_ccs_e_compatible
216
 
 
217
 
Surface Format Enums
218
 
--------------------
219
 
 
220
 
Everything in ISL is done in terms of the :cpp:enum:`isl_format` enum. However,
221
 
for the sake of interacting with other parts of Mesa, we provide a helper for
222
 
converting a :cpp:enum:`pipe_format` to an :cpp:enum:`isl_format`:
223
 
 
224
 
.. doxygenfunction:: isl_format_for_pipe_format
225
 
 
226
 
The :cpp:enum:`isl_format` enum is as follows:
227
 
 
228
 
.. doxygenenum:: isl_format