vulkan: add support for queries

This commit is contained in:
Lynne 2022-12-22 05:03:32 +01:00
parent f3fb1b50bb
commit 6eaf3fe69c
No known key found for this signature in database
GPG Key ID: A2FEA5F03F034464
2 changed files with 148 additions and 0 deletions

View File

@ -592,6 +592,114 @@ int ff_vk_create_exec_ctx(FFVulkanContext *s, FFVkExecContext **ctx,
return 0;
}
int ff_vk_create_exec_ctx_query_pool(FFVulkanContext *s, FFVkExecContext *e,
int nb_queries, VkQueryType type,
int elem_64bits, void *create_pnext)
{
VkResult ret;
size_t qd_size;
int nb_results = nb_queries;
int nb_statuses = 0 /* Once RADV has support, = nb_queries */;
int status_stride = 2;
int result_elem_size = elem_64bits ? 8 : 4;
FFVulkanFunctions *vk = &s->vkfn;
VkQueryPoolCreateInfo query_pool_info = {
.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
.pNext = create_pnext,
.queryType = type,
.queryCount = nb_queries*e->qf->nb_queues,
};
if (e->query.pool)
return AVERROR(EINVAL);
/* Video encode quieries produce two results per query */
if (type == VK_QUERY_TYPE_VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR) {
status_stride = 3; /* skip,skip,result,skip,skip,result */
nb_results *= 2;
} else if (type == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR) {
status_stride = 1;
nb_results *= 0;
}
qd_size = nb_results*result_elem_size + nb_statuses*result_elem_size;
e->query.data = av_mallocz(e->qf->nb_queues*qd_size);
if (!e->query.data)
return AVERROR(ENOMEM);
ret = vk->CreateQueryPool(s->hwctx->act_dev, &query_pool_info,
s->hwctx->alloc, &e->query.pool);
if (ret != VK_SUCCESS)
return AVERROR_EXTERNAL;
e->query.data_per_queue = qd_size;
e->query.nb_queries = nb_queries;
e->query.nb_results = nb_results;
e->query.nb_statuses = nb_statuses;
e->query.elem_64bits = elem_64bits;
e->query.status_stride = status_stride;
return 0;
}
int ff_vk_get_exec_ctx_query_results(FFVulkanContext *s, FFVkExecContext *e,
int query_idx, void **data, int64_t *status)
{
VkResult ret;
FFVulkanFunctions *vk = &s->vkfn;
uint8_t *qd;
int32_t *res32;
int64_t *res64;
int64_t res = 0;
VkQueryResultFlags qf = 0;
FFVkQueueCtx *q = &e->queues[e->qf->cur_queue];
if (!q->submitted) {
*data = NULL;
return 0;
}
qd = e->query.data + e->qf->cur_queue*e->query.data_per_queue;
qf |= e->query.nb_results && e->query.nb_statuses ?
VK_QUERY_RESULT_WITH_STATUS_BIT_KHR : 0x0;
qf |= e->query.elem_64bits ? VK_QUERY_RESULT_64_BIT : 0x0;
res32 = (int32_t *)(qd + e->query.nb_results*4);
res64 = (int64_t *)(qd + e->query.nb_results*8);
ret = vk->GetQueryPoolResults(s->hwctx->act_dev, e->query.pool,
query_idx,
e->query.nb_queries,
e->query.data_per_queue, qd,
e->query.elem_64bits ? 8 : 4, qf);
if (ret != VK_SUCCESS) {
av_log(s, AV_LOG_ERROR, "Unable to perform query: %s!\n",
ff_vk_ret2str(ret));
return AVERROR_EXTERNAL;
}
if (e->query.nb_statuses && e->query.elem_64bits) {
for (int i = 0; i < e->query.nb_queries; i++) {
res = (res64[i] < res) || (res >= 0 && res64[i] > res) ?
res64[i] : res;
res64 += e->query.status_stride;
}
} else if (e->query.nb_statuses) {
for (int i = 0; i < e->query.nb_queries; i++) {
res = (res32[i] < res) || (res >= 0 && res32[i] > res) ?
res32[i] : res;
res32 += e->query.status_stride;
}
}
if (data)
*data = qd;
if (status)
*status = res;
return 0;
}
void ff_vk_discard_exec_deps(FFVkExecContext *e)
{
FFVkQueueCtx *q = &e->queues[e->qf->cur_queue];
@ -648,6 +756,12 @@ int ff_vk_start_exec_recording(FFVulkanContext *s, FFVkExecContext *e)
return AVERROR_EXTERNAL;
}
if (e->query.pool) {
e->query.idx = e->qf->cur_queue*e->query.nb_queries;
vk->CmdResetQueryPool(e->bufs[e->qf->cur_queue], e->query.pool,
e->query.idx, e->query.nb_queries);
}
return 0;
}
@ -790,6 +904,7 @@ int ff_vk_submit_exec_queue(FFVulkanContext *s, FFVkExecContext *e)
for (int i = 0; i < e->sem_sig_cnt; i++)
*e->sem_sig_val_dst[i] += 1;
e->query.idx = e->qf->cur_queue*e->query.nb_queries;
q->submitted = 1;
return 0;
@ -1483,7 +1598,10 @@ static void free_exec_ctx(FFVulkanContext *s, FFVkExecContext *e)
vk->FreeCommandBuffers(s->hwctx->act_dev, e->pool, e->qf->nb_queues, e->bufs);
if (e->pool)
vk->DestroyCommandPool(s->hwctx->act_dev, e->pool, s->hwctx->alloc);
if (e->query.pool)
vk->DestroyQueryPool(s->hwctx->act_dev, e->query.pool, s->hwctx->alloc);
av_freep(&e->query.data);
av_freep(&e->bufs);
av_freep(&e->queues);
av_freep(&e->sem_sig);

View File

@ -168,6 +168,19 @@ typedef struct FFVkExecContext {
VkCommandBuffer *bufs;
FFVkQueueCtx *queues;
struct {
int idx;
VkQueryPool pool;
uint8_t *data;
int nb_queries;
int nb_results;
int nb_statuses;
int elem_64bits;
size_t data_per_queue;
int status_stride;
} query;
AVBufferRef ***deps;
int *nb_deps;
int *dep_alloc_size;
@ -371,6 +384,23 @@ void ff_vk_update_descriptor_set(FFVulkanContext *s, FFVulkanPipeline *pl,
int ff_vk_create_exec_ctx(FFVulkanContext *s, FFVkExecContext **ctx,
FFVkQueueFamilyCtx *qf);
/**
* Create a query pool for a command context.
* elem_64bits exists to troll driver devs for compliance. All results
* and statuses returned should be 32 bits, unless this is set, then it's 64bits.
*/
int ff_vk_create_exec_ctx_query_pool(FFVulkanContext *s, FFVkExecContext *e,
int nb_queries, VkQueryType type,
int elem_64bits, void *create_pnext);
/**
* Get results for query.
* Returns the status of the query.
* Sets *res to the status of the queries.
*/
int ff_vk_get_exec_ctx_query_results(FFVulkanContext *s, FFVkExecContext *e,
int query_idx, void **data, int64_t *status);
/**
* Begin recording to the command buffer. Previous execution must have been
* completed, which ff_vk_submit_exec_queue() will ensure.