diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 143 |
1 files changed, 109 insertions, 34 deletions
@@ -96,6 +96,7 @@ static VkBuffer vertex_buffer; static VkDeviceMemory vertex_buffer_memory; static VkBuffer index_buffer; static VkDeviceMemory index_buffer_memory; +static uint32_t mip_levels; static VkImage texture_image; static VkDeviceMemory texture_image_memory; static VkImageView texture_view; @@ -510,7 +511,7 @@ void create_swapchain() { } -VkImageView create_image_view(VkImage image, VkFormat format, VkImageAspectFlags aspect_flags) { +VkImageView create_image_view(VkImage image, VkFormat format, VkImageAspectFlags aspect_flags, uint32_t mip_level) { VkImageViewCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = image, @@ -525,7 +526,7 @@ VkImageView create_image_view(VkImage image, VkFormat format, VkImageAspectFlags .subresourceRange = { .aspectMask = aspect_flags, .baseMipLevel = 0, - .levelCount = 1, + .levelCount = mip_level, .baseArrayLayer = 0, .layerCount = 1 } @@ -547,7 +548,7 @@ void create_image_views() { swapchain_image_views->len = swapchain_images->len; for (size_t i = 0; i < swapchain_images->len; i++) { - swapchain_image_views->data[i] = create_image_view(swapchain_images->data[i], swapchain_format, VK_IMAGE_ASPECT_COLOR_BIT); + swapchain_image_views->data[i] = create_image_view(swapchain_images->data[i], swapchain_format, VK_IMAGE_ASPECT_COLOR_BIT, 1); } } @@ -1223,7 +1224,7 @@ void create_descriptor_sets() { } } -void create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, +void create_image(uint32_t width, uint32_t height, uint32_t mip_level, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags props, VkImage *img, VkDeviceMemory *memory) { VkImageCreateInfo image_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, @@ -1233,7 +1234,7 @@ void create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTilin .height = height, .depth = 1 }, - .mipLevels = 1, + .mipLevels = mip_level, .arrayLayers = 1, .format = format, .tiling = tiling, @@ -1267,7 +1268,7 @@ void create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTilin vkBindImageMemory(gpu, *img, *memory, 0); } -void transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) { +void transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout, uint32_t mip_level) { VkCommandBuffer command_buffer = being_single_command(); VkImageMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, @@ -1279,7 +1280,7 @@ void transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_l .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, - .levelCount = 1, + .levelCount = mip_level, .baseArrayLayer = 0, .layerCount = 1 }, @@ -1312,6 +1313,93 @@ void transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_l end_single_command(command_buffer); } +void generate_mipmaps(VkImage image, VkFormat image_format, int32_t width, int32_t height, uint32_t mip_levels) { + VkFormatProperties format_props; + vkGetPhysicalDeviceFormatProperties(phy_gpu, image_format, &format_props); + if (!(format_props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) { + fputs("texture image format does not support linear blitting", stderr); + exit(-1); + } + VkCommandBuffer command_buffer = being_single_command(); + + VkImageMemoryBarrier barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .image = image, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .subresourceRange = { + .layerCount = 1, + .levelCount = 1, + .baseArrayLayer = 0, + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT + }, + }; + + int32_t mip_width = width, mip_height = height; + + for (size_t i = 1; i < mip_levels; i++) { + barrier.subresourceRange.baseMipLevel = i - 1; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + VkImageBlit blit = { + .srcOffsets = { + { 0, 0, 0 }, + { mip_width, mip_height, 1 } + }, + .srcSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = i - 1, + .baseArrayLayer = 0, + .layerCount = 1 + }, + .dstOffsets = { + { 0, 0, 0 }, + { mip_width > 1 ? mip_width / 2 : 1, mip_height > 1 ? mip_height / 2 : 1, 1 }, + }, + .dstSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = i, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + + vkCmdBlitImage(command_buffer, + image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, VK_FILTER_LINEAR); + + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + + if (mip_width > 1) + mip_width /= 2; + if (mip_height > 1) + mip_height /= 2; + } + + barrier.subresourceRange.baseMipLevel = mip_levels - 1; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + + end_single_command(command_buffer); +} + void create_texture_image() { int32_t width, height, channels; @@ -1321,6 +1409,8 @@ void create_texture_image() { exit(-1); } + mip_levels = floor(log2(width > height ? width : height)) + 1; + VkDeviceSize image_size = width * height * 4; VkBuffer tmp_buffer; @@ -1336,23 +1426,26 @@ void create_texture_image() { stbi_image_free(pixels); - create_image(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, &texture_image, &texture_image_memory); + create_image(width, height, mip_levels, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &texture_image, &texture_image_memory); transition_image_layout(texture_image, VK_FORMAT_R8G8B8A8_SRGB, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mip_levels); copy_buffer_to_image(tmp_buffer, texture_image, width, height); - transition_image_layout(texture_image, VK_FORMAT_R8G8B8A8_SRGB, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); +// transition_image_layout(texture_image, VK_FORMAT_R8G8B8A8_SRGB, +// VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, mip_levels); + + generate_mipmaps(texture_image, VK_FORMAT_R8G8B8A8_SRGB, width, height, mip_levels); vkDestroyBuffer(gpu, tmp_buffer, NULL); vkFreeMemory(gpu, tmp_mem, NULL); } void create_texture_view() { - texture_view = create_image_view(texture_image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT); + texture_view = create_image_view(texture_image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, mip_levels); } void create_texture_sampler() { @@ -1374,7 +1467,7 @@ void create_texture_sampler() { .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, .mipLodBias = 0.0f, .minLod = 0.0f, - .maxLod = 0.0f + .maxLod = VK_LOD_CLAMP_NONE }; VkResult res = vkCreateSampler(gpu, &sampler_info, NULL, &texture_sampler); @@ -1386,10 +1479,10 @@ void create_texture_sampler() { void create_depth_resources() { VkFormat depth_format = VK_FORMAT_D32_SFLOAT; - create_image(swapchain_extent.width, swapchain_extent.height, VK_FORMAT_D32_SFLOAT, VK_IMAGE_TILING_OPTIMAL, + create_image(swapchain_extent.width, swapchain_extent.height, 1, VK_FORMAT_D32_SFLOAT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &depth_image, &depth_memory); - depth_image_view = create_image_view(depth_image, VK_FORMAT_D32_SFLOAT, VK_IMAGE_ASPECT_DEPTH_BIT); + depth_image_view = create_image_view(depth_image, VK_FORMAT_D32_SFLOAT, VK_IMAGE_ASPECT_DEPTH_BIT, 1); } void recreate_swapchain() { @@ -1411,24 +1504,6 @@ void recreate_swapchain() { create_framebuffers(); } -void get_data(void *ctx, const char *filename, const int is_mtl, const char *obj_filename, char **data, size_t *len) { - (void) ctx; - if (!filename) { - fputs("null filename", stderr); - *data = NULL; - *len = 0; - return; - } - - FILE *fp = fopen(filename, "rb"); - fseek(fp, 0, SEEK_END); - *len = ftell(fp); - rewind(fp); - *data = calloc(*len, 1); - fread(*data, 1, *len + 1, fp); - fclose(fp); -} - void load_model() { vertices = calloc(1, sizeof(*vertices) + sizeof(*vertices->data) * 65535); vertices->cap = 65535; |