diff options
Diffstat (limited to 'video/out/vulkan/utils.h')
-rw-r--r-- | video/out/vulkan/utils.h | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/video/out/vulkan/utils.h b/video/out/vulkan/utils.h new file mode 100644 index 0000000000..5bde48089d --- /dev/null +++ b/video/out/vulkan/utils.h @@ -0,0 +1,153 @@ +#pragma once + +#include "video/out/vo.h" +#include "video/out/gpu/context.h" +#include "video/mp_image.h" + +#include "common.h" +#include "formats.h" + +#define VK_LOAD_PFN(name) PFN_##name pfn_##name = (PFN_##name) \ + vkGetInstanceProcAddr(vk->inst, #name); + +// Return a human-readable name for various struct mpvk_ctx enums +const char* vk_err(VkResult res); + +// Convenience macros to simplify a lot of common boilerplate +#define VK_ASSERT(res, str) \ + do { \ + if (res != VK_SUCCESS) { \ + MP_ERR(vk, str ": %s\n", vk_err(res)); \ + goto error; \ + } \ + } while (0) + +#define VK(cmd) \ + do { \ + MP_TRACE(vk, #cmd "\n"); \ + VkResult res ## __LINE__ = (cmd); \ + VK_ASSERT(res ## __LINE__, #cmd); \ + } while (0) + +// Uninits everything in the correct order +void mpvk_uninit(struct mpvk_ctx *vk); + +// Initialization functions: As a rule of thumb, these need to be called in +// this order, followed by vk_malloc_init, followed by RA initialization, and +// finally followed by vk_swchain initialization. + +// Create a vulkan instance. Returns VK_NULL_HANDLE on failure +bool mpvk_instance_init(struct mpvk_ctx *vk, struct mp_log *log, bool debug); + +// Generate a VkSurfaceKHR usable for video output. Returns VK_NULL_HANDLE on +// failure. Must be called after mpvk_instance_init. +bool mpvk_surface_init(struct vo *vo, struct mpvk_ctx *vk); + +// Find a suitable physical device for use with rendering and which supports +// the surface. +// name: only match a device with this name +// sw: also allow software/virtual devices +bool mpvk_find_phys_device(struct mpvk_ctx *vk, const char *name, bool sw); + +// Pick a suitable surface format that's supported by this physical device. +bool mpvk_pick_surface_format(struct mpvk_ctx *vk); + +struct mpvk_device_opts { + int queue_count; // number of queues to use +}; + +// Create a logical device and initialize the vk_cmdpools +bool mpvk_device_init(struct mpvk_ctx *vk, struct mpvk_device_opts opts); + +// Wait until all commands submitted to all queues have completed +void mpvk_pool_wait_idle(struct mpvk_ctx *vk, struct vk_cmdpool *pool); +void mpvk_dev_wait_idle(struct mpvk_ctx *vk); + +// Wait until at least one command submitted to any queue has completed, and +// process the callbacks. Good for event loops that need to delay until a +// command completes. Will block at most `timeout` nanoseconds. If used with +// 0, it only garbage collects completed commands without blocking. +void mpvk_pool_poll_cmds(struct mpvk_ctx *vk, struct vk_cmdpool *pool, + uint64_t timeout); +void mpvk_dev_poll_cmds(struct mpvk_ctx *vk, uint32_t timeout); + +// Since lots of vulkan operations need to be done lazily once the affected +// resources are no longer in use, provide an abstraction for tracking these. +// In practice, these are only checked and run when submitting new commands, so +// the actual execution may be delayed by a frame. +typedef void (*vk_cb)(void *priv, void *arg); + +struct vk_callback { + vk_cb run; + void *priv; + void *arg; // as a convenience, you also get to pass an arg for "free" +}; + +// Associate a callback with the completion of all currently pending commands. +// This will essentially run once the device is completely idle. +void vk_dev_callback(struct mpvk_ctx *vk, vk_cb callback, void *p, void *arg); + +#define MPVK_MAX_CMD_DEPS 8 + +// Helper wrapper around command buffers that also track dependencies, +// callbacks and synchronization primitives +struct vk_cmd { + struct vk_cmdpool *pool; // pool it was allocated from + VkCommandBuffer buf; + VkFence fence; // the fence guards cmd buffer reuse + VkSemaphore done; // the semaphore signals when execution is done + // The semaphores represent dependencies that need to complete before + // this command can be executed. These are *not* owned by the vk_cmd + VkSemaphore deps[MPVK_MAX_CMD_DEPS]; + VkPipelineStageFlags depstages[MPVK_MAX_CMD_DEPS]; + int num_deps; + // Since VkFences are useless, we have to manually track "callbacks" + // to fire once the VkFence completes. These are used for multiple purposes, + // ranging from garbage collection (resource deallocation) to fencing. + struct vk_callback *callbacks; + int num_callbacks; +}; + +// Associate a callback with the completion of the current command. This +// bool will be set to `true` once the command completes, or shortly thereafter. +void vk_cmd_callback(struct vk_cmd *cmd, vk_cb callback, void *p, void *arg); + +// Associate a dependency for the current command. This semaphore must signal +// by the corresponding stage before the command may execute. +void vk_cmd_dep(struct vk_cmd *cmd, VkSemaphore dep, + VkPipelineStageFlagBits depstage); + +#define MPVK_MAX_QUEUES 8 +#define MPVK_MAX_CMDS 64 + +// Command pool / queue family hybrid abstraction +struct vk_cmdpool { + VkQueueFamilyProperties props; + uint32_t qf; // queue family index + VkCommandPool pool; + VkQueue queues[MPVK_MAX_QUEUES]; + int qcount; + int qindex; + // Command buffers associated with this queue + struct vk_cmd cmds[MPVK_MAX_CMDS]; + int cindex; + int cindex_pending; +}; + +// Fetch the next command buffer from a command pool and begin recording to it. +// Returns NULL on failure. +struct vk_cmd *vk_cmd_begin(struct mpvk_ctx *vk, struct vk_cmdpool *pool); + +// Finish the currently recording command buffer and submit it for execution. +// If `done` is not NULL, it will be set to a semaphore that will signal once +// the command completes. (And MUST have a corresponding semaphore wait) +// Returns whether successful. +bool vk_cmd_submit(struct mpvk_ctx *vk, struct vk_cmd *cmd, VkSemaphore *done); + +// Rotate the queues for each vk_cmdpool. Call this once per frame to ensure +// good parallelism between frames when using multiple queues +void vk_cmd_cycle_queues(struct mpvk_ctx *vk); + +// Predefined structs for a simple non-layered, non-mipped image +extern const VkImageSubresourceRange vk_range; +extern const VkImageSubresourceLayers vk_layers; |