1 /* 2 * This file is part of libplacebo. 3 * 4 * libplacebo is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * libplacebo is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #pragma once 19 #include "common.h" 20 21 // Since lots of vulkan operations need to be done lazily once the affected 22 // resources are no longer in use, provide an abstraction for tracking these. 23 // In practice, these are only checked and run when submitting new commands, so 24 // the actual execution may be delayed by a frame. 25 typedef void (*vk_cb)(void *p, void *arg); 26 27 struct vk_callback { 28 vk_cb run; 29 void *priv; 30 void *arg; 31 }; 32 33 // Associate a callback with the completion of all currently pending commands. 34 // This will essentially run once the device is completely idle. 35 void vk_dev_callback(struct vk_ctx *vk, vk_cb callback, 36 const void *priv, const void *arg); 37 38 // Helper wrapper around command buffers that also track dependencies, 39 // callbacks and synchronization primitives 40 // 41 // Thread-safety: Unsafe 42 struct vk_cmd { 43 struct vk_cmdpool *pool; // pool it was allocated from 44 VkQueue queue; // the submission queue (for recording/pending) 45 VkCommandBuffer buf; // the command buffer itself 46 VkFence fence; // the fence guards cmd buffer reuse 47 // The semaphores represent dependencies that need to complete before 48 // this command can be executed. These are *not* owned by the vk_cmd 49 PL_ARRAY(VkSemaphore) deps; 50 PL_ARRAY(VkPipelineStageFlags) depstages; 51 // The signals represent semaphores that fire once the command finishes 52 // executing. These are also not owned by the vk_cmd 53 PL_ARRAY(VkSemaphore) sigs; 54 // Since VkFences are useless, we have to manually track "callbacks" 55 // to fire once the VkFence completes. These are used for multiple purposes, 56 // ranging from garbage collection (resource deallocation) to fencing. 57 PL_ARRAY(struct vk_callback) callbacks; 58 // Abstract objects associated with this command. Can be used to 59 // selectively flush. 60 PL_ARRAY(const void *) objs; 61 }; 62 63 // Associate a callback with the completion of the current command. This 64 // function will be run once the command completes, or shortly thereafter. 65 void vk_cmd_callback(struct vk_cmd *cmd, vk_cb callback, 66 const void *priv, const void *arg); 67 68 // Associate a raw dependency for the current command. This semaphore must 69 // signal by the corresponding stage before the command may execute. 70 void vk_cmd_dep(struct vk_cmd *cmd, VkSemaphore dep, VkPipelineStageFlags stage); 71 72 // Associate an object with a command. This can be used to partially flush 73 // commands only involving the object in question. 74 void vk_cmd_obj(struct vk_cmd *cmd, const void *obj); 75 76 // Associate a raw signal with the current command. This semaphore will signal 77 // after the command completes. 78 void vk_cmd_sig(struct vk_cmd *cmd, VkSemaphore sig); 79 80 enum vk_wait_type { 81 VK_WAIT_NONE, // no synchronization needed 82 VK_WAIT_BARRIER, // synchronization via pipeline barriers 83 VK_WAIT_EVENT, // synchronization via events 84 }; 85 86 // Signal abstraction: represents an abstract synchronization mechanism. 87 // Internally, this may either resolve as a semaphore or an event depending 88 // on whether the appropriate conditions are met. 89 // 90 // Thread-safety: Unsafe 91 struct vk_signal; 92 93 // Generates a signal after the execution of all previous commands matching the 94 // given the pipeline stage. The signal is owned by the caller, and must be 95 // consumed with vk_cmd_wait or released with vk_signal_cancel in order to 96 // free the resources. 97 struct vk_signal *vk_cmd_signal(struct vk_ctx *vk, struct vk_cmd *cmd, 98 VkPipelineStageFlags stage); 99 100 // Consumes a previously generated signal. This signal must fire by the 101 // indicated stage before the command can run. This function takes over 102 // ownership of the signal (and the signal will be released/reused 103 // automatically) 104 // 105 // The return type indicates what the caller needs to do: 106 // VK_SIGNAL_NONE: no further handling needed, caller can use TOP_OF_PIPE 107 // VK_SIGNAL_BARRIER: caller must use pipeline barrier from last stage 108 // VK_SIGNAL_EVENT: caller must use VkEvent from last stage 109 // (never returned if out_event is NULL) 110 enum vk_wait_type vk_cmd_wait(struct vk_ctx *vk, struct vk_cmd *cmd, 111 struct vk_signal **sigptr, 112 VkPipelineStageFlags stage, 113 VkEvent *out_event); 114 115 // Destroys a currently pending signal, for example if the resource is no 116 // longer relevant. 117 void vk_signal_destroy(struct vk_ctx *vk, struct vk_signal **sig); 118 119 // Command pool / queue family hybrid abstraction 120 struct vk_cmdpool { 121 VkQueueFamilyProperties props; 122 int qf; // queue family index 123 VkCommandPool pool; 124 VkQueue *queues; 125 int num_queues; 126 int idx_queues; 127 // Command buffers associated with this queue. These are available for 128 // re-recording 129 PL_ARRAY(struct vk_cmd *) cmds; 130 }; 131 132 // Set up a vk_cmdpool corresponding to a queue family. 133 struct vk_cmdpool *vk_cmdpool_create(struct vk_ctx *vk, 134 VkDeviceQueueCreateInfo qinfo, 135 VkQueueFamilyProperties props); 136 137 void vk_cmdpool_destroy(struct vk_ctx *vk, struct vk_cmdpool *pool); 138 139 // Fetch a command buffer from a command pool and begin recording to it. 140 // Returns NULL on failure. 141 struct vk_cmd *vk_cmd_begin(struct vk_ctx *vk, struct vk_cmdpool *pool); 142 143 // Finish recording a command buffer and queue it for execution. This function 144 // takes over ownership of **cmd, and sets *cmd to NULL in doing so. 145 bool vk_cmd_queue(struct vk_ctx *vk, struct vk_cmd **cmd); 146 147 // Block until some commands complete executing. This is the only function that 148 // actually processes the callbacks. Will wait at most `timeout` nanoseconds 149 // for the completion of any command. The timeout may also be passed as 0, in 150 // which case this function will not block, but only poll for completed 151 // commands. Returns whether any forward progress was made. 152 // 153 // This does *not* flush any queued commands, forgetting to do so may result 154 // in infinite loops if waiting for the completion of callbacks that were 155 // never flushed! 156 bool vk_poll_commands(struct vk_ctx *vk, uint64_t timeout); 157 158 // Flush all currently queued commands. Returns whether successful. Failed 159 // commands will be implicitly dropped. 160 bool vk_flush_commands(struct vk_ctx *vk); 161 162 // Like `vk_flush_commands`, but only flushes up to the last command involving 163 // `obj`, inclusive. If `obj` is NULL, behaves as `vk_flush_commands`. 164 bool vk_flush_obj(struct vk_ctx *vk, const void *obj); 165 166 // Rotate through queues in each command pool. Call this once per frame, after 167 // submitting all of the command buffers for that frame. Calling this more 168 // often than that is possible but bad for performance. 169 void vk_rotate_queues(struct vk_ctx *vk); 170 171 // Wait until all commands are complete, i.e. the device is idle. This is 172 // basically equivalent to calling `vk_poll_commands` with a timeout of 173 // UINT64_MAX until it returns `false`. 174 void vk_wait_idle(struct vk_ctx *vk); 175