diff --git a/src/main.c b/src/main.c index ef62c29..2e9f2b4 100644 --- a/src/main.c +++ b/src/main.c @@ -52,6 +52,17 @@ typedef struct AllocatedBufferStruct { VkDeviceMemory memory; } AllocatedBuffer; +typedef struct AllocatedImageStruct { + VkImage image; + VkDeviceMemory memory; +} AllocatedImage; + +typedef struct TextureStruct { + AllocatedImage image; + VkImageView view; + VkSampler sampler; +} Texture; + typedef struct MeshStruct { uint32_t vertex_count; AllocatedBuffer vertex_buffer; @@ -546,7 +557,9 @@ VkDevice create_logical_device(VkPhysicalDevice physical_device, QueueIndices qu queue_create_info[i].pQueuePriorities = &default_queue_priority; } - VkPhysicalDeviceFeatures device_features = {}; + VkPhysicalDeviceFeatures device_features = { + .samplerAnisotropy = VK_TRUE, + }; VkDeviceCreateInfo device_create_info = {}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; @@ -883,6 +896,60 @@ uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t type_filter return 0xFFFFFFFF; } +AllocatedImage allocate_image(VkPhysicalDevice physical_device, VkDevice device, VkImageType type, VkFormat format, VkExtent3D size, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkSampleCountFlagBits samples) { + VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = type, + .extent = size, + .mipLevels = 1, + .arrayLayers = 1, + .format = format, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .usage = usage, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .samples = samples, + .flags = 0, + }; + + AllocatedImage allocated = { + .memory = VK_NULL_HANDLE, + .image = VK_NULL_HANDLE, + }; + VkResult result = vkCreateImage(device, &image_info, 0, &allocated.image); + if(result != VK_SUCCESS) { + return allocated; + } + + VkMemoryRequirements memory_requirements; + vkGetImageMemoryRequirements(device, allocated.image, &memory_requirements); + + VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memory_requirements.size, + .memoryTypeIndex = find_memory_type(physical_device, memory_requirements.memoryTypeBits, properties), + }; + + result = vkAllocateMemory(device, &memory_info, 0, &allocated.memory); + if(result != VK_SUCCESS) { + vkDestroyImage(device, allocated.image, 0); + allocated.image = VK_NULL_HANDLE; + return allocated; + } + + result = vkBindImageMemory(device, allocated.image, allocated.memory, 0); + if(result != VK_SUCCESS) { + vkFreeMemory(device, allocated.memory, 0); + vkDestroyImage(device, allocated.image, 0); + allocated.memory = VK_NULL_HANDLE; + allocated.image = VK_NULL_HANDLE; + + return allocated; + } + + return allocated; +} + AllocatedBuffer allocate_buffer(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties) { AllocatedBuffer ret = {}; ret.memory = VK_NULL_HANDLE; @@ -934,6 +1001,11 @@ void deallocate_buffer(VkDevice device, AllocatedBuffer buffer) { vkFreeMemory(device, buffer.memory, 0); }; +void deallocate_image(VkDevice device, AllocatedImage image) { + vkDestroyImage(device, image.image, 0); + vkFreeMemory(device, image.memory, 0); +}; + AllocatedBuffer* allocate_buffers(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, uint32_t count) { AllocatedBuffer* buffers = malloc(sizeof(AllocatedBuffer)*count); if(buffers == 0) { @@ -955,7 +1027,7 @@ AllocatedBuffer* allocate_buffers(VkPhysicalDevice physical_device, VkDevice dev return buffers; } -VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBuffer source, VkBuffer dest, VkDeviceSize size) { +VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool) { VkCommandBufferAllocateInfo command_info = {}; command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; @@ -965,7 +1037,7 @@ VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQu VkCommandBuffer command_buffer; VkResult result = vkAllocateCommandBuffers(device, &command_info, &command_buffer); if(result != VK_SUCCESS) { - return result; + return VK_NULL_HANDLE; } VkCommandBufferBeginInfo begin_info = {}; @@ -975,41 +1047,96 @@ VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQu result = vkBeginCommandBuffer(command_buffer, &begin_info); if(result != VK_SUCCESS) { vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer); - return result; + return VK_NULL_HANDLE; } - VkBufferCopy copy_region = {}; - copy_region.srcOffset = 0; - copy_region.dstOffset = 0; - copy_region.size = size; - - vkCmdCopyBuffer(command_buffer, source, dest, 1, ©_region); - result = vkEndCommandBuffer(command_buffer); - if(result != VK_SUCCESS) { - vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer); - return result; - } + return command_buffer; +} +VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, VkQueue transfer_queue) { VkSubmitInfo submit_info = {}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &command_buffer; - result = vkQueueSubmit(transfer_queue, 1, &submit_info, 0); + VkResult result = vkQueueSubmit(transfer_queue, 1, &submit_info, 0); if(result != VK_SUCCESS) { vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer); return result; } result = vkQueueWaitIdle(transfer_queue); + vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer); + return result; +} + +VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBuffer source, VkBuffer dest, VkDeviceSize size) { + VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool); + + VkBufferCopy copy_region = {}; + copy_region.srcOffset = 0; + copy_region.dstOffset = 0; + copy_region.size = size; + + vkCmdCopyBuffer(command_buffer, source, dest, 1, ©_region); + VkResult result = vkEndCommandBuffer(command_buffer); if(result != VK_SUCCESS) { vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer); return result; } - vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer); + return command_end_single(device, command_buffer, transfer_pool, transfer_queue); +} - return VK_SUCCESS; +VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image) { + VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool); + + VkImageMemoryBarrier barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .oldLayout = old_layout, + .newLayout = new_layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + .baseMipLevel = 0, + .baseArrayLayer = 0, + }, + .srcAccessMask = 0, + .dstAccessMask = 0, + }; + vkCmdPipelineBarrier(command_buffer, 0, 0, 0, 0, 0, 0, 0, 1, &barrier); + + return command_end_single(device, command_buffer, transfer_pool, transfer_queue); +} + +VkResult command_copy_buffer_to_image(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkExtent3D image_size, VkBuffer source, VkImage dest) { + VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool); + + VkBufferImageCopy region = { + .bufferOffset = 0, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = { + .baseArrayLayer = 0, + .layerCount = 1, + .mipLevel = 0, + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + }, + .imageOffset = { + .x = 0, + .y = 0, + .z = 0, + }, + .imageExtent = image_size, + }; + + vkCmdCopyBufferToImage(command_buffer, source, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + return command_end_single(device, command_buffer, transfer_pool, transfer_queue); } AllocatedBuffer create_populated_buffer(VkPhysicalDevice physical_device, VkDevice device, void* data, VkDeviceSize size, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBufferUsageFlags usage) { @@ -1050,6 +1177,118 @@ AllocatedBuffer create_populated_buffer(VkPhysicalDevice physical_device, VkDevi return vertex_buffer; } +Texture load_texture(VkPhysicalDevice physical_device, VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkExtent2D size, uint32_t stride, VkFormat format, void* image_data){ + Texture ret = { + .image.image = VK_NULL_HANDLE, + .image.memory = VK_NULL_HANDLE, + .view = VK_NULL_HANDLE, + }; + + uint32_t image_size = size.width * size.height * stride; + AllocatedBuffer staging = allocate_buffer(physical_device, device, image_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if(staging.memory == VK_NULL_HANDLE) { + return ret; + } + + void* staging_ptr; + VkResult result = vkMapMemory(device, staging.memory, 0, image_size, 0, &staging_ptr); + if(result != VK_SUCCESS) { + deallocate_buffer(device, staging); + return ret; + } + + memcpy(staging_ptr, image_data, image_size); + + vkUnmapMemory(device, staging.memory); + + VkExtent3D full_extent = { + .width = size.width, + .height = size.height, + .depth = 1, + }; + AllocatedImage image = allocate_image(physical_device, device, VK_IMAGE_TYPE_2D, format, full_extent, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_SAMPLE_COUNT_1_BIT); + if(image.memory == VK_NULL_HANDLE) { + deallocate_buffer(device, staging); + deallocate_image(device, image); + return ret; + } + + result = command_transition_image_layout(device, transfer_pool, transfer_queue, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image.image); + if(result != VK_SUCCESS) { + deallocate_buffer(device, staging); + deallocate_image(device, image); + return ret; + } + + result = command_copy_buffer_to_image(device, transfer_pool, transfer_queue, full_extent, staging.buffer, image.image); + if(result != VK_SUCCESS) { + deallocate_buffer(device, staging); + deallocate_image(device, image); + return ret; + } + + + VkImageView view; + VkImageViewCreateInfo view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = image.image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .components = { + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .format = format, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .layerCount = 1, + .levelCount = 1, + .baseArrayLayer = 0, + .baseMipLevel = 0, + }, + }; + + result = vkCreateImageView(device, &view_info, 0, &view); + if(result != VK_SUCCESS) { + deallocate_buffer(device, staging); + deallocate_image(device, image); + return ret; + } + + VkSampler sampler; + VkSamplerCreateInfo sampler_info = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .magFilter = VK_FILTER_NEAREST, + .minFilter = VK_FILTER_NEAREST, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT, + .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT, + .anisotropyEnable = VK_TRUE, + .maxAnisotropy = 2, + .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK, + .unnormalizedCoordinates = VK_FALSE, + .compareEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_ALWAYS, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .mipLodBias = 0.0f, + .minLod = 0.0f, + .maxLod = 0.0f, + }; + + result = vkCreateSampler(device, &sampler_info, 0, &sampler); + if(result != VK_SUCCESS) { + deallocate_buffer(device, staging); + deallocate_image(device, image); + return ret; + } + + ret.image = image; + ret.view = view; + ret.sampler = sampler; + return ret; +} + VkPipeline create_graphics_pipeline( VkDevice device, VkExtent2D extent,