xref: /aosp_15_r20/external/mesa3d/src/amd/vulkan/radv_pipeline_binary.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2024 Valve Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "radv_pipeline_binary.h"
8 #include "util/disk_cache.h"
9 #include "util/macros.h"
10 #include "util/mesa-blake3.h"
11 #include "util/mesa-sha1.h"
12 #include "util/u_atomic.h"
13 #include "util/u_debug.h"
14 #include "nir_serialize.h"
15 #include "radv_debug.h"
16 #include "radv_device.h"
17 #include "radv_entrypoints.h"
18 #include "radv_pipeline_cache.h"
19 #include "radv_pipeline_graphics.h"
20 #include "radv_pipeline_rt.h"
21 #include "radv_shader.h"
22 #include "vk_log.h"
23 #include "vk_pipeline.h"
24 #include "vk_util.h"
25 
26 static VkResult
radv_get_pipeline_key(struct radv_device * device,const VkPipelineCreateInfoKHR * pPipelineCreateInfo,unsigned char * key)27 radv_get_pipeline_key(struct radv_device *device, const VkPipelineCreateInfoKHR *pPipelineCreateInfo,
28                       unsigned char *key)
29 {
30    VkResult result = VK_SUCCESS;
31 
32    switch (((VkBaseInStructure *)pPipelineCreateInfo->pNext)->sType) {
33    case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO: {
34       const VkGraphicsPipelineCreateInfo *graphics_create_info =
35          (VkGraphicsPipelineCreateInfo *)pPipelineCreateInfo->pNext;
36       struct radv_graphics_pipeline_state gfx_state;
37 
38       result = radv_generate_graphics_pipeline_state(device, graphics_create_info, &gfx_state);
39       if (result != VK_SUCCESS)
40          return result;
41 
42       radv_graphics_pipeline_hash(device, &gfx_state, key);
43       radv_graphics_pipeline_state_finish(device, &gfx_state);
44       break;
45    }
46    case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO: {
47       const VkComputePipelineCreateInfo *compute_create_info =
48          (VkComputePipelineCreateInfo *)pPipelineCreateInfo->pNext;
49 
50       radv_compute_pipeline_hash(device, compute_create_info, key);
51       break;
52    }
53    case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR: {
54       const VkRayTracingPipelineCreateInfoKHR *rt_create_info =
55          (VkRayTracingPipelineCreateInfoKHR *)pPipelineCreateInfo->pNext;
56       struct radv_ray_tracing_state_key rt_state;
57 
58       result = radv_generate_ray_tracing_state_key(device, rt_create_info, &rt_state);
59       if (result != VK_SUCCESS)
60          return result;
61 
62       radv_ray_tracing_pipeline_hash(device, rt_create_info, &rt_state, key);
63       radv_ray_tracing_state_key_finish(&rt_state);
64       break;
65    }
66    default:
67       unreachable("unsupported pipeline create info struct");
68    }
69 
70    return result;
71 }
72 
73 VKAPI_ATTR VkResult VKAPI_CALL
radv_GetPipelineKeyKHR(VkDevice _device,const VkPipelineCreateInfoKHR * pPipelineCreateInfo,VkPipelineBinaryKeyKHR * pPipelineKey)74 radv_GetPipelineKeyKHR(VkDevice _device, const VkPipelineCreateInfoKHR *pPipelineCreateInfo,
75                        VkPipelineBinaryKeyKHR *pPipelineKey)
76 {
77    VK_FROM_HANDLE(radv_device, device, _device);
78    VkResult result;
79 
80    memset(pPipelineKey->key, 0, sizeof(pPipelineKey->key));
81 
82    /* Return the global key that applies to all pipelines. */
83    if (!pPipelineCreateInfo) {
84       static_assert(sizeof(device->cache_hash) <= sizeof(pPipelineKey->key), "mismatch pipeline binary key size");
85 
86       memcpy(pPipelineKey->key, device->cache_hash, sizeof(device->cache_hash));
87       pPipelineKey->keySize = sizeof(device->cache_hash);
88 
89       return VK_SUCCESS;
90    }
91 
92    result = radv_get_pipeline_key(device, pPipelineCreateInfo, pPipelineKey->key);
93    if (result != VK_SUCCESS)
94       return result;
95 
96    pPipelineKey->keySize = SHA1_DIGEST_LENGTH;
97 
98    return VK_SUCCESS;
99 }
100 
101 static VkResult
radv_create_pipeline_binary(struct radv_device * device,const VkAllocationCallbacks * pAllocator,const blake3_hash key,const void * data,size_t data_size,struct radv_pipeline_binary ** pipeline_binary_out)102 radv_create_pipeline_binary(struct radv_device *device, const VkAllocationCallbacks *pAllocator, const blake3_hash key,
103                             const void *data, size_t data_size, struct radv_pipeline_binary **pipeline_binary_out)
104 {
105    struct radv_pipeline_binary *pipeline_binary;
106 
107    pipeline_binary =
108       vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*pipeline_binary), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
109    if (pipeline_binary == NULL)
110       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
111 
112    vk_object_base_init(&device->vk, &pipeline_binary->base, VK_OBJECT_TYPE_PIPELINE_BINARY_KHR);
113 
114    pipeline_binary->data = (void *)data;
115    pipeline_binary->size = data_size;
116 
117    memcpy(pipeline_binary->key, key, BLAKE3_OUT_LEN);
118 
119    *pipeline_binary_out = pipeline_binary;
120    return VK_SUCCESS;
121 }
122 
123 static VkResult
radv_create_pipeline_binary_from_data(struct radv_device * device,const VkAllocationCallbacks * pAllocator,const VkPipelineBinaryDataKHR * pData,const VkPipelineBinaryKeyKHR * pKey,struct util_dynarray * pipeline_binaries,uint32_t * num_binaries)124 radv_create_pipeline_binary_from_data(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
125                                       const VkPipelineBinaryDataKHR *pData, const VkPipelineBinaryKeyKHR *pKey,
126                                       struct util_dynarray *pipeline_binaries, uint32_t *num_binaries)
127 {
128    struct radv_pipeline_binary *pipeline_binary;
129    VkResult result;
130    void *data;
131 
132    if (!pipeline_binaries) {
133       (*num_binaries)++;
134       return VK_SUCCESS;
135    }
136 
137    data = malloc(pData->dataSize);
138    if (!data)
139       return VK_ERROR_OUT_OF_HOST_MEMORY;
140 
141    memcpy(data, pData->pData, pData->dataSize);
142 
143    result = radv_create_pipeline_binary(device, pAllocator, pKey->key, data, pData->dataSize, &pipeline_binary);
144    if (result != VK_SUCCESS) {
145       free(data);
146       return result;
147    }
148 
149    util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary);
150    return result;
151 }
152 
153 VkResult
radv_create_pipeline_binary_from_shader(struct radv_device * device,const VkAllocationCallbacks * pAllocator,struct radv_shader * shader,struct util_dynarray * pipeline_binaries,uint32_t * num_binaries)154 radv_create_pipeline_binary_from_shader(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
155                                         struct radv_shader *shader, struct util_dynarray *pipeline_binaries,
156                                         uint32_t *num_binaries)
157 {
158    struct radv_pipeline_binary *pipeline_binary;
159    struct blob blob;
160    size_t data_size;
161    VkResult result;
162    void *data;
163 
164    if (!pipeline_binaries) {
165       (*num_binaries)++;
166       return VK_SUCCESS;
167    }
168 
169    blob_init(&blob);
170    radv_shader_serialize(shader, &blob);
171    blob_finish_get_buffer(&blob, &data, &data_size);
172 
173    result = radv_create_pipeline_binary(device, pAllocator, shader->hash, data, data_size, &pipeline_binary);
174    if (result != VK_SUCCESS) {
175       free(data);
176       return result;
177    }
178 
179    util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary);
180    return result;
181 }
182 
183 VkResult
radv_create_pipeline_binary_from_rt_shader(struct radv_device * device,const VkAllocationCallbacks * pAllocator,struct radv_shader * shader,bool is_traversal_shader,const uint8_t stage_sha1[SHA1_DIGEST_LENGTH],const struct radv_ray_tracing_stage_info * rt_stage_info,uint32_t stack_size,struct vk_pipeline_cache_object * nir,struct util_dynarray * pipeline_binaries,uint32_t * num_binaries)184 radv_create_pipeline_binary_from_rt_shader(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
185                                            struct radv_shader *shader, bool is_traversal_shader,
186                                            const uint8_t stage_sha1[SHA1_DIGEST_LENGTH],
187                                            const struct radv_ray_tracing_stage_info *rt_stage_info, uint32_t stack_size,
188                                            struct vk_pipeline_cache_object *nir,
189                                            struct util_dynarray *pipeline_binaries, uint32_t *num_binaries)
190 {
191    struct radv_pipeline_binary *pipeline_binary;
192    struct mesa_blake3 ctx;
193    struct blob blob;
194    size_t data_size;
195    blake3_hash key;
196    VkResult result;
197    void *data;
198 
199    if (!pipeline_binaries) {
200       (*num_binaries)++;
201       return VK_SUCCESS;
202    }
203 
204    _mesa_blake3_init(&ctx);
205    _mesa_blake3_update(&ctx, stage_sha1, sizeof(*stage_sha1));
206    _mesa_blake3_final(&ctx, key);
207 
208    struct radv_ray_tracing_binary_header header = {
209       .is_traversal_shader = is_traversal_shader,
210       .has_shader = !!shader,
211       .has_nir = !!nir,
212       .stack_size = stack_size,
213    };
214 
215    memcpy(header.stage_sha1, stage_sha1, sizeof(header.stage_sha1));
216    memcpy(&header.stage_info, rt_stage_info, sizeof(header.stage_info));
217 
218    blob_init(&blob);
219    blob_write_bytes(&blob, &header, sizeof(header));
220    if (header.has_shader)
221       radv_shader_serialize(shader, &blob);
222    if (header.has_nir) {
223       struct vk_raw_data_cache_object *nir_object = container_of(nir, struct vk_raw_data_cache_object, base);
224       blob_write_bytes(&blob, nir_object->data, nir_object->data_size);
225    }
226    blob_finish_get_buffer(&blob, &data, &data_size);
227 
228    result = radv_create_pipeline_binary(device, pAllocator, key, data, data_size, &pipeline_binary);
229    if (result != VK_SUCCESS) {
230       free(data);
231       return result;
232    }
233 
234    util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary);
235    return result;
236 }
237 
238 static VkResult
radv_create_pipeline_binary_from_pipeline(struct radv_device * device,const VkAllocationCallbacks * pAllocator,struct radv_pipeline * pipeline,struct util_dynarray * pipeline_binaries,uint32_t * num_binaries)239 radv_create_pipeline_binary_from_pipeline(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
240                                           struct radv_pipeline *pipeline, struct util_dynarray *pipeline_binaries,
241                                           uint32_t *num_binaries)
242 {
243    VkResult result = VK_SUCCESS;
244 
245    if (pipeline->type == RADV_PIPELINE_RAY_TRACING) {
246       struct radv_ray_tracing_pipeline *rt_pipeline = radv_pipeline_to_ray_tracing(pipeline);
247 
248       for (uint32_t i = 0; i < rt_pipeline->non_imported_stage_count; i++) {
249          struct radv_ray_tracing_stage *rt_stage = &rt_pipeline->stages[i];
250 
251          result = radv_create_pipeline_binary_from_rt_shader(device, pAllocator, rt_stage->shader, false,
252                                                              rt_stage->sha1, &rt_stage->info, rt_stage->stack_size,
253                                                              rt_stage->nir, pipeline_binaries, num_binaries);
254          if (result != VK_SUCCESS)
255             return result;
256       }
257 
258       struct radv_shader *traversal_shader = rt_pipeline->base.base.shaders[MESA_SHADER_INTERSECTION];
259       if (traversal_shader) {
260          result = radv_create_pipeline_binary_from_rt_shader(device, pAllocator, traversal_shader, true,
261                                                              traversal_shader->hash, NULL, 0, NULL, pipeline_binaries,
262                                                              num_binaries);
263          if (result != VK_SUCCESS)
264             return result;
265       }
266    } else {
267       for (uint32_t i = 0; i < MESA_VULKAN_SHADER_STAGES; i++) {
268          if (!pipeline->shaders[i])
269             continue;
270 
271          result = radv_create_pipeline_binary_from_shader(device, pAllocator, pipeline->shaders[i], pipeline_binaries,
272                                                           num_binaries);
273          if (result != VK_SUCCESS)
274             return result;
275       }
276 
277       if (pipeline->gs_copy_shader) {
278          result = radv_create_pipeline_binary_from_shader(device, pAllocator, pipeline->gs_copy_shader,
279                                                           pipeline_binaries, num_binaries);
280          if (result != VK_SUCCESS)
281             return result;
282       }
283    }
284 
285    return result;
286 }
287 
288 static VkResult
radv_create_pipeline_binary_from_cache(struct radv_device * device,const VkAllocationCallbacks * pAllocator,const VkPipelineCreateInfoKHR * pPipelineCreateInfo,struct util_dynarray * pipeline_binaries,uint32_t * num_binaries)289 radv_create_pipeline_binary_from_cache(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
290                                        const VkPipelineCreateInfoKHR *pPipelineCreateInfo,
291                                        struct util_dynarray *pipeline_binaries, uint32_t *num_binaries)
292 {
293    unsigned char key[SHA1_DIGEST_LENGTH];
294    bool found_in_internal_cache;
295    VkResult result;
296 
297    assert(pPipelineCreateInfo);
298 
299    result = radv_get_pipeline_key(device, pPipelineCreateInfo, key);
300    if (result != VK_SUCCESS)
301       return result;
302 
303    result = radv_pipeline_cache_get_binaries(device, pAllocator, key, pipeline_binaries, num_binaries,
304                                              &found_in_internal_cache);
305    if (result != VK_SUCCESS)
306       return result;
307 
308    return found_in_internal_cache ? VK_SUCCESS : VK_PIPELINE_BINARY_MISSING_KHR;
309 }
310 
311 static VkResult
radv_create_pipeline_binaries(struct radv_device * device,const VkPipelineBinaryCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,struct util_dynarray * pipeline_binaries,uint32_t * num_binaries)312 radv_create_pipeline_binaries(struct radv_device *device, const VkPipelineBinaryCreateInfoKHR *pCreateInfo,
313                               const VkAllocationCallbacks *pAllocator, struct util_dynarray *pipeline_binaries,
314                               uint32_t *num_binaries)
315 {
316    VkResult result = VK_SUCCESS;
317 
318    if (pCreateInfo->pKeysAndDataInfo) {
319       const VkPipelineBinaryKeysAndDataKHR *pKeysAndDataInfo = pCreateInfo->pKeysAndDataInfo;
320 
321       for (uint32_t i = 0; i < pKeysAndDataInfo->binaryCount; i++) {
322          const VkPipelineBinaryDataKHR *pData = &pKeysAndDataInfo->pPipelineBinaryData[i];
323          const VkPipelineBinaryKeyKHR *pKey = &pKeysAndDataInfo->pPipelineBinaryKeys[i];
324 
325          result =
326             radv_create_pipeline_binary_from_data(device, pAllocator, pData, pKey, pipeline_binaries, num_binaries);
327          if (result != VK_SUCCESS)
328             return result;
329       }
330    } else if (pCreateInfo->pipeline) {
331       VK_FROM_HANDLE(radv_pipeline, pipeline, pCreateInfo->pipeline);
332 
333       result = radv_create_pipeline_binary_from_pipeline(device, pAllocator, pipeline, pipeline_binaries, num_binaries);
334    } else {
335       result = radv_create_pipeline_binary_from_cache(device, pAllocator, pCreateInfo->pPipelineCreateInfo,
336                                                       pipeline_binaries, num_binaries);
337    }
338 
339    return result;
340 }
341 
342 static void
radv_destroy_pipeline_binary(struct radv_device * device,const VkAllocationCallbacks * pAllocator,struct radv_pipeline_binary * pipeline_binary)343 radv_destroy_pipeline_binary(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
344                              struct radv_pipeline_binary *pipeline_binary)
345 {
346    if (!pipeline_binary)
347       return;
348 
349    free(pipeline_binary->data);
350 
351    vk_object_base_finish(&pipeline_binary->base);
352    vk_free2(&device->vk.alloc, pAllocator, pipeline_binary);
353 }
354 
355 VKAPI_ATTR VkResult VKAPI_CALL
radv_CreatePipelineBinariesKHR(VkDevice _device,const VkPipelineBinaryCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineBinaryHandlesInfoKHR * pBinaries)356 radv_CreatePipelineBinariesKHR(VkDevice _device, const VkPipelineBinaryCreateInfoKHR *pCreateInfo,
357                                const VkAllocationCallbacks *pAllocator, VkPipelineBinaryHandlesInfoKHR *pBinaries)
358 {
359    VK_FROM_HANDLE(radv_device, device, _device);
360    struct util_dynarray pipeline_binaries;
361    VkResult result;
362 
363    if (!pBinaries->pPipelineBinaries) {
364       result = radv_create_pipeline_binaries(device, pCreateInfo, pAllocator, NULL, &pBinaries->pipelineBinaryCount);
365       return result;
366    }
367 
368    for (uint32_t i = 0; i < pBinaries->pipelineBinaryCount; i++)
369       pBinaries->pPipelineBinaries[i] = VK_NULL_HANDLE;
370 
371    util_dynarray_init(&pipeline_binaries, NULL);
372 
373    /* Get all pipeline binaries from the pCreateInfo first to simplify the creation. */
374    result = radv_create_pipeline_binaries(device, pCreateInfo, pAllocator, &pipeline_binaries, NULL);
375    if (result != VK_SUCCESS) {
376       util_dynarray_foreach (&pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary)
377          radv_destroy_pipeline_binary(device, pAllocator, *pipeline_binary);
378       util_dynarray_fini(&pipeline_binaries);
379       return result;
380    }
381 
382    const uint32_t num_binaries = util_dynarray_num_elements(&pipeline_binaries, struct radv_pipeline_binary *);
383 
384    for (uint32_t i = 0; i < num_binaries; i++) {
385       struct radv_pipeline_binary **pipeline_binary =
386          util_dynarray_element(&pipeline_binaries, struct radv_pipeline_binary *, i);
387 
388       if (i < pBinaries->pipelineBinaryCount) {
389          pBinaries->pPipelineBinaries[i] = radv_pipeline_binary_to_handle(*pipeline_binary);
390       } else {
391          /* Free the pipeline binary that couldn't be returned. */
392          radv_destroy_pipeline_binary(device, pAllocator, *pipeline_binary);
393       }
394    }
395 
396    result = pBinaries->pipelineBinaryCount < num_binaries ? VK_INCOMPLETE : result;
397    pBinaries->pipelineBinaryCount = MIN2(num_binaries, pBinaries->pipelineBinaryCount);
398 
399    util_dynarray_fini(&pipeline_binaries);
400    return result;
401 }
402 
403 VKAPI_ATTR void VKAPI_CALL
radv_DestroyPipelineBinaryKHR(VkDevice _device,VkPipelineBinaryKHR pipelineBinary,const VkAllocationCallbacks * pAllocator)404 radv_DestroyPipelineBinaryKHR(VkDevice _device, VkPipelineBinaryKHR pipelineBinary,
405                               const VkAllocationCallbacks *pAllocator)
406 {
407    VK_FROM_HANDLE(radv_pipeline_binary, pipeline_binary, pipelineBinary);
408    VK_FROM_HANDLE(radv_device, device, _device);
409 
410    radv_destroy_pipeline_binary(device, pAllocator, pipeline_binary);
411 }
412 
413 VKAPI_ATTR VkResult VKAPI_CALL
radv_GetPipelineBinaryDataKHR(VkDevice _device,const VkPipelineBinaryDataInfoKHR * pInfo,VkPipelineBinaryKeyKHR * pPipelineBinaryKey,size_t * pPipelineBinaryDataSize,void * pPipelineBinaryData)414 radv_GetPipelineBinaryDataKHR(VkDevice _device, const VkPipelineBinaryDataInfoKHR *pInfo,
415                               VkPipelineBinaryKeyKHR *pPipelineBinaryKey, size_t *pPipelineBinaryDataSize,
416                               void *pPipelineBinaryData)
417 {
418    VK_FROM_HANDLE(radv_pipeline_binary, pipeline_binary, pInfo->pipelineBinary);
419    const size_t size = pipeline_binary->size;
420 
421    memcpy(pPipelineBinaryKey->key, pipeline_binary->key, sizeof(pipeline_binary->key));
422    pPipelineBinaryKey->keySize = sizeof(pipeline_binary->key);
423 
424    if (!pPipelineBinaryData) {
425       *pPipelineBinaryDataSize = size;
426       return VK_SUCCESS;
427    }
428 
429    if (*pPipelineBinaryDataSize < size) {
430       *pPipelineBinaryDataSize = size;
431       return VK_ERROR_NOT_ENOUGH_SPACE_KHR;
432    }
433 
434    memcpy(pPipelineBinaryData, pipeline_binary->data, size);
435    *pPipelineBinaryDataSize = size;
436 
437    return VK_SUCCESS;
438 }
439 
440 VKAPI_ATTR VkResult VKAPI_CALL
radv_ReleaseCapturedPipelineDataKHR(VkDevice _device,const VkReleaseCapturedPipelineDataInfoKHR * pInfo,const VkAllocationCallbacks * pAllocator)441 radv_ReleaseCapturedPipelineDataKHR(VkDevice _device, const VkReleaseCapturedPipelineDataInfoKHR *pInfo,
442                                     const VkAllocationCallbacks *pAllocator)
443 {
444    /* no-op */
445    return VK_SUCCESS;
446 }
447