vOOlkan
An object oriented approach to Vulkan
CommandBuffer.h
Go to the documentation of this file.
1#ifndef VULKAN_COMMANDBUFFER
2#define VULKAN_COMMANDBUFFER
3
4#include <vulkan/vulkan.h>
5
6#include <functional>
7#include <utility>
8#include <concepts>
9
10#include "CommandBufferPool.h"
11#include "LogicalDevice.h"
12#include "RenderPass.h"
13#include "Framebuffer.h"
14#include "Pipeline.h"
15#include "VulkanException.h"
16#include "Fence.h"
17#include "Queue.h"
18
19
20namespace Vulkan { class CommandBuffer; }
21
22
23class Vulkan::CommandBuffer {
24public:
25
26 CommandBuffer(const LogicalDevice& virtualGpu, const CommandBufferPool& commandBufferPool) : virtualGpu{ &virtualGpu }, commandBufferPool{ &commandBufferPool } {
27 allocateCommandBuffer(virtualGpu, commandBufferPool);
28 reset();
29 }
30
31
45 template<typename... Args, template<typename...> class... Command> requires (std::same_as<Command<int>, std::tuple<int>> && ...)
46 CommandBuffer(const LogicalDevice& virtualGpu, const CommandBufferPool& commandBufferPool, const PipelineOptions::RenderPass& renderPass, const Framebuffer& framebuffer, const Pipeline& pipeline, Command<void(*)(VkCommandBuffer, Args...), Args...>&&... commands) : virtualGpu{ virtualGpu }, commandBufferPool{ commandBufferPool } {
47 allocateCommandBuffer(virtualGpu, commandBufferPool);
48 reset(renderPass, framebuffer, pipeline);
49
50 //this is tricky... call the function addCommand and pass as arguments (perfect forwarding) the objects in the each tuple received as argument
51 (std::apply([this]<typename... Args>(Args&&... args) {
52 this->addCommand(std::forward<Args>(args)...);
53 }, commands), ...);
54
55 endCommand();
56 }
57
58
59 CommandBuffer(const CommandBuffer&) = delete;
60 CommandBuffer& operator=(const CommandBuffer&) = delete;
61
62 CommandBuffer(CommandBuffer&& movedFrom) noexcept : CommandBuffer{} {
63 std::swap(commandBuffer, movedFrom.commandBuffer);
64 std::swap(virtualGpu, movedFrom.virtualGpu);
65 std::swap(commandBufferPool, movedFrom.commandBufferPool);
66 }
67
68 CommandBuffer& operator=(CommandBuffer&&) = delete;
69
70 ~CommandBuffer() {
71 if (commandBuffer != VK_NULL_HANDLE) {
72 vkFreeCommandBuffers(+*virtualGpu, +*commandBufferPool, 1, &commandBuffer);
73 }
74 }
75
76
77 const VkCommandBuffer& operator+() {
78 return commandBuffer;
79 }
80
81
82 //TODO make it possible to specify Viewport and Scissor and clear color
90 CommandBuffer& reset(const PipelineOptions::RenderPass& renderPass, const Framebuffer& framebuffer) {
91 //reset command buffer
92 vkResetCommandBuffer(commandBuffer, 0);
93
94 //initialize command buffer
95 VkCommandBufferBeginInfo beginInfo{};
96 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
97 beginInfo.flags = 0;
98 beginInfo.pInheritanceInfo = nullptr;
99 if (VkResult result = vkBeginCommandBuffer(commandBuffer, &beginInfo); result != VK_SUCCESS) {
100 throw VulkanException("Failed to begin recording command buffer!", result);
101 }
102
103 //set render pass
104 VkRenderPassBeginInfo renderPassInfo{};
105 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
106 renderPassInfo.renderPass = +renderPass;
107 renderPassInfo.framebuffer = +framebuffer;
108 renderPassInfo.renderArea.offset = { 0, 0 };
109 renderPassInfo.renderArea.extent = VkExtent2D{ framebuffer.getResolution().first, framebuffer.getResolution().second };
110 VkClearValue clearvalues[] = { {{0.0f, 0.0f, 0.0f, 1.0f}}, {1.0f, 0} };
111 renderPassInfo.clearValueCount = renderPass.getAttachmentCount();
112 renderPassInfo.pClearValues = clearvalues;
113 vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
114
115 //set viewport
116 VkViewport viewport{};
117 viewport.x = 0.0f;
118 viewport.y = 0.0f;
119 viewport.width = static_cast<float>(framebuffer.getResolution().first);
120 viewport.height = static_cast<float>(framebuffer.getResolution().second);
121 viewport.minDepth = 0.0f;
122 viewport.maxDepth = 1.0f;
123 vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
124
125 //set scissors
126 VkRect2D scissor{};
127 scissor.offset = { 0, 0 };
128 scissor.extent = VkExtent2D{ framebuffer.getResolution().first, framebuffer.getResolution().second };
129 vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
130
131 return *this;
132 }
133
134
135
139 CommandBuffer& reset() {
140 //reset command buffer
141 vkResetCommandBuffer(commandBuffer, 0);
142
143 //initialize command buffer
144 VkCommandBufferBeginInfo beginInfo{};
145 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
146 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
147 beginInfo.pInheritanceInfo = nullptr;
148
149 if (VkResult result = vkBeginCommandBuffer(commandBuffer, &beginInfo); result != VK_SUCCESS) {
150 throw VulkanException("Failed to begin recording command buffer!", result);
151 }
152
153 return *this;
154 }
155
156
175 template<typename... Args, typename... Params>
176 CommandBuffer& addCommand(void(*command)(VkCommandBuffer, Params...), Args&&... args) {
177 command(commandBuffer, std::forward<Args>(args)...);
178 return *this;
179 }
180
181
189 template<typename... Args, template<typename...> class... Command> requires (std::same_as<Command<>, std::tuple<>> && ...)
190 CommandBuffer& addCommands(Command<void(*)(VkCommandBuffer, Args...), Args...>&&... commands) {
191 //this is tricky... call the function addCommand and pass as arguments (perfect forwarding) the objects in the each tuple received as argument
192 (std::apply([this]<typename... Args>(Args&&... args) {
193 this->addCommand(std::forward<Args>(args)...);
194 }, commands), ...);
195 return *this;
196 }
197
198
199 CommandBuffer& endCommand() {
200 if (VkResult result = vkEndCommandBuffer(commandBuffer); result != VK_SUCCESS) {
201 throw VulkanException("Failed to record command buffer!", result);
202 }
203
204 return *this;
205 }
206
207
208 CommandBuffer& sendCommand(Queue queue, const std::vector<VkSemaphore>& waitSemaphores, const std::vector<VkSemaphore>& signalSemaphores, const std::vector<VkPipelineStageFlags>& waitStages, const SynchronizationPrimitives::Fence& fence) {
209 VkSubmitInfo submitInfo{};
210 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
211 submitInfo.waitSemaphoreCount = waitSemaphores.size();
212 submitInfo.pWaitSemaphores = waitSemaphores.size() != 0 ? waitSemaphores.data() : nullptr;
213 submitInfo.pWaitDstStageMask = waitStages.size() != 0 ? waitStages.data() : nullptr;
214 submitInfo.commandBufferCount = 1;
215 submitInfo.pCommandBuffers = &commandBuffer;
216 submitInfo.signalSemaphoreCount = signalSemaphores.size();
217 submitInfo.pSignalSemaphores = signalSemaphores.size() != 0 ? signalSemaphores.data() : nullptr;
218
219 if (VkResult result = vkQueueSubmit(+queue, 1, &submitInfo, +fence); result != VK_SUCCESS) {
220 throw VulkanException{ "Failed to submit the command buffer for the current frame", result };
221 }
222
223 return *this;
224 }
225
226
227 CommandBuffer& sendCommand(Queue queue) {
228 VkSubmitInfo submitInfo{};
229 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
230 submitInfo.waitSemaphoreCount = 0;
231 submitInfo.pWaitSemaphores = nullptr;
232 submitInfo.pWaitDstStageMask = nullptr;
233 submitInfo.commandBufferCount = 1;
234 submitInfo.pCommandBuffers = &commandBuffer;
235 submitInfo.signalSemaphoreCount = 0;
236 submitInfo.pSignalSemaphores = nullptr;
237
238 if (VkResult result = vkQueueSubmit(+queue, 1, &submitInfo, VK_NULL_HANDLE); result != VK_SUCCESS) {
239 throw VulkanException{ "Failed to submit the command buffer for the current frame", result };
240 }
241
242 return *this;
243 }
244
245
246private:
247
248 //Used only for move ctor
249 CommandBuffer() : commandBuffer{ VK_NULL_HANDLE }, commandBufferPool{ nullptr }, virtualGpu{ nullptr }{}
250
251 void allocateCommandBuffer(const LogicalDevice& virtualGpu, const CommandBufferPool& commandBufferPool) {
252 VkCommandBufferAllocateInfo allocInfo{};
253 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
254 allocInfo.commandPool = +commandBufferPool;
255 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
256 allocInfo.commandBufferCount = 1;
257
258 if (VkResult result = vkAllocateCommandBuffers(+virtualGpu, &allocInfo, &commandBuffer); result != VK_SUCCESS) {
259 throw VulkanException("Failed to allocate command buffers!", result);
260 }
261 }
262
263
264 VkCommandBuffer commandBuffer;
265 CommandBufferPool const* commandBufferPool;
266 LogicalDevice const * virtualGpu;
267};
268
269
270#endif
Position operator+(Position origin, DeltaSpace spaceCovered)
Definition: Foundations.h:307
Types of queue families.
Definition: Animations.h:17