Skip to content

Commit bb20b90

Browse files
committed
Image Loading
1 parent 8b6042a commit bb20b90

9 files changed

Lines changed: 155 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
bin
22
build
3+
.vscode
34

45
# CMake
56
CMakeLists.txt.user

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "libs/SDL"]
22
path = libs/SDL
33
url = https://github.com/libsdl-org/SDL.git
4+
[submodule "libs/stb"]
5+
path = libs/stb
6+
url = https://github.com/nothings/stb.git

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ endif(WIN32)
3333
add_executable(vulkan_tutorial ${SOURCE_FILES})
3434
add_dependencies(vulkan_tutorial build_shaders)
3535
target_include_directories(vulkan_tutorial PUBLIC libs/SDL/include)
36+
target_include_directories(vulkan_tutorial PUBLIC libs)
3637
target_link_libraries(vulkan_tutorial PUBLIC SDL2-static)
3738
target_include_directories(vulkan_tutorial PUBLIC ${Vulkan_INCLUDE_DIRS})
3839
target_link_libraries(vulkan_tutorial PUBLIC ${Vulkan_LIBRARIES})

data/images/logo.png

78 KB
Loading

libs/SDL

Submodule SDL updated 1250 files

libs/stb

Submodule stb added at af1a5bc

src/main.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#include <SDL.h>
33
#include <SDL_vulkan.h>
44

5+
#define STB_IMAGE_IMPLEMENTATION
6+
#include <stb/stb_image.h>
7+
58
#include "logger.h"
69
#include "vulkan_base/vulkan_base.h"
710

@@ -20,6 +23,7 @@ VkSemaphore acquireSemaphores[FRAMES_IN_FLIGHT];
2023
VkSemaphore releaseSemaphores[FRAMES_IN_FLIGHT];
2124
VulkanBuffer vertexBuffer;
2225
VulkanBuffer indexBuffer;
26+
VulkanImage image;
2327

2428
bool handleMessage() {
2529
SDL_Event event;
@@ -140,6 +144,17 @@ void initApplication(SDL_Window* window) {
140144

141145
createBuffer(context, &indexBuffer, sizeof(indexData), VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
142146
uploadDataToBuffer(context, &indexBuffer, indexData, sizeof(indexData));
147+
148+
{
149+
int width, height, channels;
150+
uint8_t* data = stbi_load("../data/images/logo.png", &width, &height, &channels, 4);
151+
if(!data) {
152+
LOG_ERROR("Could not load image data");
153+
}
154+
createImage(context, &image, width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
155+
uploadDataToImage(context, &image, data, width * height * 4, width, height, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
156+
stbi_image_free(data);
157+
}
143158
}
144159

145160
void recreateSwapchain() {
@@ -248,6 +263,8 @@ void shutdownApplication() {
248263
destroyBuffer(context, &vertexBuffer);
249264
destroyBuffer(context, &indexBuffer);
250265

266+
destroyImage(context, &image);
267+
251268
for(uint32_t i = 0; i < FRAMES_IN_FLIGHT; ++i) {
252269
VK(vkDestroyFence(context->device, fences[i], 0));
253270
VK(vkDestroySemaphore(context->device, acquireSemaphores[i], 0));

src/vulkan_base/vulkan_base.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ struct VulkanBuffer {
4747
VkDeviceMemory memory;
4848
};
4949

50+
struct VulkanImage {
51+
VkImage image;
52+
VkImageView view;
53+
VkDeviceMemory memory;
54+
};
55+
5056
VulkanContext* initVulkan(uint32_t instanceExtensionCount, const char** instanceExtensions, uint32_t deviceExtensionCount, const char** deviceExtensions);
5157
void exitVulkan(VulkanContext* context);
5258

@@ -60,5 +66,9 @@ void createBuffer(VulkanContext* context, VulkanBuffer* buffer, uint64_t size, V
6066
void uploadDataToBuffer(VulkanContext* context, VulkanBuffer* buffer, void* data, size_t size);
6167
void destroyBuffer(VulkanContext* context, VulkanBuffer* buffer);
6268

69+
void createImage(VulkanContext* context, VulkanImage* image, uint32_t width, uint32_t height, VkFormat format, VkImageUsageFlags usage);
70+
void uploadDataToImage(VulkanContext* context, VulkanImage* image, void* data, size_t size, uint32_t width, uint32_t height, VkImageLayout finalLayout, VkAccessFlags dstAccessMask);
71+
void destroyImage(VulkanContext* context, VulkanImage* image);
72+
6373
VulkanPipeline createPipeline(VulkanContext* context, const char* vertexShaderFilename, const char* fragmentShaderFilename, VkRenderPass renderPass, uint32_t width, uint32_t height, VkVertexInputAttributeDescription* attributes, uint32_t numAttributes, VkVertexInputBindingDescription* binding);
6474
void destroyPipeline(VulkanContext* context, VulkanPipeline* pipeline);

src/vulkan_base/vulkan_utils.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,125 @@ void destroyBuffer(VulkanContext* context, VulkanBuffer* buffer) {
9797
VK(vkDestroyBuffer(context->device, buffer->buffer, 0));
9898
// Assumes that the buffer owns its own memory block
9999
VK(vkFreeMemory(context->device, buffer->memory, 0));
100+
}
101+
102+
void createImage(VulkanContext* context, VulkanImage* image, uint32_t width, uint32_t height, VkFormat format, VkImageUsageFlags usage) {
103+
{
104+
VkImageCreateInfo createInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
105+
createInfo.imageType = VK_IMAGE_TYPE_2D;
106+
createInfo.extent.width = width;
107+
createInfo.extent.height = height;
108+
createInfo.extent.depth = 1;
109+
createInfo.mipLevels = 1;
110+
createInfo.arrayLayers = 1;
111+
createInfo.format = format;
112+
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
113+
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
114+
createInfo.usage = usage;
115+
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
116+
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
117+
VKA(vkCreateImage(context->device, &createInfo, 0, &image->image));
118+
}
119+
120+
VkMemoryRequirements memoryRequirements;
121+
VK(vkGetImageMemoryRequirements(context->device, image->image, &memoryRequirements));
122+
VkMemoryAllocateInfo allocateInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
123+
allocateInfo.allocationSize = memoryRequirements.size;
124+
allocateInfo.memoryTypeIndex = findMemoryType(context, memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
125+
VKA(vkAllocateMemory(context->device, &allocateInfo, 0, &image->memory));
126+
VKA(vkBindImageMemory(context->device, image->image, image->memory, 0));
127+
128+
{
129+
VkImageViewCreateInfo createInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
130+
createInfo.image = image->image;
131+
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
132+
createInfo.format = format;
133+
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
134+
createInfo.subresourceRange.levelCount = 1;
135+
createInfo.subresourceRange.layerCount = 1;
136+
VKA(vkCreateImageView(context->device, &createInfo, 0, &image->view));
137+
}
138+
}
139+
140+
void uploadDataToImage(VulkanContext* context, VulkanImage* image, void* data, size_t size, uint32_t width, uint32_t height, VkImageLayout finalLayout, VkAccessFlags dstAccessMask) {
141+
// Upload with staging buffer
142+
VulkanQueue* queue = &context->graphicsQueue;
143+
VkCommandPool commandPool;
144+
VkCommandBuffer commandBuffer;
145+
VulkanBuffer stagingBuffer;
146+
createBuffer(context, &stagingBuffer, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
147+
void* mapped;
148+
VKA(vkMapMemory(context->device, stagingBuffer.memory, 0, size, 0, &mapped));
149+
memcpy(mapped, data, size);
150+
VK(vkUnmapMemory(context->device, stagingBuffer.memory));
151+
{
152+
VkCommandPoolCreateInfo createInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
153+
createInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
154+
createInfo.queueFamilyIndex = queue->familyIndex;
155+
VKA(vkCreateCommandPool(context->device, &createInfo, 0, &commandPool));
156+
}
157+
{
158+
VkCommandBufferAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
159+
allocateInfo.commandPool = commandPool;
160+
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
161+
allocateInfo.commandBufferCount = 1;
162+
VKA(vkAllocateCommandBuffers(context->device, &allocateInfo, &commandBuffer));
163+
}
164+
165+
VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
166+
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
167+
VKA(vkBeginCommandBuffer(commandBuffer, &beginInfo));
168+
169+
{
170+
VkImageMemoryBarrier imageBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
171+
imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
172+
imageBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
173+
imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
174+
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
175+
imageBarrier.image = image->image;
176+
imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
177+
imageBarrier.subresourceRange.levelCount = 1;
178+
imageBarrier.subresourceRange.layerCount = 1;
179+
imageBarrier.srcAccessMask = 0;
180+
imageBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
181+
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &imageBarrier);
182+
}
183+
184+
VkBufferImageCopy region = {};
185+
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
186+
region.imageSubresource.layerCount = 1;
187+
region.imageExtent = {width, height, 1};
188+
VK(vkCmdCopyBufferToImage(commandBuffer, stagingBuffer.buffer, image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region));
189+
190+
{
191+
VkImageMemoryBarrier imageBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
192+
imageBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
193+
imageBarrier.newLayout = finalLayout;
194+
imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
195+
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
196+
imageBarrier.image = image->image;
197+
imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
198+
imageBarrier.subresourceRange.levelCount = 1;
199+
imageBarrier.subresourceRange.layerCount = 1;
200+
imageBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
201+
imageBarrier.dstAccessMask = VK_ACCESS_NONE;
202+
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &imageBarrier);
203+
}
204+
205+
VKA(vkEndCommandBuffer(commandBuffer));
206+
207+
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
208+
submitInfo.commandBufferCount = 1;
209+
submitInfo.pCommandBuffers = &commandBuffer;
210+
VKA(vkQueueSubmit(queue->queue, 1, &submitInfo, VK_NULL_HANDLE));
211+
VKA(vkQueueWaitIdle(queue->queue));
212+
213+
VK(vkDestroyCommandPool(context->device, commandPool, 0));
214+
destroyBuffer(context, &stagingBuffer);
215+
}
216+
217+
void destroyImage(VulkanContext* context, VulkanImage* image) {
218+
VK(vkDestroyImageView(context->device, image->view, 0));
219+
VK(vkDestroyImage(context->device, image->image, 0));
220+
VK(vkFreeMemory(context->device, image->memory, 0));
100221
}

0 commit comments

Comments
 (0)