Chronos 0.0
A advanced 2D rendering and animation system
Loading...
Searching...
No Matches
texture.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
23#include "texture.hpp"
24#include "helper.hpp"
25#define STB_IMAGE_IMPLEMENTATION
26#ifndef WIN32
27#ifndef __clang__
28#pragma GCC diagnostic push
29#pragma GCC diagnostic ignored "-Wstringop-overflow"
30#endif
31#endif
32#include "stb_image.h"
33#ifndef WIN32
34#ifndef __clang__
35#pragma GCC diagnostic pop
36#endif
37#endif
38#ifdef ENABLE_EDITOR
39#include "editorHeaders.hpp"
40#endif
41
43 uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling,
44 VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage* image,
45 VkDeviceMemory* imageMemory, VkSampleCountFlagBits numSamples)
46{
47 VkImageCreateInfo imageInfo {};
48 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
49 imageInfo.imageType = VK_IMAGE_TYPE_2D;
50 imageInfo.extent.width = width;
51 imageInfo.extent.height = height;
52 imageInfo.extent.depth = 1;
53 imageInfo.mipLevels = 1;
54 imageInfo.arrayLayers = 1;
55 imageInfo.format = format;
56 imageInfo.tiling = tiling;
57 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
58 imageInfo.usage = usage;
59 imageInfo.samples = numSamples;
60 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
61
62 if (vkCreateImage(device.device, &imageInfo, nullptr, image)
63 != VK_SUCCESS) {
64 throw std::runtime_error("failed to create image!");
65 }
66
67 VkMemoryRequirements memRequirements;
68 vkGetImageMemoryRequirements(device.device, *image, &memRequirements);
69
70 VkMemoryAllocateInfo allocInfo {};
71 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
72 allocInfo.allocationSize = memRequirements.size;
73 allocInfo.memoryTypeIndex = Chronos::Engine::findMemoryType(
74 memRequirements.memoryTypeBits, properties, device.physicalDevice);
75
76 if (vkAllocateMemory(device.device, &allocInfo, nullptr, imageMemory)
77 != VK_SUCCESS) {
78 throw std::runtime_error("failed to allocate image memory!");
79 }
80
81 vkBindImageMemory(device.device, *image, *imageMemory, 0);
82}
84 VkCommandPool commandPool, std::string texturePath, std::string textureName)
85{
86 this->texturePath = texturePath;
87 this->textureName = textureName;
88 int texWidth = 0, texHeight = 0, texChannels = 0;
89 this->device = device;
90 VkDeviceSize imageSize;
91 uint8_t* pixels;
92
93 if (texturePath.ends_with(".png") || texturePath.ends_with(".jpg")) {
94 pixels = stbi_load(texturePath.c_str(), &texWidth, &texHeight,
95 &texChannels, STBI_rgb_alpha);
96 imageSize = texWidth * texHeight * 4;
97 this->width = texWidth;
98 this->height = texHeight;
99 if (!pixels) {
100 throw std::runtime_error(
101 "failed to load texture image " + texturePath);
102 }
103 } else {
104 throw std::runtime_error("unsupported texture format " + texturePath);
105 }
106
107 VkBuffer stagingBuffer;
108 VkDeviceMemory stagingBufferMemory;
110 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
111 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
112 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
113 &stagingBuffer, &stagingBufferMemory);
114
115 void* data;
116 vkMapMemory(device.device, stagingBufferMemory, 0, imageSize, 0, &data);
117 memcpy(data, pixels, static_cast<size_t>(imageSize));
118 vkUnmapMemory(device.device, stagingBufferMemory);
119
120 stbi_image_free(pixels);
121
122 Chronos::Engine::createImage(device, texWidth, texHeight,
123 VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL,
124 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
125 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &textureImage, &textureImageMemory,
126 VK_SAMPLE_COUNT_1_BIT);
127
129 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
130 commandPool, device);
132 static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight),
133 commandPool, device);
135 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
136 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, commandPool, device);
137 vkDestroyBuffer(device.device, stagingBuffer, nullptr);
138 vkFreeMemory(device.device, stagingBufferMemory, nullptr);
140 = createImageView(device, VK_FORMAT_R8G8B8A8_SRGB, textureImage);
141#ifdef ENABLE_EDITOR
143 descriptorSet = ImGui_ImplVulkan_AddTexture(textureSampler,
144 textureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
145
146#endif
147}
148
150 VkCommandPool commandPool, void* data, size_t texWidth, size_t texHeight,
151 VkDeviceSize imageSize, VkFormat format, std::string textureName)
152{
153 this->textureName = textureName;
154 this->texturePath = "NA";
155 this->device = device;
156 VkBuffer stagingBuffer;
157 VkDeviceMemory stagingBufferMemory;
158 Chronos::Engine::createBuffer(device, imageSize,
159 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
160 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
161 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
162 &stagingBuffer, &stagingBufferMemory);
163
164 void* mappedData;
165 vkMapMemory(
166 device.device, stagingBufferMemory, 0, imageSize, 0, &mappedData);
167 memcpy(mappedData, data, static_cast<size_t>(imageSize));
168 vkUnmapMemory(device.device, stagingBufferMemory);
169
170 Chronos::Engine::createImage(device, texWidth, texHeight, format,
171 VK_IMAGE_TILING_OPTIMAL,
172 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
173 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &textureImage, &textureImageMemory,
174 VK_SAMPLE_COUNT_1_BIT);
175
177 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
178 commandPool, device);
179 Chronos::Engine::copyBufferToImage(stagingBuffer, textureImage,
180 static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight),
181 commandPool, device);
183 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
184 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, commandPool, device);
185 vkDestroyBuffer(device.device, stagingBuffer, nullptr);
186 vkFreeMemory(device.device, stagingBufferMemory, nullptr);
187 textureImageView = createImageView(device, format, textureImage);
188}
189
191 VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandPool commandPool,
193{
194 VkCommandBuffer commandBuffer
196 VkImageMemoryBarrier barrier {};
197 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
198 barrier.oldLayout = oldLayout;
199 barrier.newLayout = newLayout;
200 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
201 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
202 barrier.image = image;
203 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
204 barrier.subresourceRange.baseMipLevel = 0;
205 barrier.subresourceRange.levelCount = 1;
206 barrier.subresourceRange.baseArrayLayer = 0;
207 barrier.subresourceRange.layerCount = 1;
208 VkPipelineStageFlags sourceStage;
209 VkPipelineStageFlags destinationStage;
210
211 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED
212 && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
213 barrier.srcAccessMask = 0;
214 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
215
216 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
217 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
218 } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
219 && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
220 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
221 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
222
223 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
224 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
225 } else {
226 throw std::invalid_argument("unsupported layout transition!");
227 }
228
229 vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0,
230 nullptr, 0, nullptr, 1, &barrier);
231 Chronos::Engine::endSingleTimeCommands(&commandBuffer, device, commandPool);
232}
233
234void Chronos::Engine::copyBufferToImage(VkBuffer buffer, VkImage image,
235 uint32_t width, uint32_t height, VkCommandPool commandPool,
237{
238 VkCommandBuffer commandBuffer
240 VkBufferImageCopy region {};
241 region.bufferOffset = 0;
242 region.bufferRowLength = 0;
243 region.bufferImageHeight = 0;
244 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
245 region.imageSubresource.mipLevel = 0;
246 region.imageSubresource.baseArrayLayer = 0;
247 region.imageSubresource.layerCount = 1;
248 region.imageOffset = { 0, 0, 0 };
249 region.imageExtent = { width, height, 1 };
250 vkCmdCopyBufferToImage(commandBuffer, buffer, image,
251 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
252 Chronos::Engine::endSingleTimeCommands(&commandBuffer, device, commandPool);
253}
254
256 Chronos::Engine::Device device, VkFormat format, VkImage image)
257{
258 VkImageViewCreateInfo viewInfo {};
259 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
260 viewInfo.image = image;
261 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
262 viewInfo.format = format;
263 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
264 viewInfo.subresourceRange.baseMipLevel = 0;
265 viewInfo.subresourceRange.levelCount = 1;
266 viewInfo.subresourceRange.baseArrayLayer = 0;
267 viewInfo.subresourceRange.layerCount = 1;
268
269 VkImageView imageView;
270
271 if (vkCreateImageView(device.device, &viewInfo, nullptr, &imageView)
272 != VK_SUCCESS) {
273 throw std::runtime_error("failed to create texture image view!");
274 }
275 return imageView;
276}
277
279 Chronos::Engine::Device device, VkSampler* textureSampler)
280{
281 VkPhysicalDeviceProperties properties {};
282 vkGetPhysicalDeviceProperties(device.physicalDevice, &properties);
283 VkSamplerCreateInfo samplerInfo {};
284 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
285 samplerInfo.magFilter = VK_FILTER_LINEAR;
286 samplerInfo.minFilter = VK_FILTER_LINEAR;
287 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
288 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
289 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
290 samplerInfo.anisotropyEnable = VK_TRUE;
291 samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
292 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
293 samplerInfo.unnormalizedCoordinates = VK_FALSE;
294 samplerInfo.compareEnable = VK_FALSE;
295 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
296 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
297 samplerInfo.mipLodBias = 0.0f;
298 samplerInfo.minLod = 0.0f;
299 samplerInfo.maxLod = 0.0f;
300 if (vkCreateSampler(device.device, &samplerInfo, nullptr, textureSampler)
301 != VK_SUCCESS) {
302 throw std::runtime_error("failed to create texture sampler!");
303 }
304}
305
307{
308 vkDestroyImageView(device.device, textureImageView, nullptr);
309 vkDestroyImage(device.device, textureImage, nullptr);
310 vkFreeMemory(device.device, textureImageMemory, nullptr);
311}
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
std::string textureName
The name of the texture.
Definition texture.hpp:197
VkDeviceMemory textureImageMemory
The memory for the texture.
Definition texture.hpp:139
Chronos::Engine::Device device
The device that has the texture.
Definition texture.hpp:210
VkImageView textureImageView
The image view for the texture.
Definition texture.hpp:149
VkImage textureImage
The image for the texture.
Definition texture.hpp:144
void destroy()
Destroy the texture assets.
Definition texture.cpp:306
void create(Chronos::Engine::Device device, VkCommandPool commandPool, std::string texturePath, std::string textureName)
Create the texture by loading the texture from the given path. Only supports jpg and png images.
Definition texture.cpp:83
std::string texturePath
The path of the texture that it was loaded from.
Definition texture.hpp:192
Contains all the editor headers.
Contains various common functions used by other classes in the Engine namespace.
void createTextureSampler(Chronos::Engine::Device device, VkSampler *textureSampler)
Creates a VkSampler
Definition texture.cpp:278
VkCommandBuffer beginSingleTimeCommands(VkCommandPool commandPool, VkDevice device)
Begins recording of a command buffer that will be used once.
Definition helper.cpp:24
VkImageView createImageView(Chronos::Engine::Device device, VkFormat format, VkImage image)
Create a VkImageView for a given VkImage.
Definition texture.cpp:255
void endSingleTimeCommands(VkCommandBuffer *commandBuffer, Chronos::Engine::Device device, VkCommandPool commandPool)
Ends recording of single time command buffer and destroys it.
Definition helper.cpp:47
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, VkPhysicalDevice physicalDevice)
Finds suitable memory type for given requrements.
Definition helper.cpp:63
void createImage(Chronos::Engine::Device device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage *image, VkDeviceMemory *imageMemory, VkSampleCountFlagBits numSamples)
For a given image dimensons, it creates a VkImage and.
Definition texture.cpp:42
void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height, VkCommandPool commandPool, Chronos::Engine::Device device)
Copy data from a buffer to an image.
Definition texture.cpp:234
void transitionImageLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandPool commandPool, Chronos::Engine::Device device)
Transiton a VkImage from one layout to another.
Definition texture.cpp:190
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
Contains the functions for image manipulation along with the Texture class.