• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Graphics state
2==============
3
4The Mesa Vulkan runtime provides helpers for managing the numerous pieces
5of graphics state associated with a ``VkPipeline`` or set dynamically on a
6command buffer.  No such helpers are provided for compute or ray-tracing
7because they have little or no state besides the shaders themselves.
8
9
10Pipeline state
11--------------
12
13All (possibly dynamic) Vulkan graphics pipeline state is encapsulated into
14a single :cpp:struct:`vk_graphics_pipeline_state` structure which contains
15pointers to sub-structures for each of the different state categories.
16Unlike :cpp:type:`VkGraphicsPipelineCreateInfo`, the pointers in
17:cpp:struct:`vk_graphics_pipeline_state` are guaranteed to be either be
18NULL or point to valid and properly populated memory.
19
20When creating a pipeline, the
21:cpp:func:`vk_graphics_pipeline_state_fill()` function can be used to
22gather all of the state from the core structures as well as various `pNext`
23chains into a single state structure.  Whenever an extension struct is
24missing, a reasonable default value is provided whenever possible.
25
26
27:cpp:func:`vk_graphics_pipeline_state_fill()` automatically handles both
28the render pass and dynamic rendering.  For drivers which use
29:cpp:struct:`vk_render_pass`, the :cpp:struct:`vk_render_pass_state`
30structure will be populated as if for dynamic rendering, regardless of
31which path is used.  Drivers which use their own render pass structure
32should parse the render pass, if available, and pass a
33:cpp:struct:`vk_subpass_info` into
34:cpp:func:`vk_graphics_pipeline_state_fill()` with the relevant information
35from the specified subpass.  If a render pass is available,
36:cpp:struct:`vk_render_pass_state` will be populated with the
37:cpp:type:`VkRenderPass` handle and subpass index as well as the
38information from the :cpp:struct:`vk_render_pass_state`.  If dynamic
39rendering is used or the driver does not provide a
40:cpp:struct:`vk_subpass_info` structure, :cpp:struct:`vk_render_pass_state`
41structure will be populated for dynamic rendering, including color, depth,
42and stencil attachment formats.
43
44.. doxygenstruct:: vk_subpass_info
45   :members:
46
47The usual flow for creating a full graphics pipeline (not library) looks
48like this:
49
50.. code-block:: c
51
52   struct vk_graphics_pipeline_state state = { };
53   struct vk_graphics_pipeline_all_state all;
54   vk_graphics_pipeline_state_fill(&device->vk, &state, pCreateInfo,
55                                   NULL, &all, NULL, 0, NULL);
56
57   /* Emit stuff using the state in `state` */
58
59The :cpp:struct:`vk_graphics_pipeline_all_state` structure exists to allow
60the state to sit on the stack instead of requiring a heap allocation.  This
61is useful if you intend to use the state right away and don't need to store
62it.  For pipeline libraries, it's likely more useful to use the dynamically
63allocated version and store the dynamically allocated memory in the
64library pipeline.
65
66.. code-block:: c
67
68   /* Assuming we have a vk_graphics_pipeline_state in pipeline */
69   memset(&pipeline->state, 0, sizeof(pipeline->state));
70
71   for (uint32_t i = 0; i < lib_info->libraryCount; i++) {
72      VK_FROM_HANDLE(drv_graphics_pipeline_library, lib, lib_info->pLibraries[i]);
73      vk_graphics_pipeline_state_merge(&pipeline->state, &lib->state);
74   }
75
76   /* This assumes you have a void **state_mem in pipeline */
77   result = vk_graphics_pipeline_state_fill(&device->vk, &pipeline->state,
78                                            pCreateInfo, NULL, NULL, pAllocator,
79                                            VK_SYSTEM_ALLOCATION_SCOPE_OBJECT,
80                                            &pipeline->state_mem);
81   if (result != VK_SUCCESS)
82      return result;
83
84State from dependent libraries can be merged together using
85:cpp:func:`vk_graphics_pipeline_state_merge`.
86:cpp:func:`vk_graphics_pipeline_state_fill` will then only attempt to
87populate missing fields.  You can also merge dependent pipeline libraries
88together but store the final state on the stack for immediate consumption:
89
90.. code-block:: c
91
92   struct vk_graphics_pipeline_state state = { };
93
94   for (uint32_t i = 0; i < lib_info->libraryCount; i++) {
95      VK_FROM_HANDLE(drv_graphics_pipeline_library, lib, lib_info->pLibraries[i]);
96      vk_graphics_pipeline_state_merge(&state, &lib->state);
97   }
98
99   struct vk_graphics_pipeline_all_state all;
100   vk_graphics_pipeline_state_fill(&device->vk, &state, pCreateInfo,
101                                   NULL, &all, NULL, 0, NULL);
102
103.. doxygenfunction:: vk_graphics_pipeline_state_fill
104
105.. doxygenfunction:: vk_graphics_pipeline_state_merge
106
107
108Dynamic state
109-------------
110
111All dynamic states in Vulkan, regardless of which API version or extension
112introduced them, are represented by the
113:cpp:enum:`mesa_vk_dynamic_graphics_state` enum.  This corresponds to the
114:cpp:type:`VkDynamicState` enum in the Vulkan API only it's compact (has no
115holes due to extension namespacing) and a bit better organized.  Each
116enumerant is named with the name of the state group to which the dynamic
117state belongs as well as the name of the dynamic state itself.  The fact
118that it's compact allows us to use to index bitsets.
119
120.. doxygenfunction:: vk_get_dynamic_graphics_states
121
122We also provide a :cpp:struct:`vk_dynamic_graphics_state` structure which
123contains all the dynamic graphics states, regardless of which API version
124or extension introduced them.  This structure can be populated from a
125:cpp:struct:`vk_graphics_pipeline_state` via
126:cpp:func:`vk_dynamic_graphics_state_init`.
127
128.. doxygenfunction:: vk_dynamic_graphics_state_init
129.. doxygenfunction:: vk_dynamic_graphics_state_copy
130
131There is also a :cpp:struct:`vk_dynamic_graphics_state` embedded in
132:cpp:struct:`vk_command_buffer`.  Should you choose to use them, we provide
133common implementations for all ``vkCmdSet*()`` functions.  Two additional
134functions are provided for the driver to call in ``CmdBindPipeline()`` and
135``CmdBindVertexBuffers2()``:
136
137.. doxygenfunction:: vk_cmd_set_dynamic_graphics_state
138.. doxygenfunction:: vk_cmd_set_vertex_binding_strides
139
140To use the dynamic state framework, you will need the following in your
141pipeline structure:
142
143.. code-block:: c
144
145   struct drv_graphics_pipeline {
146      ....
147      struct vk_vertex_input_state vi_state;
148      struct vk_sample_locations_state sl_state;
149      struct vk_dynamic_graphics_state dynamic;
150      ...
151   };
152
153Then, in your pipeline create function,
154
155.. code-block:: c
156
157   memset(&pipeline->dynamic, 0, sizeof(pipeline->dynamic));
158   pipeline->dynamic->vi = &pipeline->vi_state;
159   pipeline->dynamic->ms.sample_locations = &pipeline->sl_state;
160   vk_dynamic_graphics_state_init(&pipeline->dynamic, &state);
161
162In your implementation of ``vkCmdBindPipeline()``,
163
164.. code-block:: c
165
166   vk_cmd_set_dynamic_graphics_state(&cmd->vk, &pipeline->dynamic_state);
167
168And, finally, at ``vkCmdDraw*()`` time, the code to emit dynamic state into
169your hardware command buffer will look something like this:
170
171.. code-block:: c
172
173   static void
174   emit_dynamic_state(struct drv_cmd_buffer *cmd)
175   {
176      struct vk_dynamic_graphics_state *dyn = &cmd->vk.dynamic_graphics_state;
177
178      if (!vk_dynamic_graphics_state_any_dirty(dyn))
179         return;
180
181      if (BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_VIEWPORTS) |
182          BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_VIEWPORT_COUNT)) {
183         /* Re-emit viewports */
184      }
185
186      if (BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_SCISSORS) |
187          BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_SCISSOR_COUNT)) {
188         /* Re-emit scissors */
189      }
190
191      /* etc... */
192
193      vk_dynamic_graphics_state_clear_dirty(dyn);
194   }
195
196Any states used by the currently bound pipeline and attachments are always
197valid in ``vk_command_buffer::dynamic_graphics_state`` so you can always
198use a state even if it isn't dirty on this particular draw.
199
200.. doxygenfunction:: vk_dynamic_graphics_state_dirty_all
201.. doxygenfunction:: vk_dynamic_graphics_state_clear_dirty
202.. doxygenfunction:: vk_dynamic_graphics_state_any_dirty
203
204
205Depth stencil state optimization
206--------------------------------
207
208.. doxygenfunction:: vk_optimize_depth_stencil_state
209
210
211Reference
212---------
213
214.. doxygenstruct:: vk_graphics_pipeline_state
215   :members:
216
217.. doxygenstruct:: vk_vertex_binding_state
218   :members:
219
220.. doxygenstruct:: vk_vertex_attribute_state
221   :members:
222
223.. doxygenstruct:: vk_vertex_input_state
224   :members:
225
226.. doxygenstruct:: vk_input_assembly_state
227   :members:
228
229.. doxygenstruct:: vk_tessellation_state
230   :members:
231
232.. doxygenstruct:: vk_viewport_state
233   :members:
234
235.. doxygenstruct:: vk_discard_rectangles_state
236   :members:
237
238.. doxygenstruct:: vk_rasterization_state
239   :members:
240
241.. doxygenstruct:: vk_fragment_shading_rate_state
242   :members:
243
244.. doxygenstruct:: vk_sample_locations_state
245   :members:
246
247.. doxygenstruct:: vk_multisample_state
248   :members:
249
250.. doxygenstruct:: vk_stencil_test_face_state
251   :members:
252
253.. doxygenstruct:: vk_depth_stencil_state
254   :members:
255
256.. doxygenstruct:: vk_color_blend_state
257   :members:
258
259.. doxygenstruct:: vk_render_pass_state
260   :members:
261
262.. doxygenenum:: mesa_vk_dynamic_graphics_state
263
264.. doxygenstruct:: vk_dynamic_graphics_state
265   :members:
266