2675 lines · 91.2 KB · C
RawDownload
/* * 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t