diff options
author | talha aamir <talha@talhaamir.xyz> | 2025-09-30 06:26:07 +0500 |
---|---|---|
committer | talha aamir <talha@talhaamir.xyz> | 2025-09-30 06:26:07 +0500 |
commit | d0fa49f8105242b0d6f6f5e53ca6ef62f10fbe34 (patch) | |
tree | a0666c5907b672846e23a597e611bdd71f942b22 /main.cpp | |
parent | 6200b0c01ef1cbe86ced432c5b668676c1d78f4b (diff) |
Texture Mapping -> Images Completedmaster
Diffstat (limited to 'main.cpp')
-rwxr-xr-x | main.cpp | 294 |
1 files changed, 258 insertions, 36 deletions
@@ -69,6 +69,9 @@ Progress Notes: Hello Triangle Lesson Completed #include "glm/glm.hpp" #include "glm/gtc/matrix_transform.hpp" +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + // Start utils typedef uint8_t u8; @@ -113,30 +116,30 @@ struct UniformBufferObject { // string struct Str256 { - char buffer[256]; - u32 len; + char buffer[256]; + u32 len; }; typedef struct Str256 Str256; internal Str256 str256(const char* str) { - Str256 res = {}; + Str256 res = {}; - u32 i = 0; - while (str[i] != '\0' && i < 256) { - res.buffer[i] = str[i]; - res.len++; - i++; - } + u32 i = 0; + while (str[i] != '\0' && i < 256) { + res.buffer[i] = str[i]; + res.len++; + i++; + } - return res; + return res; } internal bool str256_match(Str256 a, Str256 b) { - if (a.len != b.len) { - return false; - } + if (a.len != b.len) { + return false; + } - return memcmp(a.buffer, b.buffer, a.len) == 0; + return memcmp(a.buffer, b.buffer, a.len) == 0; } #define ARR_LEN(x) ((x) ? (sizeof((x))/sizeof((x)[0])) : 0) @@ -221,6 +224,9 @@ struct MegaState { std::vector<VkDeviceMemory> vk_mem_uniform_buffers; std::vector<void*> vk_mapped_uniform_buffers; + VkImage vk_tex_img; + VkDeviceMemory vk_mem_tex_img; + VkDescriptorSetLayout vk_descriptor_set_layout; VkDescriptorPool vk_descriptor_pool; std::vector<VkDescriptorSet> vk_descriptor_sets; @@ -401,6 +407,33 @@ u32 resize_swapchain(MegaState* state) { return 0; } +b8 vk_find_memory_type_index(VkPhysicalDevice physical_device, + VkMemoryRequirements mem_req, + VkMemoryPropertyFlags property_flags, + s32 *memory_index) { + *memory_index = -1; + + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties); + + // find memory meeting type requirements + for (u32 i = 0; i < memory_properties.memoryTypeCount; i++) { + b8 type_match = mem_req.memoryTypeBits & (1 << i); + b8 properties_match = (memory_properties.memoryTypes[i].propertyFlags + & property_flags) == property_flags; + + if (type_match && properties_match) { + *memory_index = i; + printf("Success::vk_find_memory_type_index: Found memory type index\n"); + return 1; + } + } + + // memory requirements did not match any memory properties + printf("Error::vk_find_memory_type_index: Failed to find memory type index\n"); + return 0; +} + b8 vk_create_buffer(VkDevice device, VkPhysicalDevice physical_device, VkDeviceSize size, @@ -415,36 +448,22 @@ b8 vk_create_buffer(VkDevice device, ci.usage = usage; ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - printf("Creating vulkan buffer\n"); if (vkCreateBuffer(device, &ci, nullptr, buffer) != VK_SUCCESS) { - printf("Failed to create buffer\n"); + printf("Error::vk_create_buffer: Failed to create buffer\n"); return 0; } + printf("Success::vk_create_buffer: Created vulkan buffer\n"); // find_matched_memory: VkMemoryRequirements mem_req; vkGetBufferMemoryRequirements(device, *buffer, &mem_req); s32 matched_mem_index = -1; - { - VkPhysicalDeviceMemoryProperties memory_properties; - vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties); - - // find memory meeting type requirement - for (u32 i = 0; i < memory_properties.memoryTypeCount; i++) { - b8 type_match = mem_req.memoryTypeBits & (1 << i); - b8 properties_match = (memory_properties.memoryTypes[i].propertyFlags - & property_flags) == property_flags; - if (type_match && properties_match) { - matched_mem_index = i; - break; - } - } - - if (matched_mem_index == -1) { - printf("Error! failed to find a memory that matches buffer requirements\n"); - return 0; - } + if (vk_find_memory_type_index(physical_device, + mem_req, + property_flags, + &matched_mem_index) == 0) { + return 0; } // allocate_memory: (debug_only) @@ -455,9 +474,10 @@ b8 vk_create_buffer(VkDevice device, ai_memory.memoryTypeIndex = matched_mem_index; if (vkAllocateMemory(device, &ai_memory, nullptr, buffer_memory) != VK_SUCCESS) { - printf("Error! failed to allocate device memory\n"); + printf("Error::vk_create_buffer: failed to allocate device memory\n"); return 0; } + printf("Success::vk_create_buffer: Allocated device memory\n"); } vkBindBufferMemory(device, *buffer, *buffer_memory, 0); @@ -465,6 +485,71 @@ b8 vk_create_buffer(VkDevice device, return 1; } +b8 vk_create_image(VkDevice vk_device, VkPhysicalDevice vk_physical_device, + u32 width, u32 height, + VkFormat format, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkMemoryPropertyFlags memory_properties, + VkImage *vk_image, + VkDeviceMemory *vk_mem_image) { + + VkImageCreateInfo ci_img{}; + ci_img.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + ci_img.imageType = VK_IMAGE_TYPE_2D; + ci_img.extent.width = width; + ci_img.extent.height = height; + ci_img.extent.depth = 1; + ci_img.mipLevels = 1; + ci_img.arrayLayers = 1; + ci_img.format = format; + ci_img.tiling = tiling; + ci_img.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + ci_img.usage = usage; + ci_img.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + ci_img.samples = VK_SAMPLE_COUNT_1_BIT; + ci_img.flags = 0; + + if (vkCreateImage(vk_device, &ci_img, nullptr, vk_image) + != VK_SUCCESS) { + printf("Error :: Failed to create image\n"); + return 0; + } + + // allocate_img_memory + VkMemoryRequirements img_mem_req; + vkGetImageMemoryRequirements(vk_device, + *vk_image, + &img_mem_req); + + s32 img_mem_type_index = -1; + if (vk_find_memory_type_index(vk_physical_device, img_mem_req, + memory_properties, + &img_mem_type_index) == 0) { + return 0; + } + + VkMemoryAllocateInfo ai_mem{}; + ai_mem.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + ai_mem.allocationSize = img_mem_req.size; + + ai_mem.memoryTypeIndex = img_mem_type_index; + + if (vkAllocateMemory(vk_device, + &ai_mem, nullptr, + vk_mem_image) != VK_SUCCESS) { + printf("Error:: Failed to allocate image memory\n"); + return 0; + } + + vkBindImageMemory(vk_device, + *vk_image, + *vk_mem_image, + 0); + + return 1; +} + int main() { MegaState state = {}; @@ -1381,6 +1466,141 @@ int main() { return -1; } } + // @func: create_texture_image: + { + s32 tex_width, tex_height, tex_chan; + stbi_uc *pixels = stbi_load("textures/spike_noodles.jpg", + &tex_width, &tex_height, &tex_chan, + STBI_rgb_alpha); + // shouldn't 4 be tex_chan (i.e. number of channels) + VkDeviceSize image_size = tex_width * tex_height * 4; + + if (!pixels) { + printf("Error :: Failed to load image\n"); + return -1; + } + + VkBuffer staging_buffer; + VkDeviceMemory staging_buffer_memory; + + vk_create_buffer(state.vk_device, state.vk_physical_device, 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 *staging_data; + vkMapMemory(state.vk_device, staging_buffer_memory, 0, image_size, 0, + &staging_data); + memcpy(staging_data, pixels, (size_t)image_size); + vkUnmapMemory(state.vk_device, staging_buffer_memory); + + stbi_image_free(pixels); + + vk_create_image(state.vk_device, state.vk_physical_device, + (s32)tex_width, (s32)tex_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.vk_tex_img, + &state.vk_mem_tex_img); + + // copy_buffer: + { + VkCommandBufferAllocateInfo ai_cmd{}; + ai_cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + ai_cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + ai_cmd.commandPool = vk_command_pool; + ai_cmd.commandBufferCount = 1; + + VkCommandBuffer vk_command_buffer; + vkAllocateCommandBuffers(state.vk_device, + &ai_cmd, + &vk_command_buffer); + { + VkCommandBufferBeginInfo bi_cmd{}; + bi_cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + bi_cmd.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(vk_command_buffer, &bi_cmd); + + // transition_image_layout: + + // transition barrier access masks and pipeline stages + // CASE: old: VK_IMAGE_LAYOUT_UNDEFINED + // new: VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + // srcAccessMask = 0 + // dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT + // sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT + // destStage = VK_PIPELINE_STAGE_TRANSFER_BIT + // + // CASE: old: VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + // new: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + // srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT + // dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + // sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT + // destStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT + // + + + VkImageMemoryBarrier img_transition_barrier{}; + img_transition_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + img_transition_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + img_transition_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + img_transition_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + img_transition_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + img_transition_barrier.image = state.vk_tex_img; + img_transition_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + img_transition_barrier.subresourceRange.baseMipLevel = 0; + img_transition_barrier.subresourceRange.levelCount = 1; + img_transition_barrier.subresourceRange.baseArrayLayer = 0; + img_transition_barrier.subresourceRange.layerCount = 1; + img_transition_barrier.srcAccessMask = 0; + img_transition_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + vkCmdPipelineBarrier(vk_command_buffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &img_transition_barrier); + + // copy_pixel_buffer_to_image: + VkBufferImageCopy region{}; + 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 = {0, 0, 0}; + region.imageExtent = { (u32)tex_width, (u32)tex_height, 1}; + + vkCmdCopyBufferToImage(vk_command_buffer, + staging_buffer, + state.vk_tex_img, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ®ion); + + + vkEndCommandBuffer(vk_command_buffer); + } + + vkFreeCommandBuffers(state.vk_device, vk_command_pool, 1, &vk_command_buffer); + } + vkDestroyBuffer(state.vk_device, staging_buffer, nullptr); + vkFreeMemory(state.vk_device, staging_buffer_memory, nullptr); + + } // @func: create_index_buffer: { u64 buffer_size = sizeof(indices[0]) * indices.size(); @@ -1898,6 +2118,8 @@ int main() { vkDestroyBuffer(state.vk_device, state.vk_index_buffer, nullptr); vkFreeMemory(state.vk_device, state.vk_mem_vertex_buffer, nullptr); vkFreeMemory(state.vk_device, state.vk_mem_index_buffer, nullptr); + vkDestroyImage(state.vk_device, state.vk_tex_img, nullptr); + vkFreeMemory(state.vk_device, state.vk_mem_tex_img, nullptr); // destroy framebuffers { |