summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortalha aamir <talha@talhaamir.xyz>2025-09-30 06:26:07 +0500
committertalha aamir <talha@talhaamir.xyz>2025-09-30 06:26:07 +0500
commitd0fa49f8105242b0d6f6f5e53ca6ef62f10fbe34 (patch)
treea0666c5907b672846e23a597e611bdd71f942b22
parent6200b0c01ef1cbe86ced432c5b668676c1d78f4b (diff)
Texture Mapping -> Images Completedmaster
-rwxr-xr-xmain.cpp294
1 files changed, 258 insertions, 36 deletions
diff --git a/main.cpp b/main.cpp
index af91be9..2b7ac69 100755
--- a/main.cpp
+++ b/main.cpp
@@ -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,
+ &region);
+
+
+ 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
{