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