20 TextureImage* TextureImage::current;
28 if (current !=
nullptr) {
29 TextureImage::current = current;
33 TextureImage::TextureImage(uint32_t width, uint32_t height) {
34 VkDevice device = VulkanContext::getCurrent()->getDevice()->
getHandle();
35 VkPhysicalDevice physicalDevice = VulkanContext::getCurrent()->getPhysicalDevice()->getHandle();
37 this->height = height;
40 VkImageCreateInfo createInfo = {};
41 createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
42 createInfo.imageType = VK_IMAGE_TYPE_2D;
43 createInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
44 createInfo.extent.width = width;
45 createInfo.extent.height = height;
46 createInfo.extent.depth = 1;
47 createInfo.mipLevels = 1;
48 createInfo.arrayLayers = 1;
49 createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
50 createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
51 createInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
52 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
53 createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
56 if (vkCreateImage(device, &createInfo,
nullptr, &handle) != VK_SUCCESS) {
57 throw runtime_error(
"Could not create a texture image!");
61 VkMemoryRequirements memoryRequirements;
62 vkGetImageMemoryRequirements(device, handle, &memoryRequirements);
65 VkPhysicalDeviceMemoryProperties memoryProperties;
66 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
69 uint32_t memoryTypeIndex = -1;
70 VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
71 for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
72 if ((memoryRequirements.memoryTypeBits & (1 << i)) &&
73 (memoryProperties.memoryTypes[i].propertyFlags & flags) == flags) {
80 VkMemoryAllocateInfo allocateInfo = {};
81 allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
82 allocateInfo.allocationSize = memoryRequirements.size;
83 allocateInfo.memoryTypeIndex = memoryTypeIndex;
86 if (vkAllocateMemory(device, &allocateInfo,
nullptr, &memory) != VK_SUCCESS) {
87 throw runtime_error(
"Could not allocate texture image memory!");
91 vkBindImageMemory(device, handle, memory, 0);
94 TextureImage::~TextureImage(
void) {
95 VkDevice device = VulkanContext::getCurrent()->getDevice()->getHandle();
98 vkDestroySampler(device, textureSampler,
nullptr);
99 vkDestroyImageView(device, imageView,
nullptr);
100 vkDestroyImage(device, handle,
nullptr);
101 vkFreeMemory(device, memory,
nullptr);
104 if (TextureImage::current ==
this) {
105 TextureImage::current =
nullptr;
109 VkImage TextureImage::getHandle() {
113 VkImageView TextureImage::getImageView() {
117 VkSampler TextureImage::getSampler() {
118 return textureSampler;
121 uint32_t TextureImage::getWidth() {
125 uint32_t TextureImage::getHeight() {
129 void TextureImage::upload(std::vector<uint8_t> data) {
130 VkDevice device = VulkanContext::getCurrent()->getDevice()->getHandle();
131 VkPhysicalDevice physicalDevice = VulkanContext::getCurrent()->getPhysicalDevice()->getHandle();
134 VkBuffer stagingBuffer;
135 VkDeviceMemory stagingBufferMemory;
138 VkBufferCreateInfo bufferInfo = {};
139 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
140 bufferInfo.size = data.size();
141 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
142 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
145 if (vkCreateBuffer(device, &bufferInfo,
nullptr, &stagingBuffer) != VK_SUCCESS) {
146 throw runtime_error(
"Could not create a staging buffer!");
150 VkMemoryRequirements memoryRequirements;
151 vkGetBufferMemoryRequirements(device, stagingBuffer, &memoryRequirements);
154 VkPhysicalDeviceMemoryProperties memoryProperties;
155 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
158 uint32_t memoryTypeIndex = -1;
159 VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
160 for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
161 if ((memoryRequirements.memoryTypeBits & (1 << i)) &&
162 (memoryProperties.memoryTypes[i].propertyFlags & flags) == flags) {
169 VkMemoryAllocateInfo allocateInfo = {};
170 allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
171 allocateInfo.allocationSize = memoryRequirements.size;
172 allocateInfo.memoryTypeIndex = memoryTypeIndex;
175 if (vkAllocateMemory(device, &allocateInfo,
nullptr, &stagingBufferMemory) != VK_SUCCESS) {
176 throw std::runtime_error(
"failed to allocate buffer memory!");
180 vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0);
184 vkMapMemory(device, stagingBufferMemory, 0, data.size(), 0, &mapData);
185 memcpy(mapData, data.data(), data.size());
186 vkUnmapMemory(device, stagingBufferMemory);
189 perfomImageLayoutTransition(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
190 copyBufferToImage(stagingBuffer, handle);
191 perfomImageLayoutTransition(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
194 vkDestroyBuffer(device, stagingBuffer,
nullptr);
195 vkFreeMemory(device, stagingBufferMemory,
nullptr);
198 VkImageViewCreateInfo viewInfo = {};
199 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
200 viewInfo.image = handle;
201 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
202 viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
203 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
204 viewInfo.subresourceRange.baseMipLevel = 0;
205 viewInfo.subresourceRange.levelCount = 1;
206 viewInfo.subresourceRange.baseArrayLayer = 0;
207 viewInfo.subresourceRange.layerCount = 1;
210 if (vkCreateImageView(device, &viewInfo,
nullptr, &imageView) != VK_SUCCESS) {
211 throw runtime_error(
"Could not create a texture image view!");
215 VkSamplerCreateInfo samplerInfo = {};
216 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
217 samplerInfo.magFilter = VK_FILTER_LINEAR;
218 samplerInfo.minFilter = VK_FILTER_LINEAR;
219 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
220 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
221 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
222 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
223 samplerInfo.mipLodBias = 0.0f;
224 samplerInfo.anisotropyEnable = VK_FALSE;
225 samplerInfo.maxAnisotropy = 1;
226 samplerInfo.compareEnable = VK_FALSE;
227 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
228 samplerInfo.minLod = 0.0f;
229 samplerInfo.maxLod = 0.0f;
230 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
231 samplerInfo.unnormalizedCoordinates = VK_FALSE;
234 if (vkCreateSampler(device, &samplerInfo,
nullptr, &textureSampler) != VK_SUCCESS) {
235 throw runtime_error(
"Could not create a texture sampler!");
239 void TextureImage::perfomImageLayoutTransition(VkImageLayout oldLayout, VkImageLayout newLayout) {
240 VkDevice device = VulkanContext::getCurrent()->getDevice()->getHandle();
241 VkCommandPool commandPool = VulkanContext::getCurrent()->getCommandPool()->getHandle();
242 VkQueue queue = VulkanContext::getCurrent()->getDevice()->getQueues().graphics;
245 VkCommandBufferAllocateInfo allocateInfo = {};
246 allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
247 allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
248 allocateInfo.commandPool = commandPool;
249 allocateInfo.commandBufferCount = 1;
252 VkCommandBuffer commandBuffer;
253 vkAllocateCommandBuffers(device, &allocateInfo, &commandBuffer);
256 VkCommandBufferBeginInfo beginInfo = {};
257 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
258 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
261 vkBeginCommandBuffer(commandBuffer, &beginInfo);
264 VkAccessFlags sourceAccessMask;
265 VkAccessFlags destinationAccessMask;
266 VkPipelineStageFlags sourceStage;
267 VkPipelineStageFlags destinationStage;
268 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
269 sourceAccessMask = 0;
270 destinationAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
271 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
272 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
273 }
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
274 sourceAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
275 destinationAccessMask = VK_ACCESS_SHADER_READ_BIT;
276 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
277 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
279 throw invalid_argument(
"Unsupported layout transition!");
283 VkImageMemoryBarrier barrier = {};
284 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
285 barrier.srcAccessMask = sourceAccessMask;
286 barrier.dstAccessMask = destinationAccessMask;
287 barrier.oldLayout = oldLayout;
288 barrier.newLayout = newLayout;
289 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
290 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
291 barrier.image = handle;
292 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
293 barrier.subresourceRange.baseMipLevel = 0;
294 barrier.subresourceRange.levelCount = 1;
295 barrier.subresourceRange.baseArrayLayer = 0;
296 barrier.subresourceRange.layerCount = 1;
299 vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0,
nullptr, 0,
nullptr, 1, &barrier);
302 vkEndCommandBuffer(commandBuffer);
305 VkSubmitInfo submitInfo = {};
306 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
307 submitInfo.commandBufferCount = 1;
308 submitInfo.pCommandBuffers = &commandBuffer;
311 vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
312 vkQueueWaitIdle(queue);
315 vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
318 void TextureImage::copyBufferToImage(VkBuffer stagingBuffer, VkImage image) {
319 VkDevice device = VulkanContext::getCurrent()->getDevice()->getHandle();
320 VkCommandPool commandPool = VulkanContext::getCurrent()->getCommandPool()->getHandle();
321 VkQueue queue = VulkanContext::getCurrent()->getDevice()->getQueues().graphics;
324 VkCommandBufferAllocateInfo allocateInfo = {};
325 allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
326 allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
327 allocateInfo.commandPool = commandPool;
328 allocateInfo.commandBufferCount = 1;
331 VkCommandBuffer commandBuffer;
332 vkAllocateCommandBuffers(device, &allocateInfo, &commandBuffer);
335 VkCommandBufferBeginInfo beginInfo = {};
336 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
337 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
340 vkBeginCommandBuffer(commandBuffer, &beginInfo);
343 VkBufferImageCopy region = {};
344 region.bufferOffset = 0;
345 region.bufferRowLength = 0;
346 region.bufferImageHeight = 0;
347 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
348 region.imageSubresource.mipLevel = 0;
349 region.imageSubresource.baseArrayLayer = 0;
350 region.imageSubresource.layerCount = 1;
351 region.imageOffset = {0, 0, 0};
352 region.imageExtent = {width, height, 1};
355 vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
358 vkEndCommandBuffer(commandBuffer);
361 VkSubmitInfo submitInfo = {};
362 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
363 submitInfo.commandBufferCount = 1;
364 submitInfo.pCommandBuffers = &commandBuffer;
367 vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
368 vkQueueWaitIdle(queue);
371 vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
VkImage getHandle()
Returns the handle of the texture image.
Generic namespace for the SimpleGL framework.
This class wraps a Vulkan texture image.