• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    const struct radv_physical_device *pdev = radv_device_physical(device);
79    VkResult result;
80 
81    memset(pPipelineKey->key, 0, sizeof(pPipelineKey->key));
82 
83    /* Return the global key that applies to all pipelines. */
84    if (!pPipelineCreateInfo) {
85       struct mesa_blake3 ctx;
86 
87       static_assert(sizeof(blake3_hash) <= sizeof(pPipelineKey->key), "mismatch pipeline binary key size");
88 
89       _mesa_blake3_init(&ctx);
90       _mesa_blake3_update(&ctx, pdev->cache_uuid, sizeof(pdev->cache_uuid));
91       _mesa_blake3_update(&ctx, device->cache_hash, sizeof(device->cache_hash));
92       _mesa_blake3_final(&ctx, pPipelineKey->key);
93 
94       pPipelineKey->keySize = sizeof(blake3_hash);
95 
96       return VK_SUCCESS;
97    }
98 
99    result = radv_get_pipeline_key(device, pPipelineCreateInfo, pPipelineKey->key);
100    if (result != VK_SUCCESS)
101       return result;
102 
103    pPipelineKey->keySize = SHA1_DIGEST_LENGTH;
104 
105    return VK_SUCCESS;
106 }
107 
108 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)109 radv_create_pipeline_binary(struct radv_device *device, const VkAllocationCallbacks *pAllocator, const blake3_hash key,
110                             const void *data, size_t data_size, struct radv_pipeline_binary **pipeline_binary_out)
111 {
112    struct radv_pipeline_binary *pipeline_binary;
113 
114    pipeline_binary =
115       vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*pipeline_binary), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
116    if (pipeline_binary == NULL)
117       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
118 
119    vk_object_base_init(&device->vk, &pipeline_binary->base, VK_OBJECT_TYPE_PIPELINE_BINARY_KHR);
120 
121    pipeline_binary->data = (void *)data;
122    pipeline_binary->size = data_size;
123 
124    memcpy(pipeline_binary->key, key, BLAKE3_OUT_LEN);
125 
126    *pipeline_binary_out = pipeline_binary;
127    return VK_SUCCESS;
128 }
129 
130 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)131 radv_create_pipeline_binary_from_data(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
132                                       const VkPipelineBinaryDataKHR *pData, const VkPipelineBinaryKeyKHR *pKey,
133                                       struct util_dynarray *pipeline_binaries, uint32_t *num_binaries)
134 {
135    struct radv_pipeline_binary *pipeline_binary;
136    VkResult result;
137    void *data;
138 
139    if (!pipeline_binaries) {
140       (*num_binaries)++;
141       return VK_SUCCESS;
142    }
143 
144    data = malloc(pData->dataSize);
145    if (!data)
146       return VK_ERROR_OUT_OF_HOST_MEMORY;
147 
148    memcpy(data, pData->pData, pData->dataSize);
149 
150    result = radv_create_pipeline_binary(device, pAllocator, pKey->key, data, pData->dataSize, &pipeline_binary);
151    if (result != VK_SUCCESS) {
152       free(data);
153       return result;
154    }
155 
156    util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary);
157    return result;
158 }
159 
160 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)161 radv_create_pipeline_binary_from_shader(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
162                                         struct radv_shader *shader, struct util_dynarray *pipeline_binaries,
163                                         uint32_t *num_binaries)
164 {
165    struct radv_pipeline_binary *pipeline_binary;
166    struct blob blob;
167    size_t data_size;
168    VkResult result;
169    void *data;
170 
171    if (!pipeline_binaries) {
172       (*num_binaries)++;
173       return VK_SUCCESS;
174    }
175 
176    blob_init(&blob);
177    radv_shader_serialize(shader, &blob);
178    blob_finish_get_buffer(&blob, &data, &data_size);
179 
180    result = radv_create_pipeline_binary(device, pAllocator, shader->hash, data, data_size, &pipeline_binary);
181    if (result != VK_SUCCESS) {
182       free(data);
183       return result;
184    }
185 
186    util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary);
187    return result;
188 }
189 
190 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)191 radv_create_pipeline_binary_from_rt_shader(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
192                                            struct radv_shader *shader, bool is_traversal_shader,
193                                            const uint8_t stage_sha1[SHA1_DIGEST_LENGTH],
194                                            const struct radv_ray_tracing_stage_info *rt_stage_info, uint32_t stack_size,
195                                            struct vk_pipeline_cache_object *nir,
196                                            struct util_dynarray *pipeline_binaries, uint32_t *num_binaries)
197 {
198    struct radv_pipeline_binary *pipeline_binary;
199    struct mesa_blake3 ctx;
200    struct blob blob;
201    size_t data_size;
202    blake3_hash key;
203    VkResult result;
204    void *data;
205 
206    if (!pipeline_binaries) {
207       (*num_binaries)++;
208       return VK_SUCCESS;
209    }
210 
211    _mesa_blake3_init(&ctx);
212    _mesa_blake3_update(&ctx, stage_sha1, sizeof(*stage_sha1));
213    _mesa_blake3_final(&ctx, key);
214 
215    struct radv_ray_tracing_binary_header header = {
216       .is_traversal_shader = is_traversal_shader,
217       .has_shader = !!shader,
218       .has_nir = !!nir,
219       .stack_size = stack_size,
220    };
221 
222    memcpy(header.stage_sha1, stage_sha1, sizeof(header.stage_sha1));
223    memcpy(&header.stage_info, rt_stage_info, sizeof(header.stage_info));
224 
225    blob_init(&blob);
226    blob_write_bytes(&blob, &header, sizeof(header));
227    if (header.has_shader)
228       radv_shader_serialize(shader, &blob);
229    if (header.has_nir) {
230       struct vk_raw_data_cache_object *nir_object = container_of(nir, struct vk_raw_data_cache_object, base);
231       blob_write_bytes(&blob, nir_object->data, nir_object->data_size);
232    }
233    blob_finish_get_buffer(&blob, &data, &data_size);
234 
235    result = radv_create_pipeline_binary(device, pAllocator, key, data, data_size, &pipeline_binary);
236    if (result != VK_SUCCESS) {
237       free(data);
238       return result;
239    }
240 
241    util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary);
242    return result;
243 }
244 
245 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)246 radv_create_pipeline_binary_from_pipeline(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
247                                           struct radv_pipeline *pipeline, struct util_dynarray *pipeline_binaries,
248                                           uint32_t *num_binaries)
249 {
250    VkResult result = VK_SUCCESS;
251 
252    if (pipeline->type == RADV_PIPELINE_RAY_TRACING) {
253       struct radv_ray_tracing_pipeline *rt_pipeline = radv_pipeline_to_ray_tracing(pipeline);
254 
255       for (uint32_t i = 0; i < rt_pipeline->non_imported_stage_count; i++) {
256          struct radv_ray_tracing_stage *rt_stage = &rt_pipeline->stages[i];
257 
258          result = radv_create_pipeline_binary_from_rt_shader(device, pAllocator, rt_stage->shader, false,
259                                                              rt_stage->sha1, &rt_stage->info, rt_stage->stack_size,
260                                                              rt_stage->nir, pipeline_binaries, num_binaries);
261          if (result != VK_SUCCESS)
262             return result;
263       }
264 
265       struct radv_shader *traversal_shader = rt_pipeline->base.base.shaders[MESA_SHADER_INTERSECTION];
266       if (traversal_shader) {
267          result = radv_create_pipeline_binary_from_rt_shader(device, pAllocator, traversal_shader, true,
268                                                              traversal_shader->hash, NULL, 0, NULL, pipeline_binaries,
269                                                              num_binaries);
270          if (result != VK_SUCCESS)
271             return result;
272       }
273    } else {
274       for (uint32_t i = 0; i < MESA_VULKAN_SHADER_STAGES; i++) {
275          if (!pipeline->shaders[i])
276             continue;
277 
278          result = radv_create_pipeline_binary_from_shader(device, pAllocator, pipeline->shaders[i], pipeline_binaries,
279                                                           num_binaries);
280          if (result != VK_SUCCESS)
281             return result;
282       }
283 
284       if (pipeline->gs_copy_shader) {
285          result = radv_create_pipeline_binary_from_shader(device, pAllocator, pipeline->gs_copy_shader,
286                                                           pipeline_binaries, num_binaries);
287          if (result != VK_SUCCESS)
288             return result;
289       }
290    }
291 
292    return result;
293 }
294 
295 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)296 radv_create_pipeline_binary_from_cache(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
297                                        const VkPipelineCreateInfoKHR *pPipelineCreateInfo,
298                                        struct util_dynarray *pipeline_binaries, uint32_t *num_binaries)
299 {
300    unsigned char key[SHA1_DIGEST_LENGTH];
301    bool found_in_internal_cache;
302    VkResult result;
303 
304    assert(pPipelineCreateInfo);
305 
306    result = radv_get_pipeline_key(device, pPipelineCreateInfo, key);
307    if (result != VK_SUCCESS)
308       return result;
309 
310    result = radv_pipeline_cache_get_binaries(device, pAllocator, key, pipeline_binaries, num_binaries,
311                                              &found_in_internal_cache);
312    if (result != VK_SUCCESS)
313       return result;
314 
315    return found_in_internal_cache ? VK_SUCCESS : VK_PIPELINE_BINARY_MISSING_KHR;
316 }
317 
318 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)319 radv_create_pipeline_binaries(struct radv_device *device, const VkPipelineBinaryCreateInfoKHR *pCreateInfo,
320                               const VkAllocationCallbacks *pAllocator, struct util_dynarray *pipeline_binaries,
321                               uint32_t *num_binaries)
322 {
323    VkResult result = VK_SUCCESS;
324 
325    if (pCreateInfo->pKeysAndDataInfo) {
326       const VkPipelineBinaryKeysAndDataKHR *pKeysAndDataInfo = pCreateInfo->pKeysAndDataInfo;
327 
328       for (uint32_t i = 0; i < pKeysAndDataInfo->binaryCount; i++) {
329          const VkPipelineBinaryDataKHR *pData = &pKeysAndDataInfo->pPipelineBinaryData[i];
330          const VkPipelineBinaryKeyKHR *pKey = &pKeysAndDataInfo->pPipelineBinaryKeys[i];
331 
332          result =
333             radv_create_pipeline_binary_from_data(device, pAllocator, pData, pKey, pipeline_binaries, num_binaries);
334          if (result != VK_SUCCESS)
335             return result;
336       }
337    } else if (pCreateInfo->pipeline) {
338       VK_FROM_HANDLE(radv_pipeline, pipeline, pCreateInfo->pipeline);
339 
340       result = radv_create_pipeline_binary_from_pipeline(device, pAllocator, pipeline, pipeline_binaries, num_binaries);
341    } else {
342       result = radv_create_pipeline_binary_from_cache(device, pAllocator, pCreateInfo->pPipelineCreateInfo,
343                                                       pipeline_binaries, num_binaries);
344    }
345 
346    return result;
347 }
348 
349 static void
radv_destroy_pipeline_binary(struct radv_device * device,const VkAllocationCallbacks * pAllocator,struct radv_pipeline_binary * pipeline_binary)350 radv_destroy_pipeline_binary(struct radv_device *device, const VkAllocationCallbacks *pAllocator,
351                              struct radv_pipeline_binary *pipeline_binary)
352 {
353    if (!pipeline_binary)
354       return;
355 
356    free(pipeline_binary->data);
357 
358    vk_object_base_finish(&pipeline_binary->base);
359    vk_free2(&device->vk.alloc, pAllocator, pipeline_binary);
360 }
361 
362 VKAPI_ATTR VkResult VKAPI_CALL
radv_CreatePipelineBinariesKHR(VkDevice _device,const VkPipelineBinaryCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineBinaryHandlesInfoKHR * pBinaries)363 radv_CreatePipelineBinariesKHR(VkDevice _device, const VkPipelineBinaryCreateInfoKHR *pCreateInfo,
364                                const VkAllocationCallbacks *pAllocator, VkPipelineBinaryHandlesInfoKHR *pBinaries)
365 {
366    VK_FROM_HANDLE(radv_device, device, _device);
367    struct util_dynarray pipeline_binaries;
368    VkResult result;
369 
370    if (!pBinaries->pPipelineBinaries) {
371       result = radv_create_pipeline_binaries(device, pCreateInfo, pAllocator, NULL, &pBinaries->pipelineBinaryCount);
372       return result;
373    }
374 
375    for (uint32_t i = 0; i < pBinaries->pipelineBinaryCount; i++)
376       pBinaries->pPipelineBinaries[i] = VK_NULL_HANDLE;
377 
378    util_dynarray_init(&pipeline_binaries, NULL);
379 
380    /* Get all pipeline binaries from the pCreateInfo first to simplify the creation. */
381    result = radv_create_pipeline_binaries(device, pCreateInfo, pAllocator, &pipeline_binaries, NULL);
382    if (result != VK_SUCCESS) {
383       util_dynarray_foreach (&pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary)
384          radv_destroy_pipeline_binary(device, pAllocator, *pipeline_binary);
385       util_dynarray_fini(&pipeline_binaries);
386       return result;
387    }
388 
389    const uint32_t num_binaries = util_dynarray_num_elements(&pipeline_binaries, struct radv_pipeline_binary *);
390 
391    for (uint32_t i = 0; i < num_binaries; i++) {
392       struct radv_pipeline_binary **pipeline_binary =
393          util_dynarray_element(&pipeline_binaries, struct radv_pipeline_binary *, i);
394 
395       if (i < pBinaries->pipelineBinaryCount) {
396          pBinaries->pPipelineBinaries[i] = radv_pipeline_binary_to_handle(*pipeline_binary);
397       } else {
398          /* Free the pipeline binary that couldn't be returned. */
399          radv_destroy_pipeline_binary(device, pAllocator, *pipeline_binary);
400       }
401    }
402 
403    result = pBinaries->pipelineBinaryCount < num_binaries ? VK_INCOMPLETE : result;
404    pBinaries->pipelineBinaryCount = MIN2(num_binaries, pBinaries->pipelineBinaryCount);
405 
406    util_dynarray_fini(&pipeline_binaries);
407    return result;
408 }
409 
410 VKAPI_ATTR void VKAPI_CALL
radv_DestroyPipelineBinaryKHR(VkDevice _device,VkPipelineBinaryKHR pipelineBinary,const VkAllocationCallbacks * pAllocator)411 radv_DestroyPipelineBinaryKHR(VkDevice _device, VkPipelineBinaryKHR pipelineBinary,
412                               const VkAllocationCallbacks *pAllocator)
413 {
414    VK_FROM_HANDLE(radv_pipeline_binary, pipeline_binary, pipelineBinary);
415    VK_FROM_HANDLE(radv_device, device, _device);
416 
417    radv_destroy_pipeline_binary(device, pAllocator, pipeline_binary);
418 }
419 
420 VKAPI_ATTR VkResult VKAPI_CALL
radv_GetPipelineBinaryDataKHR(VkDevice _device,const VkPipelineBinaryDataInfoKHR * pInfo,VkPipelineBinaryKeyKHR * pPipelineBinaryKey,size_t * pPipelineBinaryDataSize,void * pPipelineBinaryData)421 radv_GetPipelineBinaryDataKHR(VkDevice _device, const VkPipelineBinaryDataInfoKHR *pInfo,
422                               VkPipelineBinaryKeyKHR *pPipelineBinaryKey, size_t *pPipelineBinaryDataSize,
423                               void *pPipelineBinaryData)
424 {
425    VK_FROM_HANDLE(radv_pipeline_binary, pipeline_binary, pInfo->pipelineBinary);
426    const size_t size = pipeline_binary->size;
427 
428    memcpy(pPipelineBinaryKey->key, pipeline_binary->key, sizeof(pipeline_binary->key));
429    pPipelineBinaryKey->keySize = sizeof(pipeline_binary->key);
430 
431    if (!pPipelineBinaryData) {
432       *pPipelineBinaryDataSize = size;
433       return VK_SUCCESS;
434    }
435 
436    if (*pPipelineBinaryDataSize < size) {
437       *pPipelineBinaryDataSize = size;
438       return VK_ERROR_NOT_ENOUGH_SPACE_KHR;
439    }
440 
441    memcpy(pPipelineBinaryData, pipeline_binary->data, size);
442    *pPipelineBinaryDataSize = size;
443 
444    return VK_SUCCESS;
445 }
446 
447 VKAPI_ATTR VkResult VKAPI_CALL
radv_ReleaseCapturedPipelineDataKHR(VkDevice _device,const VkReleaseCapturedPipelineDataInfoKHR * pInfo,const VkAllocationCallbacks * pAllocator)448 radv_ReleaseCapturedPipelineDataKHR(VkDevice _device, const VkReleaseCapturedPipelineDataInfoKHR *pInfo,
449                                     const VkAllocationCallbacks *pAllocator)
450 {
451    /* no-op */
452    return VK_SUCCESS;
453 }
454