/* * Copyright (c) Lynne * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avassert.h"#include "mem.h" #include "vulkan.h"#include "libavutil/vulkan_loader.h" const VkComponentMapping ff_comp_identity_map = { .r = VK_COMPONENT_SWIZZLE_IDENTITY, .g = VK_COMPONENT_SWIZZLE_IDENTITY, .b = VK_COMPONENT_SWIZZLE_IDENTITY, .a = VK_COMPONENT_SWIZZLE_IDENTITY,}; /* Converts return values to strings */const char *ff_vk_ret2str(VkResult res){#define CASE(VAL) case VAL: return #VAL switch (res) { CASE(VK_SUCCESS); CASE(VK_NOT_READY); CASE(VK_TIMEOUT); CASE(VK_EVENT_SET); CASE(VK_EVENT_RESET); CASE(VK_INCOMPLETE); CASE(VK_ERROR_OUT_OF_HOST_MEMORY); CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY); CASE(VK_ERROR_INITIALIZATION_FAILED); CASE(VK_ERROR_DEVICE_LOST); CASE(VK_ERROR_MEMORY_MAP_FAILED); CASE(VK_ERROR_LAYER_NOT_PRESENT); CASE(VK_ERROR_EXTENSION_NOT_PRESENT); CASE(VK_ERROR_FEATURE_NOT_PRESENT); CASE(VK_ERROR_INCOMPATIBLE_DRIVER); CASE(VK_ERROR_TOO_MANY_OBJECTS); CASE(VK_ERROR_FORMAT_NOT_SUPPORTED); CASE(VK_ERROR_FRAGMENTED_POOL); CASE(VK_ERROR_UNKNOWN); CASE(VK_ERROR_OUT_OF_POOL_MEMORY); CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE); CASE(VK_ERROR_FRAGMENTATION); CASE(VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS); CASE(VK_PIPELINE_COMPILE_REQUIRED); CASE(VK_ERROR_SURFACE_LOST_KHR); CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR); CASE(VK_SUBOPTIMAL_KHR); CASE(VK_ERROR_OUT_OF_DATE_KHR); CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR); CASE(VK_ERROR_VALIDATION_FAILED_EXT); CASE(VK_ERROR_INVALID_SHADER_NV); CASE(VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR); CASE(VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR); CASE(VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR); CASE(VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR); CASE(VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR); CASE(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT); CASE(VK_ERROR_NOT_PERMITTED_KHR); CASE(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT); CASE(VK_THREAD_IDLE_KHR); CASE(VK_THREAD_DONE_KHR); CASE(VK_OPERATION_DEFERRED_KHR); CASE(VK_OPERATION_NOT_DEFERRED_KHR); default: return "Unknown error"; }#undef CASE} static void load_enabled_qfs(FFVulkanContext *s){ s->nb_qfs = 0; for (int i = 0; i < s->hwctx->nb_qf; i++) { /* Skip duplicates */ int skip = 0; for (int j = 0; j < s->nb_qfs; j++) { if (s->qfs[j] == s->hwctx->qf[i].idx) { skip = 1; break; } } if (skip) continue; s->qfs[s->nb_qfs++] = s->hwctx->qf[i].idx; }} int ff_vk_load_props(FFVulkanContext *s){ FFVulkanFunctions *vk = &s->vkfn; s->hprops = (VkPhysicalDeviceExternalMemoryHostPropertiesEXT) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT, }; s->optical_flow_props = (VkPhysicalDeviceOpticalFlowPropertiesNV) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV, .pNext = &s->hprops, }; s->coop_matrix_props = (VkPhysicalDeviceCooperativeMatrixPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR, .pNext = &s->optical_flow_props, }; s->subgroup_props = (VkPhysicalDeviceSubgroupSizeControlProperties) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, .pNext = &s->coop_matrix_props, }; s->desc_buf_props = (VkPhysicalDeviceDescriptorBufferPropertiesEXT) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT, .pNext = &s->subgroup_props, }; s->driver_props = (VkPhysicalDeviceDriverProperties) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, .pNext = &s->desc_buf_props, }; s->props_11 = (VkPhysicalDeviceVulkan11Properties) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES, .pNext = &s->driver_props, }; s->props = (VkPhysicalDeviceProperties2) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &s->props_11, }; s->atomic_float_feats = (VkPhysicalDeviceShaderAtomicFloatFeaturesEXT) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT, }; s->feats_12 = (VkPhysicalDeviceVulkan12Features) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, .pNext = &s->atomic_float_feats, }; s->feats = (VkPhysicalDeviceFeatures2) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, .pNext = &s->feats_12, }; vk->GetPhysicalDeviceProperties2(s->hwctx->phys_dev, &s->props); vk->GetPhysicalDeviceMemoryProperties(s->hwctx->phys_dev, &s->mprops); vk->GetPhysicalDeviceFeatures2(s->hwctx->phys_dev, &s->feats); load_enabled_qfs(s); if (s->qf_props) return 0; vk->GetPhysicalDeviceQueueFamilyProperties2(s->hwctx->phys_dev, &s->tot_nb_qfs, NULL); s->qf_props = av_calloc(s->tot_nb_qfs, sizeof(*s->qf_props)); if (!s->qf_props) return AVERROR(ENOMEM); s->query_props = av_calloc(s->tot_nb_qfs, sizeof(*s->query_props)); if (!s->qf_props) { av_freep(&s->qf_props); return AVERROR(ENOMEM); } s->video_props = av_calloc(s->tot_nb_qfs, sizeof(*s->video_props)); if (!s->video_props) { av_freep(&s->qf_props); av_freep(&s->query_props); return AVERROR(ENOMEM); } for (uint32_t i = 0; i < s->tot_nb_qfs; i++) { s->query_props[i] = (VkQueueFamilyQueryResultStatusPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_KHR, }; s->video_props[i] = (VkQueueFamilyVideoPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR, .pNext = &s->query_props[i], }; s->qf_props[i] = (VkQueueFamilyProperties2) { .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, .pNext = &s->video_props[i], }; } vk->GetPhysicalDeviceQueueFamilyProperties2(s->hwctx->phys_dev, &s->tot_nb_qfs, s->qf_props); if (s->extensions & FF_VK_EXT_COOP_MATRIX) { vk->GetPhysicalDeviceCooperativeMatrixPropertiesKHR(s->hwctx->phys_dev, &s->coop_mat_props_nb, NULL); if (s->coop_mat_props_nb) { s->coop_mat_props = av_malloc_array(s->coop_mat_props_nb, sizeof(VkCooperativeMatrixPropertiesKHR)); for (int i = 0; i < s->coop_mat_props_nb; i++) { s->coop_mat_props[i] = (VkCooperativeMatrixPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR, }; } vk->GetPhysicalDeviceCooperativeMatrixPropertiesKHR(s->hwctx->phys_dev, &s->coop_mat_props_nb, s->coop_mat_props); } } return 0;} AVVulkanDeviceQueueFamily *ff_vk_qf_find(FFVulkanContext *s, VkQueueFlagBits dev_family, VkVideoCodecOperationFlagBitsKHR vid_ops){ for (int i = 0; i < s->hwctx->nb_qf; i++) { if ((s->hwctx->qf[i].flags & dev_family) && (s->hwctx->qf[i].video_caps & vid_ops) == vid_ops) { return &s->hwctx->qf[i]; } } return NULL;} void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool){ FFVulkanFunctions *vk = &s->vkfn; for (int i = 0; i < pool->pool_size; i++) { FFVkExecContext *e = &pool->contexts[i]; if (e->fence) { if (e->had_submission) vk->WaitForFences(s->hwctx->act_dev, 1, &e->fence, VK_TRUE, UINT64_MAX); vk->DestroyFence(s->hwctx->act_dev, e->fence, s->hwctx->alloc); } ff_vk_exec_discard_deps(s, e); av_free(e->frame_deps); av_free(e->sw_frame_deps); av_free(e->buf_deps); av_free(e->queue_family_dst); av_free(e->layout_dst); av_free(e->access_dst); av_free(e->frame_update); av_free(e->frame_locked); av_free(e->sem_sig); av_free(e->sem_sig_val_dst); av_free(e->sem_wait); } /* Free shader-specific data */ for (int i = 0; i < pool->nb_reg_shd; i++) { FFVulkanShaderData *sd = &pool->reg_shd[i]; if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) { for (int j = 0; j < sd->nb_descriptor_sets; j++) { FFVulkanDescriptorSetData *set_data = &sd->desc_set_buf[j]; if (set_data->buf.mem) ff_vk_unmap_buffer(s, &set_data->buf, 0); ff_vk_free_buf(s, &set_data->buf); } } if (sd->desc_pool) vk->DestroyDescriptorPool(s->hwctx->act_dev, sd->desc_pool, s->hwctx->alloc); av_freep(&sd->desc_set_buf); av_freep(&sd->desc_bind); av_freep(&sd->desc_sets); } if (pool->cmd_bufs) vk->FreeCommandBuffers(s->hwctx->act_dev, pool->cmd_buf_pool, pool->pool_size, pool->cmd_bufs); if (pool->cmd_buf_pool) vk->DestroyCommandPool(s->hwctx->act_dev, pool->cmd_buf_pool, s->hwctx->alloc); if (pool->query_pool) vk->DestroyQueryPool(s->hwctx->act_dev, pool->query_pool, s->hwctx->alloc); av_free(pool->query_data); av_free(pool->cmd_bufs); av_free(pool->contexts);} int ff_vk_exec_pool_init(FFVulkanContext *s, AVVulkanDeviceQueueFamily *qf, FFVkExecPool *pool, int nb_contexts, int nb_queries, VkQueryType query_type, int query_64bit, const void *query_create_pnext){ int err; VkResult ret; FFVulkanFunctions *vk = &s->vkfn; VkCommandPoolCreateInfo cqueue_create; VkCommandBufferAllocateInfo cbuf_create; const VkQueryPoolVideoEncodeFeedbackCreateInfoKHR *ef = NULL; atomic_init(&pool->idx, 0); if (query_type == VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR) { ef = ff_vk_find_struct(query_create_pnext, VK_STRUCTURE_TYPE_QUERY_POOL_VIDEO_ENCODE_FEEDBACK_CREATE_INFO_KHR); if (!ef) return AVERROR(EINVAL); } /* Create command pool */ cqueue_create = (VkCommandPoolCreateInfo) { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = qf->idx, }; ret = vk->CreateCommandPool(s->hwctx->act_dev, &cqueue_create, s->hwctx->alloc, &pool->cmd_buf_pool); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Command pool creation failure: %s\n", ff_vk_ret2str(ret)); err = AVERROR_EXTERNAL; goto fail; } /* Allocate space for command buffers */ pool->cmd_bufs = av_malloc(nb_contexts*sizeof(*pool->cmd_bufs)); if (!pool->cmd_bufs) { err = AVERROR(ENOMEM); goto fail; } /* Allocate command buffer */ cbuf_create = (VkCommandBufferAllocateInfo) { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandPool = pool->cmd_buf_pool, .commandBufferCount = nb_contexts, }; ret = vk->AllocateCommandBuffers(s->hwctx->act_dev, &cbuf_create, pool->cmd_bufs); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Command buffer alloc failure: %s\n", ff_vk_ret2str(ret)); err = AVERROR_EXTERNAL; goto fail; } /* Query pool */ if (nb_queries) { VkQueryPoolCreateInfo query_pool_info = { .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, .pNext = query_create_pnext, .queryType = query_type, .queryCount = nb_queries*nb_contexts, }; ret = vk->CreateQueryPool(s->hwctx->act_dev, &query_pool_info, s->hwctx->alloc, &pool->query_pool); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Query pool alloc failure: %s\n", ff_vk_ret2str(ret)); err = AVERROR_EXTERNAL; goto fail; } pool->nb_queries = nb_queries; pool->query_status_stride = 1 + 1; /* One result, one status by default */ pool->query_results = nb_queries; pool->query_statuses = nb_queries; /* Video encode quieries produce two results per query */ if (query_type == VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR) { int nb_results = av_popcount(ef->encodeFeedbackFlags); pool->query_status_stride = nb_results + 1; pool->query_results *= nb_results; } else if (query_type == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR) { pool->query_status_stride = 1; pool->query_results = 0; } pool->qd_size = (pool->query_results + pool->query_statuses)*(query_64bit ? 8 : 4); /* Allocate space for the query data */ pool->query_data = av_calloc(nb_contexts, pool->qd_size); if (!pool->query_data) { err = AVERROR(ENOMEM); goto fail; } } /* Allocate space for the contexts */ pool->contexts = av_calloc(nb_contexts, sizeof(*pool->contexts)); if (!pool->contexts) { err = AVERROR(ENOMEM); goto fail; } pool->pool_size = nb_contexts; /* Init contexts */ for (int i = 0; i < pool->pool_size; i++) { FFVkExecContext *e = &pool->contexts[i]; VkFenceCreateInfo fence_create = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT, }; /* Fence */ ret = vk->CreateFence(s->hwctx->act_dev, &fence_create, s->hwctx->alloc, &e->fence); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Failed to create submission fence: %s\n", ff_vk_ret2str(ret)); return AVERROR_EXTERNAL; } e->idx = i; e->parent = pool; /* Query data */ e->query_data = ((uint8_t *)pool->query_data) + pool->qd_size*i; e->query_idx = nb_queries*i; /* Command buffer */ e->buf = pool->cmd_bufs[i]; /* Queue index distribution */ e->qi = i % qf->num; e->qf = qf->idx; vk->GetDeviceQueue(s->hwctx->act_dev, qf->idx, e->qi, &e->queue); } return 0; fail: ff_vk_exec_pool_free(s, pool); return err;} VkResult ff_vk_exec_get_query(FFVulkanContext *s, FFVkExecContext *e, void **data, VkQueryResultFlagBits flags){ FFVulkanFunctions *vk = &s->vkfn; const FFVkExecPool *pool = e->parent; VkQueryResultFlags qf = flags & ~(VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_STATUS_BIT_KHR); if (!e->query_data) { av_log(s, AV_LOG_ERROR, "Requested a query with a NULL query_data pointer!\n"); return VK_INCOMPLETE; } qf |= pool->query_64bit ? VK_QUERY_RESULT_64_BIT : 0x0; qf |= pool->query_statuses ? VK_QUERY_RESULT_WITH_STATUS_BIT_KHR : 0x0; if (data) *data = e->query_data; return vk->GetQueryPoolResults(s->hwctx->act_dev, pool->query_pool, e->query_idx, pool->nb_queries, pool->qd_size, e->query_data, pool->qd_size, qf);} FFVkExecContext *ff_vk_exec_get(FFVulkanContext *s, FFVkExecPool *pool){ return &pool->contexts[atomic_fetch_add(&pool->idx, 1) % pool->pool_size];} void ff_vk_exec_wait(FFVulkanContext *s, FFVkExecContext *e){ FFVulkanFunctions *vk = &s->vkfn; vk->WaitForFences(s->hwctx->act_dev, 1, &e->fence, VK_TRUE, UINT64_MAX); ff_vk_exec_discard_deps(s, e);} int ff_vk_exec_start(FFVulkanContext *s, FFVkExecContext *e){ VkResult ret; FFVulkanFunctions *vk = &s->vkfn; const FFVkExecPool *pool = e->parent; VkCommandBufferBeginInfo cmd_start = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, }; /* Wait for the fence to be signalled */Lines 1–500 of 2675. Load more
/* * Copyright (c) Lynne * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avassert.h" #include "mem.h" #include "vulkan.h" #include "libavutil/vulkan_loader.h" const VkComponentMapping ff_comp_identity_map = { .r = VK_COMPONENT_SWIZZLE_IDENTITY, .g = VK_COMPONENT_SWIZZLE_IDENTITY, .b = VK_COMPONENT_SWIZZLE_IDENTITY, .a = VK_COMPONENT_SWIZZLE_IDENTITY, }; /* Converts return values to strings */ const char *ff_vk_ret2str(VkResult res) { #define CASE(VAL) case VAL: return #VAL switch (res) { CASE(VK_SUCCESS); CASE(VK_NOT_READY); CASE(VK_TIMEOUT); CASE(VK_EVENT_SET); CASE(VK_EVENT_RESET); CASE(VK_INCOMPLETE); CASE(VK_ERROR_OUT_OF_HOST_MEMORY); CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY); CASE(VK_ERROR_INITIALIZATION_FAILED); CASE(VK_ERROR_DEVICE_LOST); CASE(VK_ERROR_MEMORY_MAP_FAILED); CASE(VK_ERROR_LAYER_NOT_PRESENT); CASE(VK_ERROR_EXTENSION_NOT_PRESENT); CASE(VK_ERROR_FEATURE_NOT_PRESENT); CASE(VK_ERROR_INCOMPATIBLE_DRIVER); CASE(VK_ERROR_TOO_MANY_OBJECTS); CASE(VK_ERROR_FORMAT_NOT_SUPPORTED); CASE(VK_ERROR_FRAGMENTED_POOL); CASE(VK_ERROR_UNKNOWN); CASE(VK_ERROR_OUT_OF_POOL_MEMORY); CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE); CASE(VK_ERROR_FRAGMENTATION); CASE(VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS); CASE(VK_PIPELINE_COMPILE_REQUIRED); CASE(VK_ERROR_SURFACE_LOST_KHR); CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR); CASE(VK_SUBOPTIMAL_KHR); CASE(VK_ERROR_OUT_OF_DATE_KHR); CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR); CASE(VK_ERROR_VALIDATION_FAILED_EXT); CASE(VK_ERROR_INVALID_SHADER_NV); CASE(VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR); CASE(VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR); CASE(VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR); CASE(VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR); CASE(VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR); CASE(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT); CASE(VK_ERROR_NOT_PERMITTED_KHR); CASE(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT); CASE(VK_THREAD_IDLE_KHR); CASE(VK_THREAD_DONE_KHR); CASE(VK_OPERATION_DEFERRED_KHR); CASE(VK_OPERATION_NOT_DEFERRED_KHR); default: return "Unknown error"; } #undef CASE } static void load_enabled_qfs(FFVulkanContext *s) { s->nb_qfs = 0; for (int i = 0; i < s->hwctx->nb_qf; i++) { /* Skip duplicates */ int skip = 0; for (int j = 0; j < s->nb_qfs; j++) { if (s->qfs[j] == s->hwctx->qf[i].idx) { skip = 1; break; } } if (skip) continue; s->qfs[s->nb_qfs++] = s->hwctx->qf[i].idx; } } int ff_vk_load_props(FFVulkanContext *s) { FFVulkanFunctions *vk = &s->vkfn; s->hprops = (VkPhysicalDeviceExternalMemoryHostPropertiesEXT) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT, }; s->optical_flow_props = (VkPhysicalDeviceOpticalFlowPropertiesNV) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV, .pNext = &s->hprops, }; s->coop_matrix_props = (VkPhysicalDeviceCooperativeMatrixPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR, .pNext = &s->optical_flow_props, }; s->subgroup_props = (VkPhysicalDeviceSubgroupSizeControlProperties) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, .pNext = &s->coop_matrix_props, }; s->desc_buf_props = (VkPhysicalDeviceDescriptorBufferPropertiesEXT) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT, .pNext = &s->subgroup_props, }; s->driver_props = (VkPhysicalDeviceDriverProperties) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, .pNext = &s->desc_buf_props, }; s->props_11 = (VkPhysicalDeviceVulkan11Properties) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES, .pNext = &s->driver_props, }; s->props = (VkPhysicalDeviceProperties2) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &s->props_11, }; s->atomic_float_feats = (VkPhysicalDeviceShaderAtomicFloatFeaturesEXT) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT, }; s->feats_12 = (VkPhysicalDeviceVulkan12Features) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, .pNext = &s->atomic_float_feats, }; s->feats = (VkPhysicalDeviceFeatures2) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, .pNext = &s->feats_12, }; vk->GetPhysicalDeviceProperties2(s->hwctx->phys_dev, &s->props); vk->GetPhysicalDeviceMemoryProperties(s->hwctx->phys_dev, &s->mprops); vk->GetPhysicalDeviceFeatures2(s->hwctx->phys_dev, &s->feats); load_enabled_qfs(s); if (s->qf_props) return 0; vk->GetPhysicalDeviceQueueFamilyProperties2(s->hwctx->phys_dev, &s->tot_nb_qfs, NULL); s->qf_props = av_calloc(s->tot_nb_qfs, sizeof(*s->qf_props)); if (!s->qf_props) return AVERROR(ENOMEM); s->query_props = av_calloc(s->tot_nb_qfs, sizeof(*s->query_props)); if (!s->qf_props) { av_freep(&s->qf_props); return AVERROR(ENOMEM); } s->video_props = av_calloc(s->tot_nb_qfs, sizeof(*s->video_props)); if (!s->video_props) { av_freep(&s->qf_props); av_freep(&s->query_props); return AVERROR(ENOMEM); } for (uint32_t i = 0; i < s->tot_nb_qfs; i++) { s->query_props[i] = (VkQueueFamilyQueryResultStatusPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_KHR, }; s->video_props[i] = (VkQueueFamilyVideoPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR, .pNext = &s->query_props[i], }; s->qf_props[i] = (VkQueueFamilyProperties2) { .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, .pNext = &s->video_props[i], }; } vk->GetPhysicalDeviceQueueFamilyProperties2(s->hwctx->phys_dev, &s->tot_nb_qfs, s->qf_props); if (s->extensions & FF_VK_EXT_COOP_MATRIX) { vk->GetPhysicalDeviceCooperativeMatrixPropertiesKHR(s->hwctx->phys_dev, &s->coop_mat_props_nb, NULL); if (s->coop_mat_props_nb) { s->coop_mat_props = av_malloc_array(s->coop_mat_props_nb, sizeof(VkCooperativeMatrixPropertiesKHR)); for (int i = 0; i < s->coop_mat_props_nb; i++) { s->coop_mat_props[i] = (VkCooperativeMatrixPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR, }; } vk->GetPhysicalDeviceCooperativeMatrixPropertiesKHR(s->hwctx->phys_dev, &s->coop_mat_props_nb, s->coop_mat_props); } } return 0; } AVVulkanDeviceQueueFamily *ff_vk_qf_find(FFVulkanContext *s, VkQueueFlagBits dev_family, VkVideoCodecOperationFlagBitsKHR vid_ops) { for (int i = 0; i < s->hwctx->nb_qf; i++) { if ((s->hwctx->qf[i].flags & dev_family) && (s->hwctx->qf[i].video_caps & vid_ops) == vid_ops) { return &s->hwctx->qf[i]; } } return NULL; } void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool) { FFVulkanFunctions *vk = &s->vkfn; for (int i = 0; i < pool->pool_size; i++) { FFVkExecContext *e = &pool->contexts[i]; if (e->fence) { if (e->had_submission) vk->WaitForFences(s->hwctx->act_dev, 1, &e->fence, VK_TRUE, UINT64_MAX); vk->DestroyFence(s->hwctx->act_dev, e->fence, s->hwctx->alloc); } ff_vk_exec_discard_deps(s, e); av_free(e->frame_deps); av_free(e->sw_frame_deps); av_free(e->buf_deps); av_free(e->queue_family_dst); av_free(e->layout_dst); av_free(e->access_dst); av_free(e->frame_update); av_free(e->frame_locked); av_free(e->sem_sig); av_free(e->sem_sig_val_dst); av_free(e->sem_wait); } /* Free shader-specific data */ for (int i = 0; i < pool->nb_reg_shd; i++) { FFVulkanShaderData *sd = &pool->reg_shd[i]; if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) { for (int j = 0; j < sd->nb_descriptor_sets; j++) { FFVulkanDescriptorSetData *set_data = &sd->desc_set_buf[j]; if (set_data->buf.mem) ff_vk_unmap_buffer(s, &set_data->buf, 0); ff_vk_free_buf(s, &set_data->buf); } } if (sd->desc_pool) vk->DestroyDescriptorPool(s->hwctx->act_dev, sd->desc_pool, s->hwctx->alloc); av_freep(&sd->desc_set_buf); av_freep(&sd->desc_bind); av_freep(&sd->desc_sets); } if (pool->cmd_bufs) vk->FreeCommandBuffers(s->hwctx->act_dev, pool->cmd_buf_pool, pool->pool_size, pool->cmd_bufs); if (pool->cmd_buf_pool) vk->DestroyCommandPool(s->hwctx->act_dev, pool->cmd_buf_pool, s->hwctx->alloc); if (pool->query_pool) vk->DestroyQueryPool(s->hwctx->act_dev, pool->query_pool, s->hwctx->alloc); av_free(pool->query_data); av_free(pool->cmd_bufs); av_free(pool->contexts); } int ff_vk_exec_pool_init(FFVulkanContext *s, AVVulkanDeviceQueueFamily *qf, FFVkExecPool *pool, int nb_contexts, int nb_queries, VkQueryType query_type, int query_64bit, const void *query_create_pnext) { int err; VkResult ret; FFVulkanFunctions *vk = &s->vkfn; VkCommandPoolCreateInfo cqueue_create; VkCommandBufferAllocateInfo cbuf_create; const VkQueryPoolVideoEncodeFeedbackCreateInfoKHR *ef = NULL; atomic_init(&pool->idx, 0); if (query_type == VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR) { ef = ff_vk_find_struct(query_create_pnext, VK_STRUCTURE_TYPE_QUERY_POOL_VIDEO_ENCODE_FEEDBACK_CREATE_INFO_KHR); if (!ef) return AVERROR(EINVAL); } /* Create command pool */ cqueue_create = (VkCommandPoolCreateInfo) { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = qf->idx, }; ret = vk->CreateCommandPool(s->hwctx->act_dev, &cqueue_create, s->hwctx->alloc, &pool->cmd_buf_pool); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Command pool creation failure: %s\n", ff_vk_ret2str(ret)); err = AVERROR_EXTERNAL; goto fail; } /* Allocate space for command buffers */ pool->cmd_bufs = av_malloc(nb_contexts*sizeof(*pool->cmd_bufs)); if (!pool->cmd_bufs) { err = AVERROR(ENOMEM); goto fail; } /* Allocate command buffer */ cbuf_create = (VkCommandBufferAllocateInfo) { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandPool = pool->cmd_buf_pool, .commandBufferCount = nb_contexts, }; ret = vk->AllocateCommandBuffers(s->hwctx->act_dev, &cbuf_create, pool->cmd_bufs); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Command buffer alloc failure: %s\n", ff_vk_ret2str(ret)); err = AVERROR_EXTERNAL; goto fail; } /* Query pool */ if (nb_queries) { VkQueryPoolCreateInfo query_pool_info = { .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, .pNext = query_create_pnext, .queryType = query_type, .queryCount = nb_queries*nb_contexts, }; ret = vk->CreateQueryPool(s->hwctx->act_dev, &query_pool_info, s->hwctx->alloc, &pool->query_pool); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Query pool alloc failure: %s\n", ff_vk_ret2str(ret)); err = AVERROR_EXTERNAL; goto fail; } pool->nb_queries = nb_queries; pool->query_status_stride = 1 + 1; /* One result, one status by default */ pool->query_results = nb_queries; pool->query_statuses = nb_queries; /* Video encode quieries produce two results per query */ if (query_type == VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR) { int nb_results = av_popcount(ef->encodeFeedbackFlags); pool->query_status_stride = nb_results + 1; pool->query_results *= nb_results; } else if (query_type == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR) { pool->query_status_stride = 1; pool->query_results = 0; } pool->qd_size = (pool->query_results + pool->query_statuses)*(query_64bit ? 8 : 4); /* Allocate space for the query data */ pool->query_data = av_calloc(nb_contexts, pool->qd_size); if (!pool->query_data) { err = AVERROR(ENOMEM); goto fail; } } /* Allocate space for the contexts */ pool->contexts = av_calloc(nb_contexts, sizeof(*pool->contexts)); if (!pool->contexts) { err = AVERROR(ENOMEM); goto fail; } pool->pool_size = nb_contexts; /* Init contexts */ for (int i = 0; i < pool->pool_size; i++) { FFVkExecContext *e = &pool->contexts[i]; VkFenceCreateInfo fence_create = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT, }; /* Fence */ ret = vk->CreateFence(s->hwctx->act_dev, &fence_create, s->hwctx->alloc, &e->fence); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Failed to create submission fence: %s\n", ff_vk_ret2str(ret)); return AVERROR_EXTERNAL; } e->idx = i; e->parent = pool; /* Query data */ e->query_data = ((uint8_t *)pool->query_data) + pool->qd_size*i; e->query_idx = nb_queries*i; /* Command buffer */ e->buf = pool->cmd_bufs[i]; /* Queue index distribution */ e->qi = i % qf->num; e->qf = qf->idx; vk->GetDeviceQueue(s->hwctx->act_dev, qf->idx, e->qi, &e->queue); } return 0; fail: ff_vk_exec_pool_free(s, pool); return err; } VkResult ff_vk_exec_get_query(FFVulkanContext *s, FFVkExecContext *e, void **data, VkQueryResultFlagBits flags) { FFVulkanFunctions *vk = &s->vkfn; const FFVkExecPool *pool = e->parent; VkQueryResultFlags qf = flags & ~(VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_STATUS_BIT_KHR); if (!e->query_data) { av_log(s, AV_LOG_ERROR, "Requested a query with a NULL query_data pointer!\n"); return VK_INCOMPLETE; } qf |= pool->query_64bit ? VK_QUERY_RESULT_64_BIT : 0x0; qf |= pool->query_statuses ? VK_QUERY_RESULT_WITH_STATUS_BIT_KHR : 0x0; if (data) *data = e->query_data; return vk->GetQueryPoolResults(s->hwctx->act_dev, pool->query_pool, e->query_idx, pool->nb_queries, pool->qd_size, e->query_data, pool->qd_size, qf); } FFVkExecContext *ff_vk_exec_get(FFVulkanContext *s, FFVkExecPool *pool) { return &pool->contexts[atomic_fetch_add(&pool->idx, 1) % pool->pool_size]; } void ff_vk_exec_wait(FFVulkanContext *s, FFVkExecContext *e) { FFVulkanFunctions *vk = &s->vkfn; vk->WaitForFences(s->hwctx->act_dev, 1, &e->fence, VK_TRUE, UINT64_MAX); ff_vk_exec_discard_deps(s, e); } int ff_vk_exec_start(FFVulkanContext *s, FFVkExecContext *e) { VkResult ret; FFVulkanFunctions *vk = &s->vkfn; const FFVkExecPool *pool = e->parent; VkCommandBufferBeginInfo cmd_start = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, }; /* Wait for the fence to be signalled */