Rendering Engine 0.2.0
Modular Graphics Rendering Engine | v0.2.0
Loading...
Searching...
No Matches
vulkan_texture_resources.cpp
Go to the documentation of this file.
2#include "vulkan_renderer.hpp"
3
4namespace rendering_engine
5{
6
14
25
27{
28 vkDestroySampler(mRenderer->GetLogicalDevice(), mTextureSampler, nullptr);
29 vkDestroyImageView(mRenderer->GetLogicalDevice(), mTextureImageView, nullptr);
30 vkDestroyImage(mRenderer->GetLogicalDevice(), mTextureImage, nullptr);
31 vkFreeMemory(mRenderer->GetLogicalDevice(), mTextureImageMemory, nullptr);
32
34}
35
40
42{
43 return static_cast<size_t>(mGpuMemorySize);
44}
45
46
48{
49 if (!mImageData)
50 {
51 throw std::runtime_error("ImageData is not initialized!");
52 }
53
54 unsigned int const width = mImageData->GetWidth();
55 unsigned int const height = mImageData->GetHeight();
56
57 mMipmapLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(width, height)))) + 1;
58 auto const pixelVector = mImageData->GetImageDataRGBA();
59
60 VkDeviceSize imageSize = width * height * 4;
61
62 if (pixelVector.size() == 0)
63 {
64 throw std::runtime_error("failed to load texture image!");
65 }
66
67 VkBuffer stagingBuffer;
68 VkDeviceMemory stagingBufferMemory;
69
70 mRenderer->CreateBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
71
72 unsigned char* pixels = new unsigned char[width * height * 4];
73 std::copy(pixelVector.begin(), pixelVector.end(), pixels);
74 void* data;
75 vkMapMemory(mRenderer->GetLogicalDevice(), stagingBufferMemory, 0, imageSize, 0, &data);
76 memcpy(data, pixels, static_cast<size_t>(imageSize));
77 vkUnmapMemory(mRenderer->GetLogicalDevice(), stagingBufferMemory);
78 delete[] pixels;
79
80 CreateVulkanImage(width, 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,
81 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mTextureImage, mTextureImageMemory);
82
83 mRenderer->TransitionImageLayout(mTextureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mMipmapLevels);
84 mRenderer->CopyBufferToImage(stagingBuffer, mTextureImage, static_cast<uint32_t>(width), static_cast<uint32_t>(height));
85
86 vkDestroyBuffer(mRenderer->GetLogicalDevice(), stagingBuffer, nullptr);
87 vkFreeMemory(mRenderer->GetLogicalDevice(), stagingBufferMemory, nullptr);
88
89 mRenderer->GenerateMipmaps(mTextureImage, VK_FORMAT_R8G8B8A8_SRGB, width, height, mMipmapLevels);
90}
91
92void 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)
93{
94 VkImageCreateInfo imageInfo{};
95 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
96 imageInfo.imageType = VK_IMAGE_TYPE_2D;
97 imageInfo.extent.width = static_cast<uint32_t>(width);
98 imageInfo.extent.height = static_cast<uint32_t>(height);
99 imageInfo.extent.depth = 1;
100 imageInfo.mipLevels = mipmapLevels;
101 imageInfo.arrayLayers = 1;
102
103 imageInfo.format = format;
104 imageInfo.tiling = tiling;
105
106 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
107
108 imageInfo.usage = usage;
109
110 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
111
112 imageInfo.samples = numSamples;
113 imageInfo.flags = 0; // Optional
114
115 if (vkCreateImage(mRenderer->GetLogicalDevice(), &imageInfo, nullptr, &image) != VK_SUCCESS)
116 {
117 throw std::runtime_error("failed to create image!");
118 }
119
120 VkMemoryRequirements memRequirements;
121 vkGetImageMemoryRequirements(mRenderer->GetLogicalDevice(), image, &memRequirements);
122
123 VkMemoryAllocateInfo allocInfo{};
124 allocInfo.allocationSize = memRequirements.size;
125 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
126 allocInfo.allocationSize = memRequirements.size;
127 allocInfo.memoryTypeIndex = mRenderer->FindMemoryType(memRequirements.memoryTypeBits, properties);
128
129 if (vkAllocateMemory(mRenderer->GetLogicalDevice(), &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
130 throw std::runtime_error("failed to allocate image memory!");
131 }
132
133 mGpuMemorySize = allocInfo.allocationSize;
134
135 vkBindImageMemory(mRenderer->GetLogicalDevice(), image, imageMemory, 0);
136 allocInfo.allocationSize;
137}
138
140{
141 mTextureImageView = CreateImageView(mTextureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, mMipmapLevels);
142}
143
144VkImageView VulkanTextureResources::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, std::uint32_t mipmapLevels)
145{
146 VkImageViewCreateInfo viewInfo{};
147 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
148 viewInfo.image = image;
149 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
150 viewInfo.format = format;
151 viewInfo.subresourceRange.aspectMask = aspectFlags;
152 viewInfo.subresourceRange.baseMipLevel = 0;
153 viewInfo.subresourceRange.levelCount = mipmapLevels;
154 viewInfo.subresourceRange.baseArrayLayer = 0;
155 viewInfo.subresourceRange.layerCount = 1;
156
157 VkImageView imageView;
158 if (vkCreateImageView(mRenderer->GetLogicalDevice(), &viewInfo, nullptr, &imageView) != VK_SUCCESS)
159 {
160 throw std::runtime_error("failed to create texture image view!");
161 }
162
163 return imageView;
164}
165
167{
168 VkSamplerCreateInfo samplerInfo{};
169
170 VkPhysicalDeviceProperties properties{};
171 vkGetPhysicalDeviceProperties(mRenderer->GetPhysicalDevice(), &properties);
172
173 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
174 samplerInfo.magFilter = VK_FILTER_LINEAR;
175 samplerInfo.minFilter = VK_FILTER_LINEAR;
176
177 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
178 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
179 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
180
181 if (mRenderer->GetPhysDevSupportedFeatures().samplerAnisotropy)
182 {
183 samplerInfo.anisotropyEnable = VK_TRUE;
184 samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
185 }
186 else
187 {
188 samplerInfo.anisotropyEnable = VK_FALSE;
189 samplerInfo.maxAnisotropy = 1.0f;
190 }
191
192 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
193 samplerInfo.unnormalizedCoordinates = VK_FALSE;
194
195 samplerInfo.compareEnable = VK_FALSE;
196 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
197
198 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
199 samplerInfo.mipLodBias = 0.0f;
200 samplerInfo.minLod = 0.0f;
201 samplerInfo.maxLod = static_cast<float>(mMipmapLevels);
202
203 if (vkCreateSampler(mRenderer->GetLogicalDevice(), &samplerInfo, nullptr, &mTextureSampler) != VK_SUCCESS)
204 {
205 throw std::runtime_error("failed to create texture sampler!");
206 }
207}
208
209}
Represents raw 2D image data stored in memory.
Vulkan-based implementation of the IRenderer interface.
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)