Rendering Engine 0.2.17
Modular Graphics Rendering Engine | v0.2.17
Loading...
Searching...
No Matches
vulkan_texture_resources.cpp
Go to the documentation of this file.
2#include "vulkan_renderer.hpp"
3
4#include <limits>
5#include <stdexcept>
6
7namespace rendering_engine
8{
9
11 :
12 bIsTextureLoadedInGPU(false),
13 mRenderer(renderer),
14 mImageData(nullptr),
15 mGpuMemorySize(0)
16{}
17
28
30{
31 vkDestroySampler(mRenderer->GetLogicalDevice(), mTextureSampler, nullptr);
32 vkDestroyImageView(mRenderer->GetLogicalDevice(), mTextureImageView, nullptr);
33 vkDestroyImage(mRenderer->GetLogicalDevice(), mTextureImage, nullptr);
34 vkFreeMemory(mRenderer->GetLogicalDevice(), mTextureImageMemory, nullptr);
35
37}
38
43
45{
46 return static_cast<size_t>(mGpuMemorySize);
47}
48
49
51{
52 if (!mImageData)
53 {
54 throw std::runtime_error("ImageData is not initialized!");
55 }
56
57 unsigned int const width = mImageData->GetWidth();
58 unsigned int const height = mImageData->GetHeight();
59
60 if (width > static_cast<unsigned int>(std::numeric_limits<int32_t>::max()) ||
61 height > static_cast<unsigned int>(std::numeric_limits<int32_t>::max()))
62 {
63 throw std::out_of_range("Texture dimensions exceed supported mipmap range.");
64 }
65
66 mMipmapLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(width, height)))) + 1;
67 auto const pixelVector = mImageData->GetImageDataRGBA();
68
69 const VkDeviceSize imageSize =
70 static_cast<VkDeviceSize>(width) *
71 static_cast<VkDeviceSize>(height) *
72 4;
73
74 if (pixelVector.size() == 0)
75 {
76 throw std::runtime_error("failed to load texture image!");
77 }
78
79 VkBuffer stagingBuffer;
80 VkDeviceMemory stagingBufferMemory;
81
82 mRenderer->CreateBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
83
84 unsigned char* pixels = new unsigned char[static_cast<size_t>(imageSize)];
85 std::copy(pixelVector.begin(), pixelVector.end(), pixels);
86 void* data;
87 vkMapMemory(mRenderer->GetLogicalDevice(), stagingBufferMemory, 0, imageSize, 0, &data);
88 memcpy(data, pixels, static_cast<size_t>(imageSize));
89 vkUnmapMemory(mRenderer->GetLogicalDevice(), stagingBufferMemory);
90 delete[] pixels;
91
92 CreateVulkanImage(static_cast<uint32_t>(width), static_cast<uint32_t>(height), mMipmapLevels, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
93 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mTextureImage, mTextureImageMemory);
94
95 mRenderer->TransitionImageLayout(mTextureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mMipmapLevels);
96 mRenderer->CopyBufferToImage(stagingBuffer, mTextureImage, static_cast<uint32_t>(width), static_cast<uint32_t>(height));
97
98 vkDestroyBuffer(mRenderer->GetLogicalDevice(), stagingBuffer, nullptr);
99 vkFreeMemory(mRenderer->GetLogicalDevice(), stagingBufferMemory, nullptr);
100
103 VK_FORMAT_R8G8B8A8_SRGB,
104 static_cast<int32_t>(width),
105 static_cast<int32_t>(height),
107}
108
109void VulkanTextureResources::CreateVulkanImage(uint32_t width, uint32_t height, std::uint32_t mipmapLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory)
110{
111 VkImageCreateInfo imageInfo{};
112 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
113 imageInfo.imageType = VK_IMAGE_TYPE_2D;
114 imageInfo.extent.width = width;
115 imageInfo.extent.height = height;
116 imageInfo.extent.depth = 1;
117 imageInfo.mipLevels = mipmapLevels;
118 imageInfo.arrayLayers = 1;
119
120 imageInfo.format = format;
121 imageInfo.tiling = tiling;
122
123 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
124
125 imageInfo.usage = usage;
126
127 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
128
129 imageInfo.samples = numSamples;
130 imageInfo.flags = 0; // Optional
131
132 if (vkCreateImage(mRenderer->GetLogicalDevice(), &imageInfo, nullptr, &image) != VK_SUCCESS)
133 {
134 throw std::runtime_error("failed to create image!");
135 }
136
137 VkMemoryRequirements memRequirements;
138 vkGetImageMemoryRequirements(mRenderer->GetLogicalDevice(), image, &memRequirements);
139
140 VkMemoryAllocateInfo allocInfo{};
141 allocInfo.allocationSize = memRequirements.size;
142 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
143 allocInfo.allocationSize = memRequirements.size;
144 allocInfo.memoryTypeIndex = mRenderer->FindMemoryType(memRequirements.memoryTypeBits, properties);
145
146 if (vkAllocateMemory(mRenderer->GetLogicalDevice(), &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
147 throw std::runtime_error("failed to allocate image memory!");
148 }
149
150 mGpuMemorySize = allocInfo.allocationSize;
151
152 vkBindImageMemory(mRenderer->GetLogicalDevice(), image, imageMemory, 0);
153}
154
156{
157 mTextureImageView = CreateImageView(mTextureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, mMipmapLevels);
158}
159
160VkImageView VulkanTextureResources::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, std::uint32_t mipmapLevels)
161{
162 VkImageViewCreateInfo viewInfo{};
163 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
164 viewInfo.image = image;
165 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
166 viewInfo.format = format;
167 viewInfo.subresourceRange.aspectMask = aspectFlags;
168 viewInfo.subresourceRange.baseMipLevel = 0;
169 viewInfo.subresourceRange.levelCount = mipmapLevels;
170 viewInfo.subresourceRange.baseArrayLayer = 0;
171 viewInfo.subresourceRange.layerCount = 1;
172
173 VkImageView imageView;
174 if (vkCreateImageView(mRenderer->GetLogicalDevice(), &viewInfo, nullptr, &imageView) != VK_SUCCESS)
175 {
176 throw std::runtime_error("failed to create texture image view!");
177 }
178
179 return imageView;
180}
181
183{
184 VkSamplerCreateInfo samplerInfo{};
185
186 VkPhysicalDeviceProperties properties{};
187 vkGetPhysicalDeviceProperties(mRenderer->GetPhysicalDevice(), &properties);
188
189 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
190 samplerInfo.magFilter = VK_FILTER_LINEAR;
191 samplerInfo.minFilter = VK_FILTER_LINEAR;
192
193 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
194 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
195 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
196
197 if (mRenderer->GetPhysDevSupportedFeatures().samplerAnisotropy)
198 {
199 samplerInfo.anisotropyEnable = VK_TRUE;
200 samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
201 }
202 else
203 {
204 samplerInfo.anisotropyEnable = VK_FALSE;
205 samplerInfo.maxAnisotropy = 1.0f;
206 }
207
208 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
209 samplerInfo.unnormalizedCoordinates = VK_FALSE;
210
211 samplerInfo.compareEnable = VK_FALSE;
212 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
213
214 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
215 samplerInfo.mipLodBias = 0.0f;
216 samplerInfo.minLod = 0.0f;
217 samplerInfo.maxLod = static_cast<float>(mMipmapLevels - 1);
218
219 if (vkCreateSampler(mRenderer->GetLogicalDevice(), &samplerInfo, nullptr, &mTextureSampler) != VK_SUCCESS)
220 {
221 throw std::runtime_error("failed to create texture sampler!");
222 }
223}
224
225}
Represents raw 2D image data stored in memory.
unsigned int GetWidth() const
Returns the image width.
std::vector< uint8_t > GetImageDataRGBA() const
Gets raw image data in RGBA format.
unsigned int GetHeight() const
Returns the image height.
Vulkan-based implementation of the IRenderer interface.
VkPhysicalDeviceFeatures & GetPhysDevSupportedFeatures()
Returns reference to the physical device�s supported features.
void GenerateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels)
Generates mipmaps for a given image resource.
void CopyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
Copies buffer data into an image (used for uploading texture data).
VkDevice & GetLogicalDevice()
Returns reference to the logical Vulkan device.
VkPhysicalDevice & GetPhysicalDevice()
Returns reference to the physical device.
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory)
Creates a new Vulkan buffer with the specified usage and memory properties.
uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
Finds a suitable memory type for a given allocation.
void TransitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, std::uint32_t mipmapLevels)
Transitions the image layout for a given Vulkan image.
VulkanTextureResources(VulkanRenderer *renderer)
Vulkan-specific implementation of ITextureRenderResources.
size_t GetSizeInGPUBytes() const override
Returns the size of the texture in GPU memory in bytes.
VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, std::uint32_t mipmapLevels)
bool IsTextureLoadedInGPU() override
Checks if the texture is currently loaded in GPU memory.
void LoadToGPU(const ImageData &data) override
Uploads the texture data from CPU to GPU memory using Vulkan.
void ReleaseFromGPU() override
Releases the texture data from GPU memory using Vulkan.
void CreateVulkanImage(uint32_t width, uint32_t height, std::uint32_t mipmapLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory)