• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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