1 /*
2 * Copyright © 2023 Valve Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "lvp_private.h"
25
lvp_CreateIndirectExecutionSetEXT(VkDevice _device,const VkIndirectExecutionSetCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkIndirectExecutionSetEXT * pIndirectExecutionSet)26 VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateIndirectExecutionSetEXT(
27 VkDevice _device,
28 const VkIndirectExecutionSetCreateInfoEXT* pCreateInfo,
29 const VkAllocationCallbacks* pAllocator,
30 VkIndirectExecutionSetEXT* pIndirectExecutionSet)
31 {
32 LVP_FROM_HANDLE(lvp_device, device, _device);
33 bool is_shaders = pCreateInfo->type == VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT;
34 size_t size = 0;
35 if (is_shaders) {
36 size += pCreateInfo->info.pShaderInfo->maxShaderCount;
37 } else {
38 size += pCreateInfo->info.pPipelineInfo->maxPipelineCount;
39 }
40 size *= sizeof(int64_t);
41 size += sizeof(struct lvp_indirect_execution_set);
42
43 struct lvp_indirect_execution_set *iset =
44 vk_zalloc2(&device->vk.alloc, pAllocator, size, alignof(struct lvp_indirect_execution_set),
45 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
46 if (!iset)
47 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
48
49 vk_object_base_init(&device->vk, &iset->base, VK_OBJECT_TYPE_INDIRECT_EXECUTION_SET_EXT);
50 iset->is_shaders = is_shaders;
51
52 if (is_shaders) {
53 for (unsigned i = 0; i < pCreateInfo->info.pShaderInfo->shaderCount; i++)
54 iset->array[i] = pCreateInfo->info.pShaderInfo->pInitialShaders[i];
55 } else {
56 iset->array[0] = pCreateInfo->info.pPipelineInfo->initialPipeline;
57 }
58
59 *pIndirectExecutionSet = lvp_indirect_execution_set_to_handle(iset);
60 return VK_SUCCESS;
61 }
62
lvp_DestroyIndirectExecutionSetEXT(VkDevice _device,VkIndirectExecutionSetEXT indirectExecutionSet,const VkAllocationCallbacks * pAllocator)63 VKAPI_ATTR void VKAPI_CALL lvp_DestroyIndirectExecutionSetEXT(
64 VkDevice _device,
65 VkIndirectExecutionSetEXT indirectExecutionSet,
66 const VkAllocationCallbacks* pAllocator)
67 {
68 LVP_FROM_HANDLE(lvp_device, device, _device);
69 VK_FROM_HANDLE(lvp_indirect_execution_set, iset, indirectExecutionSet);
70
71 if (!iset)
72 return;
73
74 vk_object_base_finish(&iset->base);
75 vk_free2(&device->vk.alloc, pAllocator, iset);
76 }
77
lvp_UpdateIndirectExecutionSetPipelineEXT(VkDevice device,VkIndirectExecutionSetEXT indirectExecutionSet,uint32_t executionSetWriteCount,const VkWriteIndirectExecutionSetPipelineEXT * pExecutionSetWrites)78 VKAPI_ATTR void VKAPI_CALL lvp_UpdateIndirectExecutionSetPipelineEXT(
79 VkDevice device,
80 VkIndirectExecutionSetEXT indirectExecutionSet,
81 uint32_t executionSetWriteCount,
82 const VkWriteIndirectExecutionSetPipelineEXT* pExecutionSetWrites)
83 {
84 VK_FROM_HANDLE(lvp_indirect_execution_set, iset, indirectExecutionSet);
85
86 assert(!iset->is_shaders);
87 for (unsigned i = 0; i < executionSetWriteCount; i++) {
88 iset->array[pExecutionSetWrites[i].index] = pExecutionSetWrites[i].pipeline;
89 }
90 }
91
lvp_UpdateIndirectExecutionSetShaderEXT(VkDevice device,VkIndirectExecutionSetEXT indirectExecutionSet,uint32_t executionSetWriteCount,const VkWriteIndirectExecutionSetShaderEXT * pExecutionSetWrites)92 VKAPI_ATTR void VKAPI_CALL lvp_UpdateIndirectExecutionSetShaderEXT(
93 VkDevice device,
94 VkIndirectExecutionSetEXT indirectExecutionSet,
95 uint32_t executionSetWriteCount,
96 const VkWriteIndirectExecutionSetShaderEXT* pExecutionSetWrites)
97 {
98 VK_FROM_HANDLE(lvp_indirect_execution_set, iset, indirectExecutionSet);
99
100 assert(iset->is_shaders);
101 for (unsigned i = 0; i < executionSetWriteCount; i++) {
102 iset->array[pExecutionSetWrites[i].index] = pExecutionSetWrites[i].shader;
103 }
104 }
105
106 static size_t
get_token_info_size(VkIndirectCommandsTokenTypeEXT type)107 get_token_info_size(VkIndirectCommandsTokenTypeEXT type)
108 {
109 switch (type) {
110 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT:
111 return sizeof(VkIndirectCommandsVertexBufferTokenEXT);
112 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT:
113 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT:
114 return sizeof(VkIndirectCommandsPushConstantTokenEXT);
115 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT:
116 return sizeof(VkIndirectCommandsIndexBufferTokenEXT);
117 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT:
118 return sizeof(VkIndirectCommandsExecutionSetTokenEXT);
119 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT:
120 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT:
121 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT:
122 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT:
123 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT:
124 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT:
125 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT:
126 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT:
127 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT:
128 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT:
129 return 0;
130 default: break;
131 }
132 unreachable("unknown token type");
133 }
134
lvp_CreateIndirectCommandsLayoutEXT(VkDevice _device,const VkIndirectCommandsLayoutCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkIndirectCommandsLayoutEXT * pIndirectCommandsLayout)135 VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateIndirectCommandsLayoutEXT(
136 VkDevice _device,
137 const VkIndirectCommandsLayoutCreateInfoEXT* pCreateInfo,
138 const VkAllocationCallbacks* pAllocator,
139 VkIndirectCommandsLayoutEXT* pIndirectCommandsLayout)
140 {
141 LVP_FROM_HANDLE(lvp_device, device, _device);
142 struct lvp_indirect_command_layout_ext *elayout;
143 size_t token_size = pCreateInfo->tokenCount * sizeof(VkIndirectCommandsLayoutTokenEXT);
144
145 for (unsigned i = 0; i < pCreateInfo->tokenCount; i++) {
146 const VkIndirectCommandsLayoutTokenEXT *token = &pCreateInfo->pTokens[i];
147 token_size += get_token_info_size(token->type);
148 }
149
150 elayout = vk_indirect_command_layout_create(&device->vk, pCreateInfo, pAllocator, sizeof(struct lvp_indirect_command_layout_ext) + token_size);
151 if (!elayout)
152 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
153
154 enum lvp_indirect_layout_type type = LVP_INDIRECT_COMMAND_LAYOUT_DRAW;
155
156 for (unsigned i = 0; i < pCreateInfo->tokenCount; i++) {
157 const VkIndirectCommandsLayoutTokenEXT *token = &pCreateInfo->pTokens[i];
158 switch (token->type) {
159 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT:
160 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT:
161 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT:
162 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT:
163 type = LVP_INDIRECT_COMMAND_LAYOUT_DRAW;
164 break;
165 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT:
166 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT:
167 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT:
168 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT:
169 type = LVP_INDIRECT_COMMAND_LAYOUT_DRAW_COUNT;
170 break;
171 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT:
172 type = LVP_INDIRECT_COMMAND_LAYOUT_DISPATCH;
173 break;
174 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT:
175 type = LVP_INDIRECT_COMMAND_LAYOUT_RAYS;
176 break;
177 default: break;
178 }
179 }
180 elayout->type = type;
181
182 /* tokens are the last member of the struct */
183 size_t tokens_offset = sizeof(struct lvp_indirect_command_layout_ext) + pCreateInfo->tokenCount * sizeof(VkIndirectCommandsLayoutTokenEXT);
184 typed_memcpy(elayout->tokens, pCreateInfo->pTokens, pCreateInfo->tokenCount);
185 uint8_t *ptr = ((uint8_t *)elayout) + tokens_offset;
186 /* after the tokens comes the token data */
187 for (unsigned i = 0; i < pCreateInfo->tokenCount; i++) {
188 const VkIndirectCommandsLayoutTokenEXT *token = &pCreateInfo->pTokens[i];
189 size_t tsize = get_token_info_size(token->type);
190 if (tsize) {
191 elayout->tokens[i].data.pPushConstant = (void*)ptr;
192 memcpy(ptr, token->data.pPushConstant, tsize);
193 }
194 ptr += tsize;
195 }
196
197 *pIndirectCommandsLayout = lvp_indirect_command_layout_ext_to_handle(elayout);
198 return VK_SUCCESS;
199 }
200
lvp_DestroyIndirectCommandsLayoutEXT(VkDevice _device,VkIndirectCommandsLayoutEXT indirectCommandsLayout,const VkAllocationCallbacks * pAllocator)201 VKAPI_ATTR void VKAPI_CALL lvp_DestroyIndirectCommandsLayoutEXT(
202 VkDevice _device,
203 VkIndirectCommandsLayoutEXT indirectCommandsLayout,
204 const VkAllocationCallbacks* pAllocator)
205 {
206 LVP_FROM_HANDLE(lvp_device, device, _device);
207 VK_FROM_HANDLE(lvp_indirect_command_layout_ext, elayout, indirectCommandsLayout);
208
209 if (!elayout)
210 return;
211
212 vk_indirect_command_layout_destroy(&device->vk, pAllocator, &elayout->vk);
213 }
214
215
216 enum vk_cmd_type
lvp_ext_dgc_token_to_cmd_type(const struct lvp_indirect_command_layout_ext * elayout,const VkIndirectCommandsLayoutTokenEXT * token)217 lvp_ext_dgc_token_to_cmd_type(const struct lvp_indirect_command_layout_ext *elayout, const VkIndirectCommandsLayoutTokenEXT *token)
218 {
219 switch (token->type) {
220 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT:
221 return VK_CMD_BIND_VERTEX_BUFFERS2;
222 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT:
223 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT:
224 return VK_CMD_PUSH_CONSTANTS2;
225 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT:
226 return VK_CMD_BIND_INDEX_BUFFER2;
227 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT:
228 return elayout->vk.is_shaders ? VK_CMD_BIND_SHADERS_EXT : VK_CMD_BIND_PIPELINE;
229 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT:
230 return VK_CMD_DRAW_INDEXED;
231 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT:
232 return VK_CMD_DRAW;
233 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT:
234 return VK_CMD_DRAW_INDEXED_INDIRECT;
235 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT:
236 return VK_CMD_DRAW_INDIRECT;
237 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT:
238 return VK_CMD_DISPATCH;
239 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT:
240 return VK_CMD_TRACE_RAYS_KHR;
241 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT:
242 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT:
243 unreachable("unsupported NV mesh");
244 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT:
245 return VK_CMD_DRAW_MESH_TASKS_EXT;
246 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT:
247 return VK_CMD_DRAW_MESH_TASKS_INDIRECT_EXT;
248 default:
249 unreachable("unknown token type");
250 }
251 return UINT32_MAX;
252 }
253
254 size_t
lvp_ext_dgc_token_size(const struct lvp_indirect_command_layout_ext * elayout,const VkIndirectCommandsLayoutTokenEXT * token)255 lvp_ext_dgc_token_size(const struct lvp_indirect_command_layout_ext *elayout, const VkIndirectCommandsLayoutTokenEXT *token)
256 {
257 UNUSED struct vk_cmd_queue_entry *cmd;
258 enum vk_cmd_type type = lvp_ext_dgc_token_to_cmd_type(elayout, token);
259 size_t size = vk_cmd_queue_type_sizes[type];
260 if (token->type == VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT || token->type == VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT) {
261 size += sizeof(*cmd->u.push_constants2.push_constants_info);
262 size += token->data.pPushConstant->updateRange.size;
263 return size;
264 }
265 if (token->type == VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT) {
266 /* special case: switch between pipelines/shaders */
267 /* CmdBindShaders has 2 dynamically sized arrays */
268 if (elayout->vk.is_shaders)
269 size += sizeof(int64_t) * util_bitcount(token->data.pExecutionSet->shaderStages) * 2;
270 return size;
271 }
272
273 if (token->type == VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT)
274 return size + sizeof(VkStridedDeviceAddressRegionKHR) * 4;
275
276 switch (token->type) {
277 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT:
278 size += sizeof(*cmd->u.bind_vertex_buffers.buffers);
279 size += sizeof(*cmd->u.bind_vertex_buffers.offsets);
280 size += sizeof(*cmd->u.bind_vertex_buffers2.sizes) + sizeof(*cmd->u.bind_vertex_buffers2.strides);
281 break;
282 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT:
283 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT:
284 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT:
285 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT:
286 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT:
287 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT:
288 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT:
289 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT:
290 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT:
291 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT:
292 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT:
293 case VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT:
294 break;
295 default:
296 unreachable("unknown type!");
297 }
298 return size;
299 }
300
lvp_GetGeneratedCommandsMemoryRequirementsEXT(VkDevice device,const VkGeneratedCommandsMemoryRequirementsInfoEXT * pInfo,VkMemoryRequirements2 * pMemoryRequirements)301 VKAPI_ATTR void VKAPI_CALL lvp_GetGeneratedCommandsMemoryRequirementsEXT(
302 VkDevice device,
303 const VkGeneratedCommandsMemoryRequirementsInfoEXT* pInfo,
304 VkMemoryRequirements2* pMemoryRequirements)
305 {
306 VK_FROM_HANDLE(lvp_indirect_command_layout_ext, elayout, pInfo->indirectCommandsLayout);
307
308 size_t size = sizeof(struct list_head);
309
310 for (unsigned i = 0; i < elayout->vk.token_count; i++) {
311 const VkIndirectCommandsLayoutTokenEXT *token = &elayout->tokens[i];
312 size += lvp_ext_dgc_token_size(elayout, token);
313 }
314 if (elayout->type == LVP_INDIRECT_COMMAND_LAYOUT_DRAW || elayout->type == LVP_INDIRECT_COMMAND_LAYOUT_DRAW_COUNT)
315 /* set/unset indirect draw offset */
316 size += sizeof(struct vk_cmd_queue_entry) * (pInfo->maxSequenceCount + 1);
317
318 size *= pInfo->maxSequenceCount;
319
320 pMemoryRequirements->memoryRequirements.memoryTypeBits = 1;
321 pMemoryRequirements->memoryRequirements.alignment = 4;
322 pMemoryRequirements->memoryRequirements.size = align(size, pMemoryRequirements->memoryRequirements.alignment);
323 }
324