51 throw std::runtime_error(
"ImageData is not initialized!");
54 unsigned int const width =
mImageData->GetWidth();
55 unsigned int const height =
mImageData->GetHeight();
57 mMipmapLevels =
static_cast<uint32_t
>(std::floor(std::log2(std::max(width, height)))) + 1;
58 auto const pixelVector =
mImageData->GetImageDataRGBA();
60 VkDeviceSize imageSize = width * height * 4;
62 if (pixelVector.size() == 0)
64 throw std::runtime_error(
"failed to load texture image!");
67 VkBuffer stagingBuffer;
68 VkDeviceMemory stagingBufferMemory;
70 mRenderer->CreateBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
72 unsigned char* pixels =
new unsigned char[width * height * 4];
73 std::copy(pixelVector.begin(), pixelVector.end(), pixels);
75 vkMapMemory(
mRenderer->GetLogicalDevice(), stagingBufferMemory, 0, imageSize, 0, &data);
76 memcpy(data, pixels,
static_cast<size_t>(imageSize));
77 vkUnmapMemory(
mRenderer->GetLogicalDevice(), stagingBufferMemory);
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,
84 mRenderer->CopyBufferToImage(stagingBuffer,
mTextureImage,
static_cast<uint32_t
>(width),
static_cast<uint32_t
>(height));
86 vkDestroyBuffer(
mRenderer->GetLogicalDevice(), stagingBuffer,
nullptr);
87 vkFreeMemory(
mRenderer->GetLogicalDevice(), stagingBufferMemory,
nullptr);
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)
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;
103 imageInfo.format = format;
104 imageInfo.tiling = tiling;
106 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
108 imageInfo.usage = usage;
110 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
112 imageInfo.samples = numSamples;
115 if (vkCreateImage(
mRenderer->GetLogicalDevice(), &imageInfo,
nullptr, &image) != VK_SUCCESS)
117 throw std::runtime_error(
"failed to create image!");
120 VkMemoryRequirements memRequirements;
121 vkGetImageMemoryRequirements(
mRenderer->GetLogicalDevice(), image, &memRequirements);
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);
129 if (vkAllocateMemory(
mRenderer->GetLogicalDevice(), &allocInfo,
nullptr, &imageMemory) != VK_SUCCESS) {
130 throw std::runtime_error(
"failed to allocate image memory!");
135 vkBindImageMemory(
mRenderer->GetLogicalDevice(), image, imageMemory, 0);
136 allocInfo.allocationSize;
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;
157 VkImageView imageView;
158 if (vkCreateImageView(
mRenderer->GetLogicalDevice(), &viewInfo,
nullptr, &imageView) != VK_SUCCESS)
160 throw std::runtime_error(
"failed to create texture image view!");
168 VkSamplerCreateInfo samplerInfo{};
170 VkPhysicalDeviceProperties properties{};
171 vkGetPhysicalDeviceProperties(
mRenderer->GetPhysicalDevice(), &properties);
173 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
174 samplerInfo.magFilter = VK_FILTER_LINEAR;
175 samplerInfo.minFilter = VK_FILTER_LINEAR;
177 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
178 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
179 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
181 if (
mRenderer->GetPhysDevSupportedFeatures().samplerAnisotropy)
183 samplerInfo.anisotropyEnable = VK_TRUE;
184 samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
188 samplerInfo.anisotropyEnable = VK_FALSE;
189 samplerInfo.maxAnisotropy = 1.0f;
192 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
193 samplerInfo.unnormalizedCoordinates = VK_FALSE;
195 samplerInfo.compareEnable = VK_FALSE;
196 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
198 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
199 samplerInfo.mipLodBias = 0.0f;
200 samplerInfo.minLod = 0.0f;
205 throw std::runtime_error(
"failed to create texture sampler!");
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.
VkDeviceMemory mTextureImageMemory
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)
const ImageData * mImageData