diff options
author | Lynne <dev@lynne.ee> | 2021-11-19 07:46:15 +0100 |
---|---|---|
committer | Lynne <dev@lynne.ee> | 2021-11-19 13:44:45 +0100 |
commit | d1133e8c44f457f0698c48f2efcedbd8626b3cee (patch) | |
tree | 034ac8f51d6225eca4a9408c30be20335adced06 /libavutil/vulkan.h | |
parent | 8c150d3d9794c29a54bbdf2f2a88066277c7197e (diff) | |
download | ffmpeg-d1133e8c44f457f0698c48f2efcedbd8626b3cee.tar.gz |
lavu/vulkan: move common Vulkan code from libavfilter to libavutil
Diffstat (limited to 'libavutil/vulkan.h')
-rw-r--r-- | libavutil/vulkan.h | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h new file mode 100644 index 0000000000..14c69ce015 --- /dev/null +++ b/libavutil/vulkan.h @@ -0,0 +1,413 @@ +/* + * 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 + */ + +#ifndef AVUTIL_VULKAN_H +#define AVUTIL_VULKAN_H + +#define VK_NO_PROTOTYPES +#define VK_ENABLE_BETA_EXTENSIONS + +#include "pixdesc.h" +#include "bprint.h" +#include "hwcontext.h" +#include "hwcontext_vulkan.h" +#include "vulkan_functions.h" + +#define FF_VK_DEFAULT_USAGE_FLAGS (VK_IMAGE_USAGE_SAMPLED_BIT | \ + VK_IMAGE_USAGE_STORAGE_BIT | \ + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | \ + VK_IMAGE_USAGE_TRANSFER_DST_BIT) + +/* GLSL management macros */ +#define INDENT(N) INDENT_##N +#define INDENT_0 +#define INDENT_1 INDENT_0 " " +#define INDENT_2 INDENT_1 INDENT_1 +#define INDENT_3 INDENT_2 INDENT_1 +#define INDENT_4 INDENT_3 INDENT_1 +#define INDENT_5 INDENT_4 INDENT_1 +#define INDENT_6 INDENT_5 INDENT_1 +#define C(N, S) INDENT(N) #S "\n" +#define GLSLC(N, S) av_bprintf(&shd->src, C(N, S)) +#define GLSLA(...) av_bprintf(&shd->src, __VA_ARGS__) +#define GLSLF(N, S, ...) av_bprintf(&shd->src, C(N, S), __VA_ARGS__) +#define GLSLD(D) GLSLC(0, ); \ + av_bprint_append_data(&shd->src, D, strlen(D)); \ + GLSLC(0, ) + +/* Helper, pretty much every Vulkan return value needs to be checked */ +#define RET(x) \ + do { \ + if ((err = (x)) < 0) \ + goto fail; \ + } while (0) + +typedef struct FFVkSPIRVShader { + const char *name; /* Name for id/debugging purposes */ + AVBPrint src; + int local_size[3]; /* Compute shader workgroup sizes */ + VkPipelineShaderStageCreateInfo shader; +} FFVkSPIRVShader; + +typedef struct FFVkSampler { + VkSampler sampler[4]; +} FFVkSampler; + +typedef struct FFVulkanDescriptorSetBinding { + const char *name; + VkDescriptorType type; + const char *mem_layout; /* Storage images (rgba8, etc.) and buffers (std430, etc.) */ + const char *mem_quali; /* readonly, writeonly, etc. */ + const char *buf_content; /* For buffers */ + uint32_t dimensions; /* Needed for e.g. sampler%iD */ + uint32_t elems; /* 0 - scalar, 1 or more - vector */ + VkShaderStageFlags stages; + FFVkSampler *sampler; /* Sampler to use for all elems */ + void *updater; /* Pointer to VkDescriptor*Info */ +} FFVulkanDescriptorSetBinding; + +typedef struct FFVkBuffer { + VkBuffer buf; + VkDeviceMemory mem; + VkMemoryPropertyFlagBits flags; +} FFVkBuffer; + +typedef struct FFVkQueueFamilyCtx { + int queue_family; + int nb_queues; + int cur_queue; + int actual_queues; +} FFVkQueueFamilyCtx; + +typedef struct FFVulkanPipeline { + FFVkQueueFamilyCtx *qf; + + VkPipelineBindPoint bind_point; + + /* Contexts */ + VkPipelineLayout pipeline_layout; + VkPipeline pipeline; + + /* Shaders */ + FFVkSPIRVShader **shaders; + int shaders_num; + + /* Push consts */ + VkPushConstantRange *push_consts; + int push_consts_num; + + /* Descriptors */ + VkDescriptorSetLayout *desc_layout; + VkDescriptorPool desc_pool; + VkDescriptorSet *desc_set; + void **desc_staging; + VkDescriptorSetLayoutBinding **desc_binding; + VkDescriptorUpdateTemplate *desc_template; + int *desc_set_initialized; + int desc_layout_num; + int descriptor_sets_num; + int total_descriptor_sets; + int pool_size_desc_num; + + /* Temporary, used to store data in between initialization stages */ + VkDescriptorUpdateTemplateCreateInfo *desc_template_info; + VkDescriptorPoolSize *pool_size_desc; +} FFVulkanPipeline; + +typedef struct FFVkQueueCtx { + VkFence fence; + VkQueue queue; + + /* Buffer dependencies */ + AVBufferRef **buf_deps; + int nb_buf_deps; + int buf_deps_alloc_size; + + /* Frame dependencies */ + AVFrame **frame_deps; + int nb_frame_deps; + int frame_deps_alloc_size; +} FFVkQueueCtx; + +typedef struct FFVkExecContext { + FFVkQueueFamilyCtx *qf; + + VkCommandPool pool; + VkCommandBuffer *bufs; + FFVkQueueCtx *queues; + + AVBufferRef ***deps; + int *nb_deps; + int *dep_alloc_size; + + FFVulkanPipeline *bound_pl; + + VkSemaphore *sem_wait; + int sem_wait_alloc; /* Allocated sem_wait */ + int sem_wait_cnt; + + uint64_t *sem_wait_val; + int sem_wait_val_alloc; + + VkPipelineStageFlagBits *sem_wait_dst; + int sem_wait_dst_alloc; /* Allocated sem_wait_dst */ + + VkSemaphore *sem_sig; + int sem_sig_alloc; /* Allocated sem_sig */ + int sem_sig_cnt; + + uint64_t *sem_sig_val; + int sem_sig_val_alloc; + + uint64_t **sem_sig_val_dst; + int sem_sig_val_dst_alloc; +} FFVkExecContext; + +typedef struct FFVulkanContext { + const AVClass *class; /* Filters and encoders use this */ + + FFVulkanFunctions vkfn; + FFVulkanExtensions extensions; + VkPhysicalDeviceProperties props; + VkPhysicalDeviceMemoryProperties mprops; + + AVBufferRef *device_ref; + AVHWDeviceContext *device; + AVVulkanDeviceContext *hwctx; + + AVBufferRef *frames_ref; + AVHWFramesContext *frames; + AVVulkanFramesContext *hwfc; + + /* Properties */ + int output_width; + int output_height; + enum AVPixelFormat output_format; + enum AVPixelFormat input_format; + + /* Samplers */ + FFVkSampler **samplers; + int samplers_num; + + /* Exec contexts */ + FFVkExecContext **exec_ctx; + int exec_ctx_num; + + /* Pipelines (each can have 1 shader of each type) */ + FFVulkanPipeline **pipelines; + int pipelines_num; + + void *scratch; /* Scratch memory used only in functions */ + unsigned int scratch_size; +} FFVulkanContext; + +/* Identity mapping - r = r, b = b, g = g, a = a */ +extern const VkComponentMapping ff_comp_identity_map; + +/** + * Converts Vulkan return values to strings + */ +const char *ff_vk_ret2str(VkResult res); + +/** + * Returns 1 if the image is any sort of supported RGB + */ +int ff_vk_mt_is_np_rgb(enum AVPixelFormat pix_fmt); + +/** + * Gets the glsl format string for a pixel format + */ +const char *ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt); + +/** + * Initialize a queue family with a specific number of queues. + * If nb_queues == 0, use however many queues the queue family has. + */ +void ff_vk_qf_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, + VkQueueFlagBits dev_family, int nb_queues); + +/** + * Rotate through the queues in a queue family. + */ +void ff_vk_qf_rotate(FFVkQueueFamilyCtx *qf); + +/** + * Create a Vulkan sampler, will be auto-freed in ff_vk_filter_uninit() + */ +FFVkSampler *ff_vk_init_sampler(FFVulkanContext *s, int unnorm_coords, + VkFilter filt); + +/** + * Create an imageview. + * Guaranteed to remain alive until the queue submission has finished executing, + * and will be destroyed after that. + */ +int ff_vk_create_imageview(FFVulkanContext *s, FFVkExecContext *e, + VkImageView *v, VkImage img, VkFormat fmt, + const VkComponentMapping map); + +/** + * Define a push constant for a given stage into a pipeline. + * Must be called before the pipeline layout has been initialized. + */ +int ff_vk_add_push_constant(FFVulkanPipeline *pl, int offset, int size, + VkShaderStageFlagBits stage); + +/** + * Inits a pipeline. Everything in it will be auto-freed when calling + * ff_vk_filter_uninit(). + */ +FFVulkanPipeline *ff_vk_create_pipeline(FFVulkanContext *s, FFVkQueueFamilyCtx *qf); + +/** + * Inits a shader for a specific pipeline. Will be auto-freed on uninit. + */ +FFVkSPIRVShader *ff_vk_init_shader(FFVulkanPipeline *pl, const char *name, + VkShaderStageFlags stage); + +/** + * Writes the workgroup size for a shader. + */ +void ff_vk_set_compute_shader_sizes(FFVkSPIRVShader *shd, int local_size[3]); + +/** + * Adds a descriptor set to the shader and registers them in the pipeline. + */ +int ff_vk_add_descriptor_set(FFVulkanContext *s, FFVulkanPipeline *pl, + FFVkSPIRVShader *shd, FFVulkanDescriptorSetBinding *desc, + int num, int only_print_to_shader); + +/** + * Compiles the shader, entrypoint must be set to "main". + */ +int ff_vk_compile_shader(FFVulkanContext *s, FFVkSPIRVShader *shd, + const char *entrypoint); + +/** + * Pretty print shader, mainly used by shader compilers. + */ +void ff_vk_print_shader(void *ctx, FFVkSPIRVShader *shd, int prio); + +/** + * Initializes the pipeline layout after all shaders and descriptor sets have + * been finished. + */ +int ff_vk_init_pipeline_layout(FFVulkanContext *s, FFVulkanPipeline *pl); + +/** + * Initializes a compute pipeline. Will pick the first shader with the + * COMPUTE flag set. + */ +int ff_vk_init_compute_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl); + +/** + * Updates a descriptor set via the updaters defined. + * Can be called immediately after pipeline creation, but must be called + * at least once before queue submission. + */ +void ff_vk_update_descriptor_set(FFVulkanContext *s, FFVulkanPipeline *pl, + int set_id); + +/** + * Init an execution context for command recording and queue submission. + * WIll be auto-freed on uninit. + */ +int ff_vk_create_exec_ctx(FFVulkanContext *s, FFVkExecContext **ctx, + FFVkQueueFamilyCtx *qf); + +/** + * Begin recording to the command buffer. Previous execution must have been + * completed, which ff_vk_submit_exec_queue() will ensure. + */ +int ff_vk_start_exec_recording(FFVulkanContext *s, FFVkExecContext *e); + +/** + * Add a command to bind the completed pipeline and its descriptor sets. + * Must be called after ff_vk_start_exec_recording() and before submission. + */ +void ff_vk_bind_pipeline_exec(FFVulkanContext *s, FFVkExecContext *e, + FFVulkanPipeline *pl); + +/** + * Updates push constants. + * Must be called after binding a pipeline if any push constants were defined. + */ +void ff_vk_update_push_exec(FFVulkanContext *s, FFVkExecContext *e, + VkShaderStageFlagBits stage, int offset, + size_t size, void *src); + +/** + * Gets the command buffer to use for this submission from the exe context. + */ +VkCommandBuffer ff_vk_get_exec_buf(FFVkExecContext *e); + +/** + * Adds a generic AVBufferRef as a queue depenency. + */ +int ff_vk_add_dep_exec_ctx(FFVulkanContext *s, FFVkExecContext *e, + AVBufferRef **deps, int nb_deps); + +/** + * Discards all queue dependencies + */ +void ff_vk_discard_exec_deps(FFVkExecContext *e); + +/** + * Adds a frame as a queue dependency. This also manages semaphore signalling. + * Must be called before submission. + */ +int ff_vk_add_exec_dep(FFVulkanContext *s, FFVkExecContext *e, AVFrame *frame, + VkPipelineStageFlagBits in_wait_dst_flag); + +/** + * Submits a command buffer to the queue for execution. + * Will block until execution has finished in order to simplify resource + * management. + */ +int ff_vk_submit_exec_queue(FFVulkanContext *s, FFVkExecContext *e); + +/** + * Create a VkBuffer with the specified parameters. + */ +int ff_vk_create_buf(FFVulkanContext *s, FFVkBuffer *buf, size_t size, + VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags); + +/** + * Maps the buffer to userspace. Set invalidate to 1 if reading the contents + * is necessary. + */ +int ff_vk_map_buffers(FFVulkanContext *s, FFVkBuffer *buf, uint8_t *mem[], + int nb_buffers, int invalidate); + +/** + * Unmaps the buffer from userspace. Set flush to 1 to write and sync. + */ +int ff_vk_unmap_buffers(FFVulkanContext *s, FFVkBuffer *buf, int nb_buffers, + int flush); + +/** + * Frees a buffer. + */ +void ff_vk_free_buf(FFVulkanContext *s, FFVkBuffer *buf); + +/** + * Frees the main Vulkan context. + */ +void ff_vk_uninit(FFVulkanContext *s); + +#endif /* AVUTIL_VULKAN_H */ |