diff options
| author | Lionel Landwerlin <lionel.g.landwerlin@intel.com> | 2025-08-07 16:29:49 +0300 |
|---|---|---|
| committer | Marge Bot <marge-bot@fdo.invalid> | 2025-11-06 15:27:28 +0000 |
| commit | 5c47ac640b21c40c30f29600997a9337ba399916 (patch) | |
| tree | 77e81a9afb04652722aeaa40b64d6f8ea6080763 | |
| parent | 2e42e03cec150ad6968fed602c23cf8c1c8f04b3 (diff) | |
vulkan/runtime: implement VK_KHR_pipeline_binary
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Co-Authored-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36647>
| -rw-r--r-- | src/vulkan/runtime/vk_pipeline.c | 1040 |
1 files changed, 905 insertions, 135 deletions
diff --git a/src/vulkan/runtime/vk_pipeline.c b/src/vulkan/runtime/vk_pipeline.c index 06f9b3f35d9..63eb6b0333e 100644 --- a/src/vulkan/runtime/vk_pipeline.c +++ b/src/vulkan/runtime/vk_pipeline.c @@ -45,6 +45,22 @@ #include "util/mesa-sha1.h" +struct vk_pipeline_binary { + struct vk_object_base base; + + blake3_hash key; + + size_t size; + + /* The first byte is boolean of whether the binary is precomp or not, + * following by the serialized data. + */ + uint8_t data[]; +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_pipeline_binary, base, VkPipelineBinaryKHR, + VK_OBJECT_TYPE_PIPELINE_BINARY_KHR); + bool vk_pipeline_shader_stage_is_null(const VkPipelineShaderStageCreateInfo *info) { @@ -533,11 +549,10 @@ vk_shader_init_cache_obj(struct vk_device *device, struct vk_shader *shader, } static struct vk_pipeline_cache_object * -vk_pipeline_shader_deserialize(struct vk_pipeline_cache *cache, +vk_pipeline_shader_deserialize(struct vk_device *device, const void *key_data, size_t key_size, struct blob_reader *blob) { - struct vk_device *device = cache->base.device; const struct vk_device_shader_ops *ops = device->shader_ops; /* TODO: Do we really want to always use the latest version? */ @@ -556,6 +571,15 @@ vk_pipeline_shader_deserialize(struct vk_pipeline_cache *cache, return &shader->pipeline.cache_obj; } +static struct vk_pipeline_cache_object * +vk_pipeline_shader_deserialize_cb(struct vk_pipeline_cache *cache, + const void *key_data, size_t key_size, + struct blob_reader *blob) +{ + return vk_pipeline_shader_deserialize(cache->base.device, + key_data, key_size, blob); +} + static void vk_pipeline_shader_destroy(struct vk_device *device, struct vk_pipeline_cache_object *object) @@ -568,7 +592,7 @@ vk_pipeline_shader_destroy(struct vk_device *device, static const struct vk_pipeline_cache_object_ops pipeline_shader_cache_ops = { .serialize = vk_pipeline_shader_serialize, - .deserialize = vk_pipeline_shader_deserialize, + .deserialize = vk_pipeline_shader_deserialize_cb, .destroy = vk_pipeline_shader_destroy, }; @@ -761,12 +785,10 @@ vk_pipeline_precomp_shader_serialize(struct vk_pipeline_cache_object *obj, } static struct vk_pipeline_cache_object * -vk_pipeline_precomp_shader_deserialize(struct vk_pipeline_cache *cache, +vk_pipeline_precomp_shader_deserialize(struct vk_device *device, const void *key_data, size_t key_size, struct blob_reader *blob) { - struct vk_device *device = cache->base.device; - struct vk_pipeline_precomp_shader *shader = vk_zalloc(&device->alloc, sizeof(*shader), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); @@ -809,6 +831,15 @@ fail_shader: return NULL; } +static struct vk_pipeline_cache_object * +vk_pipeline_precomp_shader_deserialize_cb(struct vk_pipeline_cache *cache, + const void *key_data, size_t key_size, + struct blob_reader *blob) +{ + return vk_pipeline_precomp_shader_deserialize(cache->base.device, + key_data, key_size, blob); +} + static void vk_pipeline_precomp_shader_destroy(struct vk_device *device, struct vk_pipeline_cache_object *obj) @@ -839,7 +870,7 @@ vk_pipeline_precomp_shader_get_nir(const struct vk_pipeline_precomp_shader *shad static const struct vk_pipeline_cache_object_ops pipeline_precomp_shader_cache_ops = { .serialize = vk_pipeline_precomp_shader_serialize, - .deserialize = vk_pipeline_precomp_shader_deserialize, + .deserialize = vk_pipeline_precomp_shader_deserialize_cb, .destroy = vk_pipeline_precomp_shader_destroy, }; @@ -942,6 +973,63 @@ vk_pipeline_precompile_shader(struct vk_device *device, return VK_SUCCESS; } +static VkResult +vk_pipeline_load_precomp_from_binary(struct vk_device *device, + struct vk_pipeline_stage *stage, + struct vk_pipeline_binary *binary) +{ + struct vk_pipeline_cache_object *cache_obj; + if (device->mem_cache) { + cache_obj = vk_pipeline_cache_create_and_insert_object( + device->mem_cache, + binary->key, sizeof(binary->key), + binary->data, binary->size, + &pipeline_precomp_shader_cache_ops); + } else { + struct blob_reader reader; + blob_reader_init(&reader, binary->data, binary->size); + cache_obj = vk_pipeline_precomp_shader_deserialize( + device, binary->key, sizeof(binary->key), &reader); + } + + if (cache_obj == NULL) + return vk_error(device, VK_ERROR_UNKNOWN); + + stage->precomp = vk_pipeline_precomp_shader_from_cache_obj(cache_obj); + memcpy(stage->precomp_key, stage->precomp->cache_key, + sizeof(stage->precomp_key)); + + return VK_SUCCESS; +} + +static VkResult +vk_pipeline_load_shader_from_binary(struct vk_device *device, + struct vk_pipeline_stage *stage, + struct vk_pipeline_binary *binary) +{ + struct vk_pipeline_cache_object *cache_obj; + if (device->mem_cache) { + cache_obj = vk_pipeline_cache_create_and_insert_object( + device->mem_cache, + binary->key, sizeof(binary->key), + binary->data, binary->size, + &pipeline_shader_cache_ops); + } else { + struct blob_reader reader; + blob_reader_init(&reader, binary->data, binary->size); + cache_obj = vk_pipeline_shader_deserialize( + device, binary->key, sizeof(binary->key), &reader); + } + if (cache_obj == NULL) + return vk_error(device, VK_ERROR_UNKNOWN); + + stage->shader = vk_shader_from_cache_obj(cache_obj); + memcpy(stage->shader_key, stage->shader->pipeline.cache_key, + sizeof(stage->shader_key)); + + return VK_SUCCESS; +} + static int cmp_vk_pipeline_stages(const void *_a, const void *_b) { @@ -1169,6 +1257,7 @@ struct vk_graphics_pipeline_compile_info { struct vk_graphics_pipeline_state *state; + bool retain_precomp; bool optimize; uint32_t part_count; @@ -1196,6 +1285,14 @@ vk_get_graphics_pipeline_compile_info(struct vk_graphics_pipeline_compile_info * const VkPipelineCreateFlags2KHR pipeline_flags = vk_graphics_pipeline_create_flags(pCreateInfo); + info->retain_precomp = + (pipeline_flags & + VK_PIPELINE_CREATE_2_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT) != 0; + + const VkPipelineBinaryInfoKHR *bin_info = + vk_find_struct_const(pCreateInfo->pNext, + PIPELINE_BINARY_INFO_KHR); + const VkPipelineLibraryCreateInfoKHR *libs_info = vk_find_struct_const(pCreateInfo->pNext, PIPELINE_LIBRARY_CREATE_INFO_KHR); @@ -1285,6 +1382,17 @@ vk_get_graphics_pipeline_compile_info(struct vk_graphics_pipeline_compile_info * }; all_stages |= stage_info->stage; + /* + * "If a VkPipelineBinaryInfoKHR structure with a binaryCount greater + * than 0 is included in the pNext chain of any Vk*PipelineCreateInfo + * structure when creating a pipeline, implementations must use the + * data in pPipelineBinaries instead of recalculating it. Any shader + * module identifiers or shader modules declared in + * VkPipelineShaderStageCreateInfo instances are ignored." + */ + if (bin_info != NULL && bin_info->binaryCount > 0) + continue; + vk_pipeline_hash_precomp_shader_stage(device, pipeline_flags, pCreateInfo->pNext, stage_info, &info->stages[stage]); @@ -1864,6 +1972,10 @@ vk_create_graphics_pipeline(struct vk_device *device, const VkPipelineCreateFlags2KHR pipeline_flags = vk_graphics_pipeline_create_flags(pCreateInfo); + const VkPipelineBinaryInfoKHR *bin_info = + vk_find_struct_const(pCreateInfo->pNext, + PIPELINE_BINARY_INFO_KHR); + const VkPipelineCreationFeedbackCreateInfo *feedback_info = vk_find_struct_const(pCreateInfo->pNext, PIPELINE_CREATION_FEEDBACK_CREATE_INFO); @@ -1900,49 +2012,94 @@ vk_create_graphics_pipeline(struct vk_device *device, vk_dynamic_graphics_state_fill(&pipeline->linked.dynamic, &state_tmp); } - for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { - const VkPipelineShaderStageCreateInfo *stage_info = - &pCreateInfo->pStages[i]; + if (bin_info != NULL && bin_info->binaryCount > 0) { + const uint32_t expected_binary_count = compile_info.retain_precomp ? + (2 * pCreateInfo->stageCount) : pCreateInfo->stageCount; - const int64_t stage_start = os_time_get_nano(); + if (bin_info->binaryCount < expected_binary_count) { + result = vk_error(device, VK_ERROR_UNKNOWN); + } else { + uint32_t binary_index = 0; + for (uint32_t i = 0; i < compile_info.stage_count; i++) { + if (compile_info.stages[i].imported) + continue; - assert(util_bitcount(stage_info->stage) == 1); + const int64_t stage_start = os_time_get_nano(); - /* We don't need to load anything for imported stages, precomp should be - * included if - * VK_PIPELINE_CREATE_2_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT was - * provided and shader should obviously be there. - */ - mesa_shader_stage stage = vk_to_mesa_shader_stage(stage_info->stage); + mesa_shader_stage stage = compile_info.stages[i].stage; - if (compile_info.stages[compile_info.stage_to_index[stage]].imported) - continue; + if (compile_info.retain_precomp) { + VK_FROM_HANDLE(vk_pipeline_binary, binary, + bin_info->pPipelineBinaries[binary_index++]); - stage_feedbacks[stage].flags |= - VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT; + result = vk_pipeline_load_precomp_from_binary( + device, &compile_info.stages[i], binary); + if (result != VK_SUCCESS) + goto fail_stages; + } - stage_feedbacks[stage].flags |= VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT; + VK_FROM_HANDLE(vk_pipeline_binary, binary, + bin_info->pPipelineBinaries[binary_index++]); + result = vk_pipeline_load_shader_from_binary( + device, &compile_info.stages[i], binary); + if (result != VK_SUCCESS) + goto fail_stages; - struct vk_pipeline_stage *pipeline_stage = - &compile_info.stages[compile_info.stage_to_index[stage]]; - result = vk_pipeline_precompile_shader(device, cache, pipeline_flags, - pCreateInfo->pNext, - stage_info, pipeline_stage); + + stage_feedbacks[stage].flags |= + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT; + + stage_feedbacks[stage].flags |= VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT; + + const int64_t stage_end = os_time_get_nano(); + stage_feedbacks[stage].duration += stage_end - stage_start; + } + } + } else { + for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { + const VkPipelineShaderStageCreateInfo *stage_info = + &pCreateInfo->pStages[i]; + + const int64_t stage_start = os_time_get_nano(); + + assert(util_bitcount(stage_info->stage) == 1); + + mesa_shader_stage stage = vk_to_mesa_shader_stage(stage_info->stage); + + /* We don't need to load anything for imported stages, precomp should be + * included if + * VK_PIPELINE_CREATE_2_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT was + * provided and shader should obviously be there. + */ + if (compile_info.stages[compile_info.stage_to_index[stage]].imported) + continue; + + stage_feedbacks[stage].flags |= + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT; + + stage_feedbacks[stage].flags |= VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT; + + struct vk_pipeline_stage *pipeline_stage = + &compile_info.stages[compile_info.stage_to_index[stage]]; + result = vk_pipeline_precompile_shader(device, cache, pipeline_flags, + pCreateInfo->pNext, + stage_info, pipeline_stage); + if (result != VK_SUCCESS) + goto fail_stages; + + const int64_t stage_end = os_time_get_nano(); + stage_feedbacks[stage].duration += stage_end - stage_start; + } + + result = vk_graphics_pipeline_compile_shaders(device, cache, + pipeline_flags, + pipeline_layout, + &compile_info, + stage_feedbacks); if (result != VK_SUCCESS) goto fail_stages; - - const int64_t stage_end = os_time_get_nano(); - stage_feedbacks[stage].duration += stage_end - stage_start; } - result = vk_graphics_pipeline_compile_shaders(device, cache, - pipeline_flags, - pipeline_layout, - &compile_info, - stage_feedbacks); - if (result != VK_SUCCESS) - goto fail_stages; - /* Keep a reference on the set layouts */ pipeline->set_layout_count = compile_info.set_layout_count; for (uint32_t i = 0; i < compile_info.set_layout_count; i++) { @@ -1962,8 +2119,7 @@ vk_create_graphics_pipeline(struct vk_device *device, /* Throw away precompiled shaders unless the client explicitly asks us to * keep them. */ - if (!(pipeline_flags & - VK_PIPELINE_CREATE_2_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT)) { + if (!compile_info.retain_precomp) { for (uint32_t i = 0; i < compile_info.stage_count; i++) { if (pipeline->stages[i].precomp != NULL) { vk_pipeline_precomp_shader_unref(device, pipeline->stages[i].precomp); @@ -2133,45 +2289,62 @@ vk_get_compute_pipeline_compile_info(struct vk_pipeline_stage *stage, *stage = (struct vk_pipeline_stage) { .stage = MESA_SHADER_COMPUTE, }; - const VkPushConstantRange *push_range = - get_push_range_for_stage(pipeline_layout, MESA_SHADER_COMPUTE); + const VkPipelineBinaryInfoKHR *bin_info = + vk_find_struct_const(pCreateInfo->pNext, + PIPELINE_BINARY_INFO_KHR); + + /* + * "If a VkPipelineBinaryInfoKHR structure with a binaryCount greater + * than 0 is included in the pNext chain of any Vk*PipelineCreateInfo + * structure when creating a pipeline, implementations must use the + * data in pPipelineBinaries instead of recalculating it. Any shader + * module identifiers or shader modules declared in + * VkPipelineShaderStageCreateInfo instances are ignored." + * + * There is no point in computing a precomp/shader hash at this point, + * since we don't have any information. + */ + if (bin_info == NULL || bin_info->binaryCount == 0) { + const VkPushConstantRange *push_range = + get_push_range_for_stage(pipeline_layout, MESA_SHADER_COMPUTE); - const VkPipelineCreateFlags2KHR pipeline_flags = - vk_compute_pipeline_create_flags(pCreateInfo); + const VkPipelineCreateFlags2KHR pipeline_flags = + vk_compute_pipeline_create_flags(pCreateInfo); - const VkShaderCreateFlagsEXT shader_flags = - vk_pipeline_to_shader_flags(pipeline_flags, MESA_SHADER_COMPUTE); + const VkShaderCreateFlagsEXT shader_flags = + vk_pipeline_to_shader_flags(pipeline_flags, MESA_SHADER_COMPUTE); - vk_pipeline_hash_precomp_shader_stage(device, pipeline_flags, pCreateInfo->pNext, - &pCreateInfo->stage, stage); + vk_pipeline_hash_precomp_shader_stage(device, pipeline_flags, pCreateInfo->pNext, + &pCreateInfo->stage, stage); - struct mesa_blake3 blake3_ctx; - _mesa_blake3_init(&blake3_ctx); + struct mesa_blake3 blake3_ctx; + _mesa_blake3_init(&blake3_ctx); - _mesa_blake3_update(&blake3_ctx, &stage->stage, sizeof(stage->stage)); + _mesa_blake3_update(&blake3_ctx, &stage->stage, sizeof(stage->stage)); - _mesa_blake3_update(&blake3_ctx, stage->precomp_key, - sizeof(stage->precomp_key)); + _mesa_blake3_update(&blake3_ctx, stage->precomp_key, + sizeof(stage->precomp_key)); - _mesa_blake3_update(&blake3_ctx, &shader_flags, sizeof(shader_flags)); + _mesa_blake3_update(&blake3_ctx, &shader_flags, sizeof(shader_flags)); - blake3_hash features_blake3; - ops->hash_state(device->physical, NULL /* state */, - &device->enabled_features, VK_SHADER_STAGE_COMPUTE_BIT, - features_blake3); - _mesa_blake3_update(&blake3_ctx, features_blake3, sizeof(features_blake3)); + blake3_hash features_blake3; + ops->hash_state(device->physical, NULL /* state */, + &device->enabled_features, VK_SHADER_STAGE_COMPUTE_BIT, + features_blake3); + _mesa_blake3_update(&blake3_ctx, features_blake3, sizeof(features_blake3)); - for (uint32_t i = 0; i < pipeline_layout->set_count; i++) { - if (pipeline_layout->set_layouts[i] != NULL) { - _mesa_blake3_update(&blake3_ctx, - pipeline_layout->set_layouts[i]->blake3, - sizeof(pipeline_layout->set_layouts[i]->blake3)); + for (uint32_t i = 0; i < pipeline_layout->set_count; i++) { + if (pipeline_layout->set_layouts[i] != NULL) { + _mesa_blake3_update(&blake3_ctx, + pipeline_layout->set_layouts[i]->blake3, + sizeof(pipeline_layout->set_layouts[i]->blake3)); + } } - } - if (push_range != NULL) - _mesa_blake3_update(&blake3_ctx, push_range, sizeof(*push_range)); + if (push_range != NULL) + _mesa_blake3_update(&blake3_ctx, push_range, sizeof(*push_range)); - _mesa_blake3_final(&blake3_ctx, stage->shader_key); + _mesa_blake3_final(&blake3_ctx, stage->shader_key); + } } static VkResult @@ -2338,6 +2511,10 @@ vk_create_compute_pipeline(struct vk_device *device, const VkPipelineCreateFlags2KHR pipeline_flags = vk_compute_pipeline_create_flags(pCreateInfo); + const VkPipelineBinaryInfoKHR *bin_info = + vk_find_struct_const(pCreateInfo->pNext, + PIPELINE_BINARY_INFO_KHR); + const VkPipelineCreationFeedbackCreateInfo *feedback_info = vk_find_struct_const(pCreateInfo->pNext, PIPELINE_CREATION_FEEDBACK_CREATE_INFO); @@ -2353,19 +2530,28 @@ vk_create_compute_pipeline(struct vk_device *device, pipeline->base.stages = VK_SHADER_STAGE_COMPUTE_BIT; - result = vk_pipeline_precompile_shader(device, cache, pipeline_flags, - pCreateInfo->pNext, - &pCreateInfo->stage, - &stage); - if (result != VK_SUCCESS) - goto fail_pipeline; - bool cache_hit; - result = vk_pipeline_compile_compute_stage(device, cache, pipeline, - pipeline_layout, &stage, - &cache_hit); - if (result != VK_SUCCESS) - goto fail_pipeline; + if (bin_info != NULL && bin_info->binaryCount > 0) { + VK_FROM_HANDLE(vk_pipeline_binary, binary, + bin_info->pPipelineBinaries[0]); + + result = vk_pipeline_load_shader_from_binary(device, &stage, binary); + if (result != VK_SUCCESS) + goto fail_pipeline; + } else { + result = vk_pipeline_precompile_shader(device, cache, pipeline_flags, + pCreateInfo->pNext, + &pCreateInfo->stage, + &stage); + if (result != VK_SUCCESS) + goto fail_pipeline; + + result = vk_pipeline_compile_compute_stage(device, cache, pipeline, + pipeline_layout, &stage, + &cache_hit); + if (result != VK_SUCCESS) + goto fail_pipeline; + } pipeline->stage = vk_pipeline_stage_clone(&stage); @@ -2468,6 +2654,7 @@ vk_cmd_unbind_pipelines_for_stages(struct vk_command_buffer *cmd_buffer, struct vk_rt_stage { bool linked : 1; + bool imported : 1; struct vk_shader *shader; }; @@ -2633,6 +2820,7 @@ vk_pipeline_hash_rt_shader(struct vk_device *device, static void vk_pipeline_rehash_rt_linked_shaders(struct vk_device *device, VkPipelineCreateFlags2KHR pipeline_flags, + const VkPipelineBinaryInfoKHR *bin_info, struct vk_pipeline_layout *pipeline_layout, struct vk_pipeline_stage *stages, uint32_t stage_count, @@ -2650,31 +2838,35 @@ vk_pipeline_rehash_rt_linked_shaders(struct vk_device *device, if (!(mesa_to_vk_shader_stage(stages[i].stage) & linked_stages)) continue; - struct mesa_blake3 blake3_ctx; - _mesa_blake3_init(&blake3_ctx); + stages[i].linked = true; - assert(mesa_shader_stage_is_rt(stages[i].stage)); - _mesa_blake3_update(&blake3_ctx, &stages[i].stage, - sizeof(stages[i].stage)); + if (bin_info == NULL || bin_info->binaryCount == 0) { + struct mesa_blake3 blake3_ctx; + _mesa_blake3_init(&blake3_ctx); - const VkPushConstantRange *push_range = - get_push_range_for_stage(pipeline_layout, stages[i].stage); + assert(mesa_shader_stage_is_rt(stages[i].stage)); + _mesa_blake3_update(&blake3_ctx, &stages[i].stage, + sizeof(stages[i].stage)); - VkShaderCreateFlagsEXT shader_flags = - vk_pipeline_to_shader_flags(pipeline_flags, stages[i].stage); + const VkPushConstantRange *push_range = + get_push_range_for_stage(pipeline_layout, stages[i].stage); + + VkShaderCreateFlagsEXT shader_flags = + vk_pipeline_to_shader_flags(pipeline_flags, stages[i].stage); - hash_rt_parameters(&blake3_ctx, shader_flags, pipeline_flags, - push_range, pipeline_layout); + hash_rt_parameters(&blake3_ctx, shader_flags, pipeline_flags, + push_range, pipeline_layout); - /* Tie the shader to all the other shaders we're linking with */ - for (uint32_t j = 0; j < stage_count; j++) { - if (mesa_to_vk_shader_stage(stages[j].stage) & linked_stages) { - _mesa_blake3_update(&blake3_ctx, stages[j].precomp_key, - sizeof(stages[j].precomp_key)); + /* Tie the shader to all the other shaders we're linking with */ + for (uint32_t j = 0; j < stage_count; j++) { + if (mesa_to_vk_shader_stage(stages[j].stage) & linked_stages) { + _mesa_blake3_update(&blake3_ctx, stages[j].precomp_key, + sizeof(stages[j].precomp_key)); + } } - } - _mesa_blake3_final(&blake3_ctx, stages[i].shader_key); + _mesa_blake3_final(&blake3_ctx, stages[i].shader_key); + } } } @@ -2722,6 +2914,7 @@ vk_pipeline_stage_from_rt_stage(struct vk_rt_stage *stage) .stage = stage->shader->stage, .shader = vk_shader_ref(stage->shader), .linked = stage->linked, + .imported = true, /* precomp & precomp_key left empty on purpose */ }; assert(sizeof(ret.shader_key) == @@ -2745,6 +2938,7 @@ vk_rt_shader_group_from_compile_info(struct vk_rt_group_compile_info *group_info assert(group_info->stages[i].shader != NULL); group.stages[i] = (struct vk_rt_stage) { + .imported = true, .linked = group_info->stages[i].linked, .shader = vk_shader_ref(group_info->stages[i].shader), }; @@ -2798,6 +2992,10 @@ vk_get_rt_pipeline_compile_info(struct vk_rt_pipeline_compile_info *info, const VkPipelineCreateFlags2KHR pipeline_flags = vk_rt_pipeline_create_flags(pCreateInfo); + const VkPipelineBinaryInfoKHR *bin_info = + vk_find_struct_const(pCreateInfo->pNext, + PIPELINE_BINARY_INFO_KHR); + for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { const VkPipelineShaderStageCreateInfo *stage_info = &pCreateInfo->pStages[i]; @@ -2806,12 +3004,14 @@ vk_get_rt_pipeline_compile_info(struct vk_rt_pipeline_compile_info *info, .stage = vk_to_mesa_shader_stage(stage_info->stage), }; - vk_pipeline_hash_precomp_shader_stage(device, pipeline_flags, - pCreateInfo->pNext, stage_info, - &info->stages[i]); + if (bin_info == NULL || bin_info->binaryCount == 0) { + vk_pipeline_hash_precomp_shader_stage(device, pipeline_flags, + pCreateInfo->pNext, stage_info, + &info->stages[i]); - vk_pipeline_hash_rt_shader(device, pipeline_flags, pipeline_layout, - &info->stages[i]); + vk_pipeline_hash_rt_shader(device, pipeline_flags, pipeline_layout, + &info->stages[i]); + } } for (uint32_t i = 0; i < pCreateInfo->groupCount; i++) { @@ -2848,8 +3048,8 @@ vk_get_rt_pipeline_compile_info(struct vk_rt_pipeline_compile_info *info, VkShaderStageFlags group_all_stages = 0; for (uint32_t s = 0; s < group->stage_count; s++) { - group->stages[s] = - vk_pipeline_stage_clone(&info->stages[group->stage_indices[s]]); + group->stages[s] = vk_pipeline_stage_clone( + &info->stages[group->stage_indices[s]]); group_all_stages |= mesa_to_vk_shader_stage(group->stages[s].stage); } @@ -2858,7 +3058,7 @@ vk_get_rt_pipeline_compile_info(struct vk_rt_pipeline_compile_info *info, ops->get_rt_group_linking(device->physical, group_all_stages) : 0; /* Compute shader hashes for the linked stages */ - vk_pipeline_rehash_rt_linked_shaders(device, pipeline_flags, + vk_pipeline_rehash_rt_linked_shaders(device, pipeline_flags, bin_info, pipeline_layout, group->stages, group->stage_count, group_linked_stages); @@ -3266,6 +3466,10 @@ vk_create_rt_pipeline(struct vk_device *device, const VkPipelineCreateFlags2KHR pipeline_flags = vk_rt_pipeline_create_flags(pCreateInfo); + const VkPipelineBinaryInfoKHR *bin_info = + vk_find_struct_const(pCreateInfo->pNext, + PIPELINE_BINARY_INFO_KHR); + const VkPipelineCreationFeedbackCreateInfo *feedback_info = vk_find_struct_const(pCreateInfo->pNext, PIPELINE_CREATION_FEEDBACK_CREATE_INFO); @@ -3293,6 +3497,8 @@ vk_create_rt_pipeline(struct vk_device *device, uint32_t stack_max[MESA_SHADER_KERNEL] = { 0 }; + uint32_t binary_index = 0; + /* Load/Compile individual shaders */ for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { const VkPipelineShaderStageCreateInfo *stage_info = @@ -3300,25 +3506,38 @@ vk_create_rt_pipeline(struct vk_device *device, pipeline->base.stages |= pCreateInfo->pStages[i].stage; - result = vk_pipeline_precompile_shader(device, cache, pipeline_flags, - pCreateInfo->pNext, - stage_info, &compile_info.stages[i]); - if (result != VK_SUCCESS) - goto fail_stages_compile; - VkPipelineCreationFeedback feedback = { 0 }; - result = vk_pipeline_compile_rt_shader(device, cache, - pipeline_flags, - pipeline_layout, - &compile_info.stages[i], - &feedback); - - if ((feedback.flags & - VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) == 0 && - (pipeline->base.flags & - VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_KHR)) { - result = VK_PIPELINE_COMPILE_REQUIRED; - goto fail_stages_compile; + if (bin_info != NULL && bin_info->binaryCount > 0) { + VK_FROM_HANDLE(vk_pipeline_binary, binary, + bin_info->pPipelineBinaries[binary_index++]); + + result = vk_pipeline_load_shader_from_binary(device, + &compile_info.stages[i], + binary); + if (result != VK_SUCCESS) + goto fail_stages_compile; + } else { + result = vk_pipeline_precompile_shader(device, cache, pipeline_flags, + pCreateInfo->pNext, + stage_info, &compile_info.stages[i]); + if (result != VK_SUCCESS) + goto fail_stages_compile; + + assert(compile_info.stages[i].precomp != NULL); + + result = vk_pipeline_compile_rt_shader(device, cache, + pipeline_flags, + pipeline_layout, + &compile_info.stages[i], + &feedback); + + if ((feedback.flags & + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) == 0 && + (pipeline->base.flags & + VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_KHR)) { + result = VK_PIPELINE_COMPILE_REQUIRED; + goto fail_stages_compile; + } } if (result != VK_SUCCESS) @@ -3368,17 +3587,30 @@ vk_create_rt_pipeline(struct vk_device *device, if (linked_stage_count > 0) { assert(linked_stage_count > 1); - bool cache_hit; - result = vk_pipeline_compile_rt_shader_group(device, cache, - pipeline_flags, - pipeline_layout, - linked_stage_count, - linked_stages, - &cache_hit); - if (result != VK_SUCCESS) - goto fail_stages_compile; + if (bin_info != NULL && bin_info->binaryCount > 0) { + for (uint32_t s = 0; s < linked_stage_count; s++) { + VK_FROM_HANDLE(vk_pipeline_binary, binary, + bin_info->pPipelineBinaries[binary_index++]); - all_cache_hit &= cache_hit; + result = vk_pipeline_load_shader_from_binary(device, + &linked_stages[s], + binary); + if (result != VK_SUCCESS) + goto fail_stages_compile; + } + } else { + bool cache_hit; + result = vk_pipeline_compile_rt_shader_group(device, cache, + pipeline_flags, + pipeline_layout, + linked_stage_count, + linked_stages, + &cache_hit); + if (result != VK_SUCCESS) + goto fail_stages_compile; + + all_cache_hit &= cache_hit; + } /* Discard the precomps */ for (uint32_t s = 0; s < linked_stage_count; s++) { @@ -3393,6 +3625,7 @@ vk_create_rt_pipeline(struct vk_device *device, assert(compile_info.groups[i].stages[s].shader != NULL); group->stages[s] = (struct vk_rt_stage) { .shader = vk_shader_ref(compile_info.groups[i].stages[s].shader), + .imported = compile_info.groups[i].stages[s].imported, }; } else { for (uint32_t j = 0; j < linked_stage_count; j++) { @@ -3712,3 +3945,540 @@ vk_common_CmdSetRayTracingPipelineStackSizeKHR( ops->cmd_set_stack_size(cmd_buffer, pipelineStackSize); } + +static VkResult +vk_create_pipeline_binary(struct vk_device *device, + const void *key, size_t key_size, + const void *data, size_t data_size, + const VkAllocationCallbacks *alloc, + VkPipelineBinaryKHR *out_binary_h) +{ + struct vk_pipeline_binary *binary = + vk_object_alloc(device, alloc, sizeof(*binary) + data_size, + VK_OBJECT_TYPE_PIPELINE_BINARY_KHR); + if (binary == NULL) + return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + assert(key_size == sizeof(binary->key)); + memcpy(binary->key, key, key_size); + + binary->size = data_size; + memcpy(binary->data, data, data_size); + + *out_binary_h = vk_pipeline_binary_to_handle(binary); + + return VK_SUCCESS; +} + +static VkResult +vk_create_pipeline_binary_from_precomp(struct vk_device *device, + struct vk_pipeline_precomp_shader *precomp, + const VkAllocationCallbacks *alloc, + VkPipelineBinaryKHR *out_binary_h) +{ + VkResult result = VK_SUCCESS; + + struct blob blob; + blob_init(&blob); + + if (!vk_pipeline_precomp_shader_serialize(&precomp->cache_obj, &blob)) + result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + if (result == VK_SUCCESS) { + result = vk_create_pipeline_binary(device, + precomp->cache_key, + sizeof(precomp->cache_key), + blob.data, blob.size, + alloc, out_binary_h); + } + + blob_finish(&blob); + + return result; +} + +static VkResult +vk_create_pipeline_binary_from_shader(struct vk_device *device, + struct vk_shader *shader, + const VkAllocationCallbacks *alloc, + VkPipelineBinaryKHR *out_binary_h) +{ + VkResult result = VK_SUCCESS; + + struct blob blob; + blob_init(&blob); + + if (!shader->ops->serialize(device, shader, &blob)) + result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + if (result == VK_SUCCESS) { + result = vk_create_pipeline_binary(device, + shader->pipeline.cache_key, + sizeof(shader->pipeline.cache_key), + blob.data, blob.size, + alloc, out_binary_h); + } + + blob_finish(&blob); + + return result; +} + +static VkResult +vk_lookup_create_precomp_binary(struct vk_device *device, + struct vk_pipeline_cache *cache, + const void *key, uint32_t key_size, + const VkAllocationCallbacks *alloc, + VkPipelineBinaryKHR *out_binary_h) +{ + struct vk_pipeline_cache_object *cache_obj = + vk_pipeline_cache_lookup_object(cache, key, key_size, + &pipeline_precomp_shader_cache_ops, + NULL); + if (cache_obj == NULL) + return VK_PIPELINE_BINARY_MISSING_KHR; + + struct vk_pipeline_precomp_shader *precomp = + vk_pipeline_precomp_shader_from_cache_obj(cache_obj); + VkResult result = vk_create_pipeline_binary_from_precomp( + device, precomp, alloc, out_binary_h); + vk_pipeline_precomp_shader_unref(device, precomp); + + return result; +} + +static VkResult +vk_lookup_create_shader_binary(struct vk_device *device, + struct vk_pipeline_cache *cache, + const void *key, uint32_t key_size, + const VkAllocationCallbacks *alloc, + VkPipelineBinaryKHR *out_binary_h) +{ + struct vk_pipeline_cache_object *cache_obj = + vk_pipeline_cache_lookup_object(cache, key, key_size, + &pipeline_shader_cache_ops, + NULL); + if (cache_obj == NULL) + return VK_PIPELINE_BINARY_MISSING_KHR; + + struct vk_shader *shader = vk_shader_from_cache_obj(cache_obj); + VkResult result = vk_create_pipeline_binary_from_shader( + device, shader, alloc, out_binary_h); + vk_shader_unref(device, shader); + + return result; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreatePipelineBinariesKHR( + VkDevice _device, + const VkPipelineBinaryCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineBinaryHandlesInfoKHR* pBinaries) +{ + VK_FROM_HANDLE(vk_device, device, _device); + VK_FROM_HANDLE(vk_pipeline, pipeline, pCreateInfo->pipeline); + VK_OUTARRAY_MAKE_TYPED(VkPipelineBinaryKHR, out, + pBinaries->pPipelineBinaries, + &pBinaries->pipelineBinaryCount); + VkResult success_or_first_fail = VK_SUCCESS; + + /* VkPipelineBinaryCreateInfoKHR: + * + * "When pPipelineCreateInfo is not NULL, an implementation will attempt + * to retrieve pipeline binary data from an internal cache external to + * the application if pipelineBinaryInternalCache is VK_TRUE. + * Applications can use this to determine if a pipeline can be created + * without compilation. If the implementation fails to create a + * pipeline binary due to missing an internal cache entry, + * VK_PIPELINE_BINARY_MISSING_KHR is returned. If creation succeeds, the + * resulting binary can be used to create a pipeline. + * VK_PIPELINE_BINARY_MISSING_KHR may be returned for any reason in this + * situation, even if creating a pipeline binary with the same + * parameters that succeeded earlier." + */ + if (pCreateInfo->pPipelineCreateInfo && + device->physical->properties.pipelineBinaryInternalCache) { + assert(device->mem_cache != NULL); + struct vk_pipeline_cache *cache = device->mem_cache; + const VkBaseInStructure *next = pCreateInfo->pPipelineCreateInfo->pNext; + + switch (next->sType) { + case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO: { + struct vk_graphics_pipeline_state state_tmp; + struct vk_graphics_pipeline_all_state all_state_tmp; + memset(&state_tmp, 0, sizeof(state_tmp)); + struct vk_graphics_pipeline_compile_info info; + vk_get_graphics_pipeline_compile_info( + &info, device, &state_tmp, &all_state_tmp, + pCreateInfo->pPipelineCreateInfo->pNext); + + for (uint32_t i = 0; i < info.stage_count; i++) { + if (info.stages[i].imported) + continue; + + if (info.retain_precomp) { + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + VkResult result = vk_lookup_create_precomp_binary( + device, cache, + info.stages[i].precomp_key, + sizeof(info.stages[i].precomp_key), + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + VkResult result = vk_lookup_create_shader_binary( + device, cache, + info.stages[i].shader_key, + sizeof(info.stages[i].shader_key), + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + + vk_release_graphics_pipeline_compile_info(&info, device, pAllocator); + break; + } + + case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO: { + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + struct vk_pipeline_stage info; + vk_get_compute_pipeline_compile_info( + &info, device, pCreateInfo->pPipelineCreateInfo->pNext); + + VkResult result = vk_lookup_create_shader_binary( + device, cache, + info.shader_key, sizeof(info.shader_key), + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + + vk_pipeline_stage_finish(device, &info); + } + break; + } + + case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR: { + struct vk_rt_pipeline_compile_info info; + VkResult result = vk_get_rt_pipeline_compile_info( + &info, device, pCreateInfo->pPipelineCreateInfo->pNext, pAllocator); + if (result != VK_SUCCESS) + return result; + + for (uint32_t i = 0; i < info.stage_count; i++) { + if (info.stages[i].imported) + continue; + + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + result = vk_lookup_create_shader_binary( + device, cache, + info.stages[i].shader_key, sizeof(info.stages[i].shader_key), + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + + for (uint32_t i = 0; i < info.group_count; i++) { + for (uint32_t s = 0; s < info.groups[i].stage_count; s++) { + if (!info.groups[i].stages[s].linked) + continue; + + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + result = vk_lookup_create_shader_binary( + device, cache, + info.groups[i].stages[s].shader_key, + sizeof(info.groups[i].stages[s].shader_key), + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + } + + vk_release_rt_pipeline_compile_info(&info, device, pAllocator); + break; + } + + default: + UNREACHABLE("Unsupported pNext"); + } + } else if (pipeline != NULL) { + switch (pipeline->bind_point) { + case VK_PIPELINE_BIND_POINT_GRAPHICS: { + struct vk_graphics_pipeline *gfx_pipeline = + container_of(pipeline, struct vk_graphics_pipeline, base); + + for (uint32_t i = 0; i < gfx_pipeline->stage_count; i++) { + if (gfx_pipeline->stages[i].imported) + continue; + + if (gfx_pipeline->stages[i].precomp) { + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + VkResult result = vk_create_pipeline_binary_from_precomp( + device, gfx_pipeline->stages[i].precomp, + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + VkResult result = vk_create_pipeline_binary_from_shader( + device, gfx_pipeline->stages[i].shader, + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + break; + } + + case VK_PIPELINE_BIND_POINT_COMPUTE: { + struct vk_compute_pipeline *cs_pipeline = + container_of(pipeline, struct vk_compute_pipeline, base); + + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + VkResult result = vk_create_pipeline_binary_from_shader( + device, cs_pipeline->stage.shader, + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + break; + } + + case VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR: { + struct vk_rt_pipeline *rt_pipeline = + container_of(pipeline, struct vk_rt_pipeline, base); + + for (uint32_t i = 0; i < rt_pipeline->stage_count; i++) { + if (rt_pipeline->stages[i].imported) + continue; + + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + VkResult result = vk_create_pipeline_binary_from_shader( + device, rt_pipeline->stages[i].shader, + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + + for (uint32_t i = 0; i < rt_pipeline->group_count; i++) { + for (uint32_t s = 0; s < rt_pipeline->groups[i].stage_count; s++) { + if (!rt_pipeline->groups[i].stages[s].linked) + continue; + + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + VkResult result = vk_create_pipeline_binary_from_shader( + device, rt_pipeline->groups[i].stages[s].shader, + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + } + break; + } + + default: + UNREACHABLE("Unsupported pipeline"); + } + } else { + assert(pCreateInfo->pKeysAndDataInfo != NULL); + + for (uint32_t i = 0; i < pCreateInfo->pKeysAndDataInfo->binaryCount; i++) { + vk_outarray_append_typed(VkPipelineBinaryKHR, &out, binary) { + VkResult result = vk_create_pipeline_binary( + device, + pCreateInfo->pKeysAndDataInfo->pPipelineBinaryKeys[i].key, + pCreateInfo->pKeysAndDataInfo->pPipelineBinaryKeys[i].keySize, + pCreateInfo->pKeysAndDataInfo->pPipelineBinaryData[i].pData, + pCreateInfo->pKeysAndDataInfo->pPipelineBinaryData[i].dataSize, + pAllocator, binary); + if (result != VK_SUCCESS) { + *binary = VK_NULL_HANDLE; + if (success_or_first_fail == VK_SUCCESS) + success_or_first_fail = result; + } + } + } + } + + return success_or_first_fail != VK_SUCCESS ? + success_or_first_fail : vk_outarray_status(&out); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_DestroyPipelineBinaryKHR( + VkDevice _device, + VkPipelineBinaryKHR pipelineBinary, + const VkAllocationCallbacks* pAllocator) +{ + VK_FROM_HANDLE(vk_device, device, _device); + VK_FROM_HANDLE(vk_pipeline_binary, binary, pipelineBinary); + + if (binary == NULL) + return; + + vk_object_free(device, pAllocator, binary); +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_GetPipelineKeyKHR( + VkDevice _device, + const VkPipelineCreateInfoKHR* pPipelineCreateInfo, + VkPipelineBinaryKeyKHR* pPipelineKey) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + STATIC_ASSERT(sizeof(pPipelineKey->key) == sizeof(blake3_hash)); + + if (pPipelineCreateInfo == NULL) { + struct vk_physical_device *physical_device = device->physical; + _mesa_blake3_compute(physical_device->properties.shaderBinaryUUID, + sizeof(physical_device->properties.shaderBinaryUUID), + pPipelineKey->key); + pPipelineKey->keySize = sizeof(blake3_hash); + return VK_SUCCESS; + } + + const VkBaseInStructure *next = pPipelineCreateInfo->pNext; + + struct mesa_blake3 blake3_ctx; + _mesa_blake3_init(&blake3_ctx); + + switch (next->sType) { + case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO: { + struct vk_graphics_pipeline_state state_tmp; + struct vk_graphics_pipeline_all_state all_state_tmp; + memset(&state_tmp, 0, sizeof(state_tmp)); + struct vk_graphics_pipeline_compile_info info; + vk_get_graphics_pipeline_compile_info(&info, device, + &state_tmp, &all_state_tmp, + pPipelineCreateInfo->pNext); + for (uint32_t i = 0; i < info.stage_count; i++) { + _mesa_blake3_update(&blake3_ctx, &info.stages[i].shader_key, + sizeof(info.stages[i].shader_key)); + } + vk_release_graphics_pipeline_compile_info(&info, device, NULL); + break; + } + + case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO: { + struct vk_pipeline_stage info; + vk_get_compute_pipeline_compile_info(&info, device, + pPipelineCreateInfo->pNext); + _mesa_blake3_update(&blake3_ctx, &info.shader_key, + sizeof(info.shader_key)); + vk_pipeline_stage_finish(device, &info); + break; + } + + case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR: { + struct vk_rt_pipeline_compile_info info; + VkResult result = + vk_get_rt_pipeline_compile_info(&info, device, + pPipelineCreateInfo->pNext, NULL); + if (result != VK_SUCCESS) + return result; + for (uint32_t i = 0; i < info.stage_count; i++) { + _mesa_blake3_update(&blake3_ctx, &info.stages[i].shader_key, + sizeof(info.stages[i].shader_key)); + } + for (uint32_t i = 0; i < info.group_count; i++) { + for (uint32_t s = 0; s < info.groups[i].stage_count; s++) { + if (!info.groups[i].stages[s].linked) + continue; + _mesa_blake3_update(&blake3_ctx, + &info.groups[i].stages[s].shader_key, + sizeof(info.groups[i].stages[s].shader_key)); + } + } + vk_release_rt_pipeline_compile_info(&info, device, NULL); + break; + } + + default: + UNREACHABLE("Unsupported pNext"); + } + + pPipelineKey->keySize = sizeof(blake3_hash); + _mesa_blake3_final(&blake3_ctx, pPipelineKey->key); + + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_GetPipelineBinaryDataKHR( + VkDevice device, + const VkPipelineBinaryDataInfoKHR* pInfo, + VkPipelineBinaryKeyKHR* pPipelineBinaryKey, + size_t* pPipelineBinaryDataSize, + void* pPipelineBinaryData) +{ + VK_FROM_HANDLE(vk_pipeline_binary, binary, pInfo->pipelineBinary); + + pPipelineBinaryKey->keySize = sizeof(binary->key); + memcpy(pPipelineBinaryKey->key, binary->key, sizeof(binary->key)); + + if (*pPipelineBinaryDataSize == 0) { + *pPipelineBinaryDataSize = binary->size; + return VK_SUCCESS; + } + + VkResult result = + *pPipelineBinaryDataSize < binary->size ? + VK_ERROR_NOT_ENOUGH_SPACE_KHR : VK_SUCCESS; + + *pPipelineBinaryDataSize = binary->size; + if (result == VK_SUCCESS) + memcpy(pPipelineBinaryData, binary->data, binary->size); + + return result; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_ReleaseCapturedPipelineDataKHR( + VkDevice device, + const VkReleaseCapturedPipelineDataInfoKHR* pInfo, + const VkAllocationCallbacks* pAllocator) +{ + /* NO-OP */ + return VK_SUCCESS; +} |