16 : m_device{device}, m_format(format), m_extent(extent)
18 VkImageAspectFlags aspectMask = 0;
19 VkImageLayout imageLayout;
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;
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;
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;
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;
56 throw std::runtime_error(
"failed to create texture image view!");
60 if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0U) {
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;
77 throw std::runtime_error(
"failed to create sampler!");
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;
109 void *data =
nullptr;
110 stbi_uc *pixels =
nullptr;
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);
116 if (pixels ==
nullptr) {
117 throw std::runtime_error(
"failed to load texture image!");
123 VkBuffer stagingBuffer =
nullptr;
124 VkDeviceMemory stagingBufferMemory =
nullptr;
126 m_device.createBuffer(
128 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
129 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
131 stagingBufferMemory);
133 vkMapMemory(m_device.device(), stagingBufferMemory, 0, imageSize, 0, &data);
134 memcpy(data, pixels, imageSize);
135 vkUnmapMemory(m_device.device(), stagingBufferMemory);
137 stbi_image_free(pixels);
139 m_format = VK_FORMAT_R8G8B8A8_SRGB;
140 m_extent = {.width=
static_cast<uint32_t
>(texWidth), .height=
static_cast<uint32_t
>(texHeight), .depth=1};
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;
155 m_device.createImageWithInfo(
157 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
159 m_textureImageMemory);
160 m_device.transitionImageLayout(
162 VK_FORMAT_R8G8B8A8_SRGB,
163 VK_IMAGE_LAYOUT_UNDEFINED,
164 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
167 m_device.copyBufferToImage(
170 static_cast<uint32_t
>(texWidth),
171 static_cast<uint32_t
>(texHeight),
175 m_device.transitionImageLayout(
177 VK_FORMAT_R8G8B8A8_SRGB,
178 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
179 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
185 m_textureLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
187 vkDestroyBuffer(m_device.device(), stagingBuffer,
nullptr);
188 vkFreeMemory(m_device.device(), stagingBufferMemory,
nullptr);
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;
204 if (vkCreateImageView(m_device.device(), &viewInfo,
nullptr, &m_textureImageView) != VK_SUCCESS) {
205 throw std::runtime_error(
"failed to create texture image view!");
211 VkSamplerCreateInfo samplerInfo{};
212 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
213 samplerInfo.magFilter = VK_FILTER_LINEAR;
214 samplerInfo.minFilter = VK_FILTER_LINEAR;
216 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
217 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
218 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
220 samplerInfo.anisotropyEnable = VK_TRUE;
221 samplerInfo.maxAnisotropy = 16.0F;
222 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
223 samplerInfo.unnormalizedCoordinates = VK_FALSE;
226 samplerInfo.compareEnable = VK_FALSE;
227 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
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);
234 if (vkCreateSampler(m_device.device(), &samplerInfo,
nullptr, &m_textureSampler) != VK_SUCCESS) {
235 throw std::runtime_error(
"failed to create texture sampler!");
241 VkPipelineStageFlags sourceStage = 0;
242 VkPipelineStageFlags destinationStage = 0;
243 VkImageMemoryBarrier barrier{};
245 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
246 barrier.oldLayout = oldLayout;
247 barrier.newLayout = newLayout;
249 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
250 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
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;
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;
264 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
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;
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) {
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;
296 throw std::invalid_argument(
"unsupported layout transition!");
298 vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0,
nullptr, 0,
nullptr, 1, &barrier);
This file contains the Texture class.
void transitionLayout(VkCommandBuffer commandBuffer, VkImageLayout oldLayout, VkImageLayout newLayout) const
VkSampler m_textureSampler
VkDeviceMemory m_textureImageMemory
void createTextureImageView(VkImageViewType viewType)
VkDescriptorImageInfo m_descriptor
void createTextureImage(const std::string &filepath)
VkImageView m_textureImageView
void createTextureSampler()
Texture(Device &device, const std::string &textureFilepath)