Browse Source

Add image loading and layout transition.

master
Amber 2 years ago
parent
commit
bb190e9908
  1. 175
      src/main.c
  2. BIN
      src/res/texture.jpg
  3. 7897
      src/stb_image.h

175
src/main.c

@ -11,6 +11,8 @@ @@ -11,6 +11,8 @@
#include <cglm/cam.h>
#include <time.h>
#include <cglm/util.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define WIDTH 2560
#define HEIGHT 1440
@ -88,6 +90,9 @@ typedef struct ApplicationState { @@ -88,6 +90,9 @@ typedef struct ApplicationState {
VkDescriptorPool descriptor_pool;
VkDescriptorSet descriptor_sets[2];
VkImage texture_image;
VkDeviceMemory texture_image_memory;
} ApplicationState;
typedef struct QueueFamilyIndices {
@ -348,7 +353,7 @@ int cmp(const void* a, const void* b) { @@ -348,7 +353,7 @@ int cmp(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}
void create_logical_device(ApplicationState* state) {
void create_logical_device(ApplicationState* state) {;
//we already ensured that all of the required queues exist
QueueFamilyIndices indices = find_queue_families(state, state->physical_device);
@ -985,7 +990,7 @@ void create_buffer(ApplicationState* state, VkDeviceSize size, VkBufferUsageFlag @@ -985,7 +990,7 @@ void create_buffer(ApplicationState* state, VkDeviceSize size, VkBufferUsageFlag
vkBindBufferMemory(state->device, *buffer, *memory, 0);
}
void copy_buffer(ApplicationState* state, VkBuffer src, VkBuffer dst, VkDeviceSize size) {
VkCommandBuffer begin_single_time_commands(ApplicationState* state) {
VkCommandBufferAllocateInfo command_buf_allocate_info = {0};
command_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buf_allocate_info.commandPool = state->commandPool;
@ -1005,10 +1010,10 @@ void copy_buffer(ApplicationState* state, VkBuffer src, VkBuffer dst, VkDeviceSi @@ -1005,10 +1010,10 @@ void copy_buffer(ApplicationState* state, VkBuffer src, VkBuffer dst, VkDeviceSi
vkBeginCommandBuffer(buffer, &begin_info);
VkBufferCopy copy = {0};
copy.size = size;
vkCmdCopyBuffer(buffer, src, dst, 1, &copy);
return buffer;
}
void end_single_time_commands(ApplicationState* state, VkCommandBuffer buffer) {
vkEndCommandBuffer(buffer);
VkSubmitInfo submit_info = {0};
@ -1022,6 +1027,16 @@ void copy_buffer(ApplicationState* state, VkBuffer src, VkBuffer dst, VkDeviceSi @@ -1022,6 +1027,16 @@ void copy_buffer(ApplicationState* state, VkBuffer src, VkBuffer dst, VkDeviceSi
vkFreeCommandBuffers(state->device, state->commandPool, 1, &buffer);
}
void copy_buffer(ApplicationState* state, VkBuffer src, VkBuffer dst, VkDeviceSize size) {
VkCommandBuffer buffer = begin_single_time_commands(state);
VkBufferCopy copy = {0};
copy.size = size;
vkCmdCopyBuffer(buffer, src, dst, 1, &copy);
end_single_time_commands(state, buffer);
}
void create_vertex_buffer(ApplicationState* state) {
VkDeviceSize buffer_size = sizeof(Vertex) * ARRSIZE(vertices);
@ -1077,6 +1092,153 @@ void create_uniform_buffers(ApplicationState* state) { @@ -1077,6 +1092,153 @@ void create_uniform_buffers(ApplicationState* state) {
}
}
void create_image(ApplicationState* state, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling,
VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage* image, VkDeviceMemory* memory) {
VkImageCreateInfo image_info = {0};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.extent.width = width;
image_info.extent.height = height;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.format = format;
image_info.tiling = tiling;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.usage = usage;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
if (vkCreateImage(state->device, &image_info, NULL, image) != VK_SUCCESS) {
printf("failed to create image\n");
exit(1);
}
VkMemoryRequirements mem_req;
vkGetImageMemoryRequirements(state->device, state->texture_image, &mem_req);
VkMemoryAllocateInfo alloc_info = {0};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = mem_req.size;
alloc_info.memoryTypeIndex = find_memory_type(state, mem_req.memoryTypeBits, properties);
if (vkAllocateMemory(state->device, &alloc_info, NULL, memory) != VK_SUCCESS) {
printf("failed to allocate memory for buffer\n");
exit(1);
}
vkBindImageMemory(state->device, *image, *memory, 0);
}
void transition_image_layout(ApplicationState* state, VkImage image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) {
VkCommandBuffer buffer = begin_single_time_commands(state);
VkImageMemoryBarrier barrier = {0};
VkPipelineStageFlags source_stage;
VkPipelineStageFlags destination_stage;
//specify barrier masks
if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destination_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
} else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
destination_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else {
exit(1);
}
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = old_layout;
barrier.newLayout = new_layout;
//these are necessary if the barrier is used to transfer ownership
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(buffer,
source_stage, destination_stage,
0,
0, NULL,
0, NULL,
1, &barrier);
end_single_time_commands(state, buffer);
}
void copy_buffer_to_image(ApplicationState* state, VkBuffer to_copy, VkImage image, uint32_t width, uint32_t height) {
VkCommandBuffer buffer = begin_single_time_commands(state);
VkBufferImageCopy region = {0};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset.x = 0;
region.imageOffset.y = 0;
region.imageOffset.z = 0;
region.imageExtent.width = width;
region.imageExtent.height = height;
region.imageExtent.depth = 1;
vkCmdCopyBufferToImage(buffer, to_copy, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
end_single_time_commands(state, buffer);
}
void create_texture_image(ApplicationState* state) {
int width, height, channels;
stbi_uc* pixels = stbi_load("../src/res/texture.jpg", &width, &height, &channels, STBI_rgb_alpha);
if (!pixels) {
printf("failed to load texture\n");
exit(1);
}
VkDeviceSize image_size = width * height * 4;
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
create_buffer(state, image_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&staging_buffer, &staging_buffer_memory);
void* data;
vkMapMemory(state->device, staging_buffer_memory, 0, image_size, 0, &data);
memcpy(data, pixels, image_size);
vkUnmapMemory(state->device, staging_buffer_memory);
stbi_image_free(pixels);
create_image(state, width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&state->texture_image, &state->texture_image_memory);
printf("created image texture\n");
transition_image_layout(state, state->texture_image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
copy_buffer_to_image(state, staging_buffer, state->texture_image, width, height);
transition_image_layout(state, state->texture_image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkDestroyBuffer(state->device, staging_buffer, NULL);
vkFreeMemory(state->device, staging_buffer_memory, NULL);
}
void create_descriptor_pool(ApplicationState* state) {
VkDescriptorPoolSize pool_size = {0};
pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@ -1250,6 +1412,7 @@ void init_vulkan(ApplicationState* state) { @@ -1250,6 +1412,7 @@ void init_vulkan(ApplicationState* state) {
create_graphics_pipeline(state);
create_framebuffers(state);
create_command_pool(state);
create_texture_image(state);
create_vertex_buffer(state);
create_index_buffer(state);
create_uniform_buffers(state);
@ -1371,6 +1534,8 @@ void terminate(ApplicationState* state) { @@ -1371,6 +1534,8 @@ void terminate(ApplicationState* state) {
vkFreeMemory(state->device, state->vertex_buffer_memory, NULL);
vkDestroyBuffer(state->device, state->index_buffer, NULL);
vkFreeMemory(state->device, state->index_buffer_memory, NULL);
vkDestroyImage(state->device, state->texture_image, NULL);
vkFreeMemory(state->device, state->texture_image_memory, NULL);
vkDestroySwapchainKHR(state->device, state->swapchain, NULL);
vkDestroyDevice(state->device, NULL);

BIN
src/res/texture.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

7897
src/stb_image.h

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save