vengine  0.0.1
3D graphics engine
Loading...
Searching...
No Matches
texture.cpp
Go to the documentation of this file.
1#include <cstring>
2
3#include <stb_image.h>
4
6
7ven::Texture::Texture(Device &device, const std::string &textureFilepath) : m_device{device}
8{
9 createTextureImage(textureFilepath);
10 createTextureImageView(VK_IMAGE_VIEW_TYPE_2D);
13}
14
15ven::Texture::Texture(Device &device, VkFormat format, VkExtent3D extent, VkImageUsageFlags usage, VkSampleCountFlagBits sampleCount)
16 : m_device{device}, m_format(format), m_extent(extent)
17{
18 VkImageAspectFlags aspectMask = 0;
19 VkImageLayout imageLayout;
20
21 if ((usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0u) {
22 aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
23 imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
24 }
25 if ((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0u) {
26 aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
27 imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
28 }
29
30 // Don't like this, should I be using an image array instead of multiple images?
31 VkImageCreateInfo imageInfo{};
32 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
33 imageInfo.imageType = VK_IMAGE_TYPE_2D;
34 imageInfo.format = format;
35 imageInfo.extent = extent;
36 imageInfo.mipLevels = 1;
37 imageInfo.arrayLayers = 1;
38 imageInfo.samples = sampleCount;
39 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
40 imageInfo.usage = usage;
41 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
42 device.createImageWithInfo(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_textureImage, m_textureImageMemory);
43
44 VkImageViewCreateInfo viewInfo{};
45 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
46 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
47 viewInfo.format = format;
48 viewInfo.subresourceRange = {};
49 viewInfo.subresourceRange.aspectMask = aspectMask;
50 viewInfo.subresourceRange.baseMipLevel = 0;
51 viewInfo.subresourceRange.levelCount = 1;
52 viewInfo.subresourceRange.baseArrayLayer = 0;
53 viewInfo.subresourceRange.layerCount = 1;
54 viewInfo.image = m_textureImage;
55 if (vkCreateImageView(device.device(), &viewInfo, nullptr, &m_textureImageView) != VK_SUCCESS) {
56 throw std::runtime_error("failed to create texture image view!");
57 }
58
59 // Sampler should be seperated out
60 if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0U) {
61 // Create sampler to sample from the attachment in the fragment shader
62 VkSamplerCreateInfo samplerInfo{};
63 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
64 samplerInfo.magFilter = VK_FILTER_LINEAR;
65 samplerInfo.minFilter = VK_FILTER_LINEAR;
66 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
67 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
68 samplerInfo.addressModeV = samplerInfo.addressModeU;
69 samplerInfo.addressModeW = samplerInfo.addressModeU;
70 samplerInfo.mipLodBias = 0.0F;
71 samplerInfo.maxAnisotropy = 1.0F;
72 samplerInfo.minLod = 0.0F;
73 samplerInfo.maxLod = 1.0F;
74 samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
75
76 if (vkCreateSampler(device.device(), &samplerInfo, nullptr, &m_textureSampler) != VK_SUCCESS) {
77 throw std::runtime_error("failed to create sampler!");
78 }
79
80 VkImageLayout samplerImageLayout = imageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
81 ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
82 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
85 m_descriptor.imageLayout = samplerImageLayout;
86 }
87}
88
90{
91 vkDestroySampler(m_device.device(), m_textureSampler, nullptr);
92 vkDestroyImageView(m_device.device(), m_textureImageView, nullptr);
93 vkDestroyImage(m_device.device(), m_textureImage, nullptr);
94 vkFreeMemory(m_device.device(), m_textureImageMemory, nullptr);
95}
96
98{
99 m_descriptor.sampler = m_textureSampler;
100 m_descriptor.imageView = m_textureImageView;
101 m_descriptor.imageLayout = m_textureLayout;
102}
103
104void ven::Texture::createTextureImage(const std::string &filepath)
105{
106 int texWidth = 0;
107 int texHeight = 0;
108 int texChannels = 0;
109 void *data = nullptr;
110 stbi_uc *pixels = nullptr;
111
112 stbi_set_flip_vertically_on_load(1);
113 pixels = stbi_load(filepath.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
114 const auto imageSize = static_cast<VkDeviceSize>(texWidth * texHeight * 4);
115
116 if (pixels == nullptr) {
117 throw std::runtime_error("failed to load texture image!");
118 }
119
120 // mMipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
121 m_mipLevels = 1;
122
123 VkBuffer stagingBuffer = nullptr;
124 VkDeviceMemory stagingBufferMemory = nullptr;
125
126 m_device.createBuffer(
127 imageSize,
128 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
129 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
130 stagingBuffer,
131 stagingBufferMemory);
132
133 vkMapMemory(m_device.device(), stagingBufferMemory, 0, imageSize, 0, &data);
134 memcpy(data, pixels, imageSize);
135 vkUnmapMemory(m_device.device(), stagingBufferMemory);
136
137 stbi_image_free(pixels);
138
139 m_format = VK_FORMAT_R8G8B8A8_SRGB;
140 m_extent = {.width=static_cast<uint32_t>(texWidth), .height=static_cast<uint32_t>(texHeight), .depth=1};
141
142 VkImageCreateInfo imageInfo{};
143 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
144 imageInfo.imageType = VK_IMAGE_TYPE_2D;
145 imageInfo.extent = m_extent;
146 imageInfo.mipLevels = m_mipLevels;
147 imageInfo.arrayLayers = m_layerCount;
148 imageInfo.format = m_format;
149 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
150 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
151 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
152 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
153 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
154
155 m_device.createImageWithInfo(
156 imageInfo,
157 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
158 m_textureImage,
159 m_textureImageMemory);
160 m_device.transitionImageLayout(
161 m_textureImage,
162 VK_FORMAT_R8G8B8A8_SRGB,
163 VK_IMAGE_LAYOUT_UNDEFINED,
164 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
165 m_mipLevels,
166 m_layerCount);
167 m_device.copyBufferToImage(
168 stagingBuffer,
169 m_textureImage,
170 static_cast<uint32_t>(texWidth),
171 static_cast<uint32_t>(texHeight),
172 m_layerCount);
173
174 // comment this out if using mips
175 m_device.transitionImageLayout(
176 m_textureImage,
177 VK_FORMAT_R8G8B8A8_SRGB,
178 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
179 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
180 m_mipLevels,
181 m_layerCount);
182
183 // If we generate mip maps then the final image will alerady be READ_ONLY_OPTIMAL
184 // mDevice.generateMipmaps(mTextureImage, mFormat, texWidth, texHeight, mMipLevels);
185 m_textureLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
186
187 vkDestroyBuffer(m_device.device(), stagingBuffer, nullptr);
188 vkFreeMemory(m_device.device(), stagingBufferMemory, nullptr);
189}
190
191void ven::Texture::createTextureImageView(const VkImageViewType viewType)
192{
193 VkImageViewCreateInfo viewInfo{};
194 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
195 viewInfo.image = m_textureImage;
196 viewInfo.viewType = viewType;
197 viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
198 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
199 viewInfo.subresourceRange.baseMipLevel = 0;
200 viewInfo.subresourceRange.levelCount = m_mipLevels;
201 viewInfo.subresourceRange.baseArrayLayer = 0;
202 viewInfo.subresourceRange.layerCount = m_layerCount;
203
204 if (vkCreateImageView(m_device.device(), &viewInfo, nullptr, &m_textureImageView) != VK_SUCCESS) {
205 throw std::runtime_error("failed to create texture image view!");
206 }
207}
208
210{
211 VkSamplerCreateInfo samplerInfo{};
212 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
213 samplerInfo.magFilter = VK_FILTER_LINEAR;
214 samplerInfo.minFilter = VK_FILTER_LINEAR;
215
216 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
217 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
218 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
219
220 samplerInfo.anisotropyEnable = VK_TRUE;
221 samplerInfo.maxAnisotropy = 16.0F;
222 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
223 samplerInfo.unnormalizedCoordinates = VK_FALSE;
224
225 // these fields useful for percentage close filtering for shadow maps
226 samplerInfo.compareEnable = VK_FALSE;
227 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
228
229 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
230 samplerInfo.mipLodBias = 0.0F;
231 samplerInfo.minLod = 0.0F;
232 samplerInfo.maxLod = static_cast<float>(m_mipLevels);
233
234 if (vkCreateSampler(m_device.device(), &samplerInfo, nullptr, &m_textureSampler) != VK_SUCCESS) {
235 throw std::runtime_error("failed to create texture sampler!");
236 }
237}
238
239void ven::Texture::transitionLayout(const VkCommandBuffer commandBuffer, const VkImageLayout oldLayout, const VkImageLayout newLayout) const
240{
241 VkPipelineStageFlags sourceStage = 0;
242 VkPipelineStageFlags destinationStage = 0;
243 VkImageMemoryBarrier barrier{};
244
245 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
246 barrier.oldLayout = oldLayout;
247 barrier.newLayout = newLayout;
248
249 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
250 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
251
252 barrier.image = m_textureImage;
253 barrier.subresourceRange.baseMipLevel = 0;
254 barrier.subresourceRange.levelCount = m_mipLevels;
255 barrier.subresourceRange.baseArrayLayer = 0;
256 barrier.subresourceRange.layerCount = m_layerCount;
257
258 if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
259 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
260 if (m_format == VK_FORMAT_D32_SFLOAT_S8_UINT || m_format == VK_FORMAT_D24_UNORM_S8_UINT) {
261 barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
262 }
263 } else {
264 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
265 }
266 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
267 barrier.srcAccessMask = 0;
268 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
269 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
270 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
271 } else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
272 barrier.srcAccessMask = 0;
273 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
274 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
275 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
276 } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
277 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
278 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
279
280 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
281 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
282 } else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
283 barrier.srcAccessMask = 0;
284 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
285 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
286 destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
287 } else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
288 // This says that any cmd that acts in color output or after (dstStage)
289 // that needs read or write access to a resource
290 // must wait until all previous read accesses in fragment shader
291 barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
292 barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
293 sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
294 destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
295 } else {
296 throw std::invalid_argument("unsupported layout transition!");
297 }
298 vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
299}
This file contains the Texture class.
Class for device.
Definition Device.hpp:35
VkDevice device() const
Definition Device.hpp:54
void createImageWithInfo(const VkImageCreateInfo &imageInfo, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory) const
Definition device.cpp:481
void transitionLayout(VkCommandBuffer commandBuffer, VkImageLayout oldLayout, VkImageLayout newLayout) const
Definition texture.cpp:239
VkSampler m_textureSampler
Definition Texture.hpp:56
VkDeviceMemory m_textureImageMemory
Definition Texture.hpp:54
VkImage m_textureImage
Definition Texture.hpp:53
void createTextureImageView(VkImageViewType viewType)
Definition texture.cpp:191
void updateDescriptor()
Definition texture.cpp:97
VkDescriptorImageInfo m_descriptor
Definition Texture.hpp:51
void createTextureImage(const std::string &filepath)
Definition texture.cpp:104
VkImageView m_textureImageView
Definition Texture.hpp:55
void createTextureSampler()
Definition texture.cpp:209
Texture(Device &device, const std::string &textureFilepath)
Definition texture.cpp:7