Chronos 0.0
A advanced 2D rendering and animation system
Loading...
Searching...
No Matches
helper.cpp
Go to the documentation of this file.
1/*
2Copyright (c) 2024 Rahul Satish Vadhyar
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20SOFTWARE.
21*/
22#include "helper.hpp"
23
25 VkCommandPool commandPool, VkDevice device)
26{
27 // used for staging buffers. We need a temproary command buffer to copy the
28 // data to the device buffer
29 VkCommandBufferAllocateInfo allocInfo {};
30 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
31 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
32 allocInfo.commandPool = commandPool;
33 allocInfo.commandBufferCount = 1;
34
35 VkCommandBuffer commandBuffer;
36 vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
37
38 VkCommandBufferBeginInfo beginInfo {};
39 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
40 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
41
42 vkBeginCommandBuffer(commandBuffer, &beginInfo);
43
44 return commandBuffer;
45}
46
47void Chronos::Engine::endSingleTimeCommands(VkCommandBuffer* commandBuffer,
48 Chronos::Engine::Device device, VkCommandPool commandPool)
49{
50 vkEndCommandBuffer(*commandBuffer);
51
52 VkSubmitInfo submitInfo {};
53 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
54 submitInfo.commandBufferCount = 1;
55 submitInfo.pCommandBuffers = commandBuffer;
56
57 vkQueueSubmit(device.graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
58 vkQueueWaitIdle(device.graphicsQueue);
59
60 vkFreeCommandBuffers(device.device, commandPool, 1, commandBuffer);
61}
62
63uint32_t Chronos::Engine::findMemoryType(uint32_t typeFilter,
64 VkMemoryPropertyFlags properties, VkPhysicalDevice physicalDevice)
65{
66 VkPhysicalDeviceMemoryProperties memProperties;
67 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
68 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
69 if ((typeFilter & (1 << i))
70 && (memProperties.memoryTypes[i].propertyFlags & properties)
71 == properties) {
72 return i;
73 }
74 }
75 throw std::runtime_error("failed to find suitable memory type!");
76}
77
79 VkDeviceSize size, VkBufferUsageFlags usage,
80 VkMemoryPropertyFlags properties, VkBuffer* buffer,
81 VkDeviceMemory* bufferMemory)
82{
83 VkBufferCreateInfo bufferInfo {};
84 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
85 bufferInfo.size = size;
86 bufferInfo.usage = usage;
87 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
88
89 if (vkCreateBuffer(device.device, &bufferInfo, nullptr, buffer)
90 != VK_SUCCESS) {
91 throw std::runtime_error("failed to create buffer!");
92 }
93
94 VkMemoryRequirements memRequirements;
95 vkGetBufferMemoryRequirements(device.device, *buffer, &memRequirements);
96
97 VkMemoryAllocateInfo allocInfo {};
98 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
99 allocInfo.allocationSize = memRequirements.size;
100 allocInfo.memoryTypeIndex = findMemoryType(
101 memRequirements.memoryTypeBits, properties, device.physicalDevice);
102
103 if (vkAllocateMemory(device.device, &allocInfo, nullptr, bufferMemory)
104 != VK_SUCCESS) {
105 throw std::runtime_error("failed to allocate buffer memory!");
106 }
107
108 vkBindBufferMemory(device.device, *buffer, *bufferMemory, 0);
109}
110
112 VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size,
113 VkCommandPool commandPool)
114{
115 // copies data from a buffer to another buffer
116 VkCommandBuffer commandBuffer
118 VkBufferCopy copyRegion {};
119 copyRegion.srcOffset = 0;
120 copyRegion.dstOffset = 0;
121 copyRegion.size = size;
122 vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
123 Chronos::Engine::endSingleTimeCommands(&commandBuffer, device, commandPool);
124}
125
127 VkPhysicalDevice device, VkSurfaceKHR surface)
128{
130 uint32_t queueFamilyCount = 0;
131 vkGetPhysicalDeviceQueueFamilyProperties(
132 device, &queueFamilyCount, nullptr);
133 // get the queue families
134 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
135 vkGetPhysicalDeviceQueueFamilyProperties(
136 device, &queueFamilyCount, queueFamilies.data());
137 // check if the queue family has the required properties
138 int i = 0;
139 for (const auto& queueFamily : queueFamilies) {
140 if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
141 indices.graphicsFamily = i;
142 }
143 VkBool32 presentSupport = false;
144 vkGetPhysicalDeviceSurfaceSupportKHR(
145 device, i, surface, &presentSupport);
146 if (presentSupport) {
147 indices.presentFamily = i;
148 }
149 if (indices.isComplete()) {
150 break;
151 }
152 i++;
153 }
154 return indices;
155}
156
158 Chronos::Engine::Device device, VkSurfaceKHR surface)
159{
160 VkCommandPool commandPool;
161 QueueFamilyIndices queueFamilyIndices
163 VkCommandPoolCreateInfo poolInfo {};
164 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
165 poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
166 poolInfo.flags
167 = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; // Optional
168 if (vkCreateCommandPool(device.device, &poolInfo, nullptr, &commandPool)
169 != VK_SUCCESS) {
170 throw std::runtime_error("failed to create command pool!");
171 }
172 return commandPool;
173}
174
176 SwapChain swapChain, VkImageLayout initalLayout, VkImageLayout finalLayout,
177 VkImageLayout msaaFinalLayout, bool msaa, bool clearFramebuffer,
178 bool dependency)
179{
180 VkRenderPass renderPass;
181 VkAttachmentDescription colorAttachment {};
182 colorAttachment.format = swapChain.swapChainImageFormat;
183 // if using msaa, set the bits
184 if (msaa && device.msaaSamples != VK_SAMPLE_COUNT_1_BIT) {
185 colorAttachment.samples = device.msaaSamples;
186 } else {
187 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
188 }
189 // when using multiple render passes, we dont want to clear the framebuffer
190 // each pass
191 if (clearFramebuffer) {
192 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
193 } else {
194 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
195 }
196 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
197 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
198 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
199 colorAttachment.initialLayout = initalLayout; // initial layout of image
200 colorAttachment.finalLayout
201 = finalLayout; // final layout of image if not using msaa
202
203 VkAttachmentDescription colorAttachmentResolve {};
204 colorAttachmentResolve.format = swapChain.swapChainImageFormat;
205 colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
206 colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
207 colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
208 colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
209 colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
210 colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
211 colorAttachmentResolve.finalLayout
212 = msaaFinalLayout; // final layout if using msaa
213
214 VkAttachmentReference colorAttachmentRef {};
215 colorAttachmentRef.attachment = 0;
216 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
217
218 VkAttachmentReference colorAttachmentResolveRef {};
219 colorAttachmentResolveRef.attachment = 1;
220 colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
221
222 VkSubpassDescription subpass {};
223 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
224 subpass.colorAttachmentCount = 1;
225 subpass.pColorAttachments = &colorAttachmentRef;
226 if (msaa && device.msaaSamples != VK_SAMPLE_COUNT_1_BIT) {
227 subpass.pResolveAttachments = &colorAttachmentResolveRef;
228 } else {
229 subpass.pResolveAttachments = nullptr;
230 }
231 // if we are using multiple render passes, then we need to wait for other
232 // commands to finish
233 VkSubpassDependency subpassDependencies[2];
234 subpassDependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
235 subpassDependencies[0].dstSubpass = 0;
236 subpassDependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
237 subpassDependencies[0].dstStageMask
238 = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
239 subpassDependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
240 subpassDependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
241 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
242 subpassDependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
243
244 subpassDependencies[1].srcSubpass = 0;
245 subpassDependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
246 subpassDependencies[1].srcStageMask
247 = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
248 subpassDependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
249 subpassDependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
250 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
251 subpassDependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
252 subpassDependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
253
254 std::vector<VkAttachmentDescription> attachments = { colorAttachment };
255 if (msaa && device.msaaSamples != VK_SAMPLE_COUNT_1_BIT) {
256 attachments.push_back(colorAttachmentResolve);
257 }
258
259 VkRenderPassCreateInfo renderPassInfo {};
260 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
261 renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
262 renderPassInfo.pAttachments = attachments.data();
263 renderPassInfo.subpassCount = 1;
264 renderPassInfo.pSubpasses = &subpass;
265 if (dependency) {
266 renderPassInfo.dependencyCount = 2;
267 renderPassInfo.pDependencies = subpassDependencies;
268 }
269 if (vkCreateRenderPass(device.device, &renderPassInfo, nullptr, &renderPass)
270 != VK_SUCCESS) {
271 throw std::runtime_error("failed to create render pass!");
272 }
273 return renderPass;
274}
275
276std::vector<VkFramebuffer> Chronos::Engine::createFramebuffer(
277 Chronos::Engine::Device device, SwapChain swapChain,
278 VkRenderPass renderPass, bool msaa)
279{
280 std::vector<VkFramebuffer> framebuffers;
281 framebuffers.resize(swapChain.swapChainImageViews.size());
282 for (size_t i = 0; i < swapChain.swapChainImageViews.size(); i++) {
283 std::vector<VkImageView> attachments;
284 if (msaa && device.msaaSamples != VK_SAMPLE_COUNT_1_BIT) {
285 attachments = { swapChain.colorImageView,
286 swapChain.swapChainImageViews[i] };
287 } else {
288 attachments = { swapChain.swapChainImageViews[i] };
289 }
290 VkFramebufferCreateInfo framebufferInfo {};
291 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
292 framebufferInfo.renderPass = renderPass;
293 framebufferInfo.attachmentCount
294 = static_cast<uint32_t>(attachments.size());
295 framebufferInfo.pAttachments = attachments.data();
296 framebufferInfo.width = swapChain.swapChainExtent.width;
297 framebufferInfo.height = swapChain.swapChainExtent.height;
298 framebufferInfo.layers = 1;
299 if (vkCreateFramebuffer(
300 device.device, &framebufferInfo, nullptr, &framebuffers[i])
301 != VK_SUCCESS) {
302 throw std::runtime_error("failed to create framebuffer!");
303 }
304 }
305 return framebuffers;
306}
307
308std::vector<VkCommandBuffer> Chronos::Engine::createCommandBuffer(
310 VkCommandPool commandPool)
311{
312 std::vector<VkCommandBuffer> commandBuffers;
313 commandBuffers.resize(swapChain.swapChainImageViews.size());
314 VkCommandBufferAllocateInfo allocInfo {};
315 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
316 allocInfo.commandPool = commandPool;
317 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
318 allocInfo.commandBufferCount = static_cast<uint32_t>(commandBuffers.size());
319 if (vkAllocateCommandBuffers(
320 device.device, &allocInfo, commandBuffers.data())
321 != VK_SUCCESS) {
322 throw std::runtime_error("failed to allocate command buffers!");
323 }
324 return commandBuffers;
325}
This initializes, manages and destroys the logical and physical devices(GPU).
Definition device.hpp:47
VkDevice device
This is the logical device that is used by Vulkan.
Definition device.hpp:52
VkPhysicalDevice physicalDevice
This is the physical device that is used by Vulkan.
Definition device.hpp:60
VkSampleCountFlagBits msaaSamples
This sets the MSAA samples count.
Definition device.hpp:80
VkQueue graphicsQueue
This is the queue that is used for graphics rendering.
Definition device.hpp:65
std::vector< VkImageView > swapChainImageViews
Image views of the swapchain textures(images, aka window)
VkExtent2D swapChainExtent
Dimenisons of the current swapchain.
VkImageView colorImageView
image view of the color attachement
VkFormat swapChainImageFormat
Chosen swapchain image format.
Contains various common functions used by other classes in the Engine namespace.
VkCommandBuffer beginSingleTimeCommands(VkCommandPool commandPool, VkDevice device)
Begins recording of a command buffer that will be used once.
Definition helper.cpp:24
std::vector< VkFramebuffer > createFramebuffer(Chronos::Engine::Device device, Chronos::Engine::SwapChain swapChain, VkRenderPass renderPass, bool msaa)
Creates a set of framebuffers for use.
Definition helper.cpp:276
std::vector< VkCommandBuffer > createCommandBuffer(Chronos::Engine::Device device, Chronos::Engine::SwapChain swapChain, VkCommandPool commandPool)
Creates a set of command buffers for use.
Definition helper.cpp:308
void endSingleTimeCommands(VkCommandBuffer *commandBuffer, Chronos::Engine::Device device, VkCommandPool commandPool)
Ends recording of single time command buffer and destroys it.
Definition helper.cpp:47
VkRenderPass createRenderPass(Chronos::Engine::Device device, Chronos::Engine::SwapChain swapChain, VkImageLayout initalLayout, VkImageLayout finalLayout, VkImageLayout msaaFinalLayout, bool msaa, bool clearFramebuffer, bool dependency)
Creates a render pass.
Definition helper.cpp:175
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, VkPhysicalDevice physicalDevice)
Finds suitable memory type for given requrements.
Definition helper.cpp:63
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface)
Gets the indices of the needed queue families.
Definition helper.cpp:126
void createBuffer(Chronos::Engine::Device device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer *buffer, VkDeviceMemory *bufferMemory)
Creates a buffer of a given size, usage and properties.
Definition helper.cpp:78
void copyBuffer(Chronos::Engine::Device device, VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size, VkCommandPool commandPool)
Copies data from one buffer to another.
Definition helper.cpp:111
VkCommandPool createCommandPool(Chronos::Engine::Device device, VkSurfaceKHR surface)
Creates a command pool for a given device and surface.
Definition helper.cpp:157
This is used to check if a given familty supports graphics and presentation.
Definition helper.hpp:44
std::optional< uint32_t > presentFamily
Definition helper.hpp:46
std::optional< uint32_t > graphicsFamily
Definition helper.hpp:45