From 0898bfdf5d8e1c468a2d0aa8a3a7e320c4578dd3 Mon Sep 17 00:00:00 2001 From: gramanas Date: Fri, 24 May 2024 15:08:47 +0300 Subject: Depth buffers --- src/game.c | 643 ++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 471 insertions(+), 172 deletions(-) (limited to 'src/game.c') diff --git a/src/game.c b/src/game.c index c566f85..50f686e 100644 --- a/src/game.c +++ b/src/game.c @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -15,6 +15,9 @@ #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #include "vk_mem_alloc.h" +#define STB_IMAGE_IMPLEMENTATION +#include "../lib/stb_image.h" + //#include "cplusplus.h" #include "vkutil.h" #include "state.h" @@ -23,15 +26,16 @@ uint32_t currentFrame = 0; state_t s; -const uint32_t validation_layer_count = 1; const char *const validation_layers[] = { "VK_LAYER_KHRONOS_validation" }; +const uint32_t validation_layer_count = VK_ARRAY_LEN(validation_layers); -const uint32_t deviceExtensionCount = 1; -const char *const deviceExtensions[] = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, +const char *const device_extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; +const uint32_t deviceExtensionCount = VK_ARRAY_LEN(device_extensions); + #ifdef VKDEBUG const bool enableValidationLayers = true; @@ -51,8 +55,9 @@ typedef struct { } V3; typedef struct { - V2 pos; + V3 pos; V3 color; + V2 texCoord; } Vertex; /* Vertex vertices[] = { */ @@ -76,15 +81,19 @@ typedef struct { /* const int INDICES_SIZE = VK_ARRAY_LEN(indices); */ Vertex vertices[] = { - (Vertex) { (V2) {-0.5f, -0.5f}, (V3) {1.0f, 0.0f, 0.0f}}, - (Vertex) { (V2) {0.5f, -0.5f}, (V3) {0.0f, 1.0f, 0.0f}}, - (Vertex) { (V2) {0.5f, 0.5f}, (V3) {0.0f, 0.0f, 1.0f}}, - (Vertex) { (V2) {-0.5f, 0.5f}, (V3) {1.0f, 1.0f, 1.0f}}, + (Vertex) { (V3) {-0.5f, -0.5f, 0.0f}, (V3) {1.0f, 0.0f, 0.0f}, (V2) {0.0f, 0.0f}}, + (Vertex) { (V3) {0.5f, -0.5f, 0.0f}, (V3) {0.0f, 1.0f, 0.0f}, (V2) {1.0f, 0.0f}}, + (Vertex) { (V3) {0.5f, 0.5f, 0.0f}, (V3) {0.0f, 0.0f, 1.0f}, (V2) {1.0f, 1.0f}}, + (Vertex) { (V3) {-0.5f, 0.5f, 0.0f}, (V3) {1.0f, 1.0f, 1.0f}, (V2) {0.0f, 1.0f}}, + (Vertex) { (V3) {-0.5f, -0.5f, -0.5f}, (V3) {1.0f, 0.0f, 0.0f}, (V2) {0.0f, 0.0f}}, + (Vertex) { (V3) {0.5f, -0.5f, -0.5f}, (V3) {0.0f, 1.0f, 0.0f}, (V2) {1.0f, 0.0f}}, + (Vertex) { (V3) {0.5f, 0.5f, -0.5f}, (V3) {0.0f, 0.0f, 1.0f}, (V2) {1.0f, 1.0f}}, + (Vertex) { (V3) {-0.5f, 0.5f, -0.5f}, (V3) {1.0f, 1.0f, 1.0f}, (V2) {0.0f, 1.0f}}, }; const int VERTICES_SIZE = VK_ARRAY_LEN(vertices); const uint16_t indices[] = { - 0, 1, 2, 2, 3, 0 + 0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4 }; const int INDICES_SIZE = VK_ARRAY_LEN(indices); @@ -411,7 +420,7 @@ vulkan_check_device_extension_support(VkPhysicalDevice device) for (uint32_t i = 0; i < deviceExtensionCount; i++) { for (uint32_t j = 0; j < extensionCount; j++) { - if (strcmp(deviceExtensions[i], availableExtensions[j].extensionName) == 0) { + if (strcmp(device_extensions[i], availableExtensions[j].extensionName) == 0) { flag++; break; } @@ -433,7 +442,12 @@ vulkan_is_device_suitable(VkPhysicalDevice device) swapChainAdequate = !(swapChainSupport.formatCount == 0) && !(swapChainSupport.presentModeCount == 0); } - return vulkan_queue_family_check_flags(indices) && extensionsSupported && swapChainAdequate; + + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(device, &supportedFeatures); + + return vulkan_queue_family_check_flags(indices) && extensionsSupported + && swapChainAdequate && supportedFeatures.samplerAnisotropy; } void @@ -494,6 +508,7 @@ vulkan_create_logical_device() VkPhysicalDeviceFeatures deviceFeatures = {0}; vkGetPhysicalDeviceFeatures(s.vk_physical_device, &deviceFeatures); + deviceFeatures.samplerAnisotropy = VK_TRUE; #ifndef NDEBUG /* Disable robust buffer access when building without debug */ deviceFeatures.robustBufferAccess = VK_FALSE; @@ -511,7 +526,7 @@ vulkan_create_logical_device() .pNext = &dynamic_rendering_feature, .pEnabledFeatures = &deviceFeatures, .enabledExtensionCount = deviceExtensionCount, - .ppEnabledExtensionNames = deviceExtensions, + .ppEnabledExtensionNames = device_extensions, .enabledLayerCount = 0, }; @@ -630,29 +645,32 @@ vulkan_create_swap_chain() vk_log(VK_INFO, "Vulkan swapchain created!\n"); } + +VkImageView +create_image_view(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) +{ + VkImageViewCreateInfo viewInfo = {0}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = format; + viewInfo.subresourceRange.aspectMask = aspectFlags; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + VkImageView imageView; + VK_CHECK(vkCreateImageView(s.vk_device, &viewInfo, NULL, &imageView)); + + return imageView; +} + void vulkan_create_image_views() { for (size_t i = 0; i < s.vk_swap_chain_image_count; i++) { - VkImageViewCreateInfo createInfo = { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = s.vk_swap_chain_images[i], - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = s.vk_swap_chain_image_format, - .components.r = VK_COMPONENT_SWIZZLE_IDENTITY, - .components.g = VK_COMPONENT_SWIZZLE_IDENTITY, - .components.b = VK_COMPONENT_SWIZZLE_IDENTITY, - .components.a = VK_COMPONENT_SWIZZLE_IDENTITY, - .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .subresourceRange.baseMipLevel = 0, - .subresourceRange.levelCount = 1, - .subresourceRange.baseArrayLayer = 0, - .subresourceRange.layerCount = 1, - }; - - if (vkCreateImageView(s.vk_device, &createInfo, NULL, &s.vk_swap_chain_image_views[i]) != VK_SUCCESS) { - vk_log(VK_ERROR, "failed to create image views!\n"); - } + s.vk_swap_chain_image_views[i] = create_image_view(s.vk_swap_chain_images[i], s.vk_swap_chain_image_format, VK_IMAGE_ASPECT_COLOR_BIT); } vk_log(VK_INFO, "Vulkan image views created!\n"); } @@ -725,6 +743,192 @@ load_compile_shader_data(const char * path, shaderc_shader_kind shader_kind) return result; } +uint32_t +findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) +{ + VkPhysicalDeviceMemoryProperties memProperties; + vkGetPhysicalDeviceMemoryProperties(s.vk_physical_device, &memProperties); + + for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { + if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { + return i; + } + } + + vk_log(VK_ERROR, "failed to find suitable memory type!\n"); + return 9999; +} + +void +createImage(uint32_t width, uint32_t height, VkFormat format, + VkImageTiling tiling, VkImageUsageFlags usage, + VkMemoryPropertyFlags properties, VkImage *image, + VkDeviceMemory *imageMemory) +{ + VkImageCreateInfo imageInfo = {0}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = width; + imageInfo.extent.height = height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = format; + imageInfo.tiling = tiling; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = usage; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VK_CHECK(vkCreateImage(s.vk_device, &imageInfo, NULL, image)); + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(s.vk_device, *image, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {0}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); + + VK_CHECK(vkAllocateMemory(s.vk_device, &allocInfo, NULL, imageMemory)); + + vkBindImageMemory(s.vk_device, *image, *imageMemory , 0); +} + +VkCommandBuffer +beginSingleTimeCommands() +{ + VkCommandBufferAllocateInfo allocInfo = {0}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = s.vk_command_pool; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + VK_CHECK(vkAllocateCommandBuffers(s.vk_device, &allocInfo, &commandBuffer)); + + VkCommandBufferBeginInfo beginInfo = {0}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + VK_CHECK(vkBeginCommandBuffer(commandBuffer, &beginInfo)); + + return commandBuffer; +} + +void +endSingleTimeCommands(VkCommandBuffer commandBuffer) +{ + VK_CHECK(vkEndCommandBuffer(commandBuffer)); + + VkSubmitInfo submitInfo = {0}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + VK_CHECK(vkQueueSubmit(s.vk_graphics_queue, 1, &submitInfo, VK_NULL_HANDLE)); + VK_CHECK(vkQueueWaitIdle(s.vk_graphics_queue)); + + vkFreeCommandBuffers(s.vk_device, s.vk_command_pool, 1, &commandBuffer); +} + +int +hasStencilComponent(VkFormat format) +{ + return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; +} + +void +transitionImageLayout(VkImage image, VkFormat format, + VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, + VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, + VkImageLayout oldLayout, VkImageLayout newLayout) +{ + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + VkImageMemoryBarrier barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.srcAccessMask = srcAccessMask; + barrier.dstAccessMask = dstAccessMask; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + + // barrier.subresourceRange.aspectMask = + if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + if (hasStencilComponent(format)) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + 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(commandBuffer, + srcStageMask, dstStageMask, + 0, + 0, NULL, + 0, NULL, + 1, &barrier); + endSingleTimeCommands(commandBuffer); +} + +VkFormat +findSupportedFormat(VkFormat *candidates, size_t n, + VkImageTiling tiling, + VkFormatFeatureFlags features) +{ + for (size_t i = 0; i < n; i++) { + VkFormat format = candidates[i]; + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(s.vk_physical_device, format, &props); + + if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) { + return format; + } else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) { + return format; + } + } + + vk_log(VK_ERROR, "failed to find supported format!\n"); + abort(); +} + +VkFormat +findDepthFormat() +{ + VkFormat formats[] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}; + return findSupportedFormat(formats, VK_ARRAY_LEN(formats), + VK_IMAGE_TILING_OPTIMAL, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); +} + +void +vulkan_create_depth_resources() +{ + VkFormat depthFormat = findDepthFormat(); + createImage(s.vk_swap_chain_extent.width, s.vk_swap_chain_extent.height, + depthFormat, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + &s.vk_depth_image, &s.vk_depth_image_memory); + s.vk_depth_image_view = create_image_view(s.vk_depth_image, depthFormat, + VK_IMAGE_ASPECT_DEPTH_BIT); + + transitionImageLayout(s.vk_depth_image, depthFormat, + VK_ACCESS_NONE, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); +} + void vulkan_create_graphics_pipeline() { @@ -773,12 +977,14 @@ vulkan_create_graphics_pipeline() VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE }; VkPipelineDynamicStateCreateInfo dynamicState = {0}; dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicState.dynamicStateCount = 2; + dynamicState.dynamicStateCount = VK_ARRAY_LEN(dynamicStates); dynamicState.pDynamicStates = dynamicStates; VkVertexInputBindingDescription bindingDescription = {0}; @@ -786,10 +992,10 @@ vulkan_create_graphics_pipeline() bindingDescription.stride = sizeof(Vertex); bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - VkVertexInputAttributeDescription attributeDescriptions[2] = {0}; + VkVertexInputAttributeDescription attributeDescriptions[3] = {0}; attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; - attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[0].offset = offsetof(Vertex, pos); attributeDescriptions[1].binding = 0; @@ -797,11 +1003,16 @@ vulkan_create_graphics_pipeline() attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[1].offset = offsetof(Vertex, color); + attributeDescriptions[2].binding = 0; + attributeDescriptions[2].location = 2; + attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions[2].offset = offsetof(Vertex, texCoord); + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {0}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputInfo.vertexBindingDescriptionCount = 1; vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; - vertexInputInfo.vertexAttributeDescriptionCount = 2; + vertexInputInfo.vertexAttributeDescriptionCount = VK_ARRAY_LEN(attributeDescriptions); vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions; VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; @@ -891,11 +1102,25 @@ vulkan_create_graphics_pipeline() vk_log(VK_ERROR, "failed to create pipeline layout!\n"); } + VkPipelineDepthStencilStateCreateInfo depthStencil = {0}; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.stencilTestEnable = VK_FALSE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.minDepthBounds = 0.0f; // Optional + depthStencil.maxDepthBounds = 1.0f; // Optional + depthStencil.front = (VkStencilOpState){0}; // Optional + depthStencil.back = (VkStencilOpState){0}; // Optional + + // TODO depthAttachment VkPipelineRenderingCreateInfo pipeline_rendering_create_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, .colorAttachmentCount = 1, .pColorAttachmentFormats = &s.vk_swap_chain_image_format, - }; + .depthAttachmentFormat = findDepthFormat(), + }; VkGraphicsPipelineCreateInfo pipelineInfo = {0}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = 2; @@ -907,7 +1132,7 @@ vulkan_create_graphics_pipeline() pipelineInfo.pViewportState = &viewportState; pipelineInfo.pRasterizationState = &rasterizer; pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pDepthStencilState = NULL; // Optional + pipelineInfo.pDepthStencilState = &depthStencil; pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = &dynamicState; pipelineInfo.layout = s.vk_pipeline_layout; @@ -968,56 +1193,45 @@ recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) beginInfo.pInheritanceInfo = NULL; // Optional VK_CHECK(vkBeginCommandBuffer(commandBuffer, &beginInfo)); + vkCmdSetDepthTestEnable(commandBuffer, 1); + vkCmdSetDepthWriteEnable(commandBuffer, 1); - VkImageMemoryBarrier image_memory_barrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .image = s.vk_swap_chain_images[imageIndex], - .subresourceRange = (VkImageSubresourceRange){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - } - }; - - vkCmdPipelineBarrier( - commandBuffer, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // dstStageMask - 0, - 0, - NULL, - 0, - NULL, - 1, // imageMemoryBarrierCount - &image_memory_barrier // pImageMemoryBarriers - ); + transitionImageLayout( + s.vk_swap_chain_images[imageIndex], VK_FORMAT_R8G8B8A8_SRGB, 0, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; - - // TODO DYNAMIC RENDERING - VkRenderingAttachmentInfo colorAttachment = {}; + VkRenderingAttachmentInfo colorAttachment = {0}; colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; colorAttachment.imageView = s.vk_swap_chain_image_views[imageIndex]; colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - //colorAttachment.clearValue.color = clearColor; + colorAttachment.clearValue.color = + (VkClearColorValue){0.0f, 0.0f, 0.0f, 1.0f}; + + VkRenderingAttachmentInfo depthAttachment = {0}; + depthAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + depthAttachment.imageView = s.vk_depth_image_view; + depthAttachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.clearValue.depthStencil = (VkClearDepthStencilValue){1.0f, 0u}; VkRenderingInfo renderingInfo = {}; renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; - renderingInfo.renderArea = (VkRect2D){ {0, 0}, {(float)(s.vk_swap_chain_extent.width), (float)(s.vk_swap_chain_extent.height)} }; + renderingInfo.renderArea = + (VkRect2D){{0, 0}, s.vk_swap_chain_extent}; renderingInfo.layerCount = 1; renderingInfo.colorAttachmentCount = 1; renderingInfo.pColorAttachments = &colorAttachment; + renderingInfo.pDepthAttachment = &depthAttachment; vkCmdBeginRendering(commandBuffer, &renderingInfo); - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, s.vk_graphics_pipeline); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + s.vk_graphics_pipeline); VkViewport viewport = {0}; viewport.x = 0.0f; @@ -1036,44 +1250,23 @@ recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) VkBuffer vertexBuffers[] = {s.vk_vertex_buffer}; VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); - vkCmdBindIndexBuffer(commandBuffer, s.vk_index_buffer, 0, VK_INDEX_TYPE_UINT16); - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, s.vk_pipeline_layout, 0, 1, &s.frames[currentFrame].vk_descriptor_set, 0, NULL); + vkCmdBindIndexBuffer(commandBuffer, s.vk_index_buffer, 0, + VK_INDEX_TYPE_UINT16); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + s.vk_pipeline_layout, 0, 1, + &s.frames[currentFrame].vk_descriptor_set, 0, NULL); + vkCmdDrawIndexed(commandBuffer, INDICES_SIZE, 1, 0, 0, 0); vkCmdEndRendering(commandBuffer); - /* vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); */ - - - /* vkCmdEndRenderPass(commandBuffer); */ - - VkImageMemoryBarrier image_memory_barrier2 = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - .image = s.vk_swap_chain_images[imageIndex], - .subresourceRange = (VkImageSubresourceRange){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - } - }; - - vkCmdPipelineBarrier( - commandBuffer, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // dstStageMask - 0, - 0, - NULL, - 0, - NULL, - 1, // imageMemoryBarrierCount - &image_memory_barrier2 // pImageMemoryBarriers - ); + transitionImageLayout(s.vk_swap_chain_images[imageIndex], + VK_FORMAT_R8G8B8A8_SRGB, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); VK_CHECK(vkEndCommandBuffer(commandBuffer)); } @@ -1095,22 +1288,6 @@ vulkan_create_sync_objects() } } -uint32_t -findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) -{ - VkPhysicalDeviceMemoryProperties memProperties; - vkGetPhysicalDeviceMemoryProperties(s.vk_physical_device, &memProperties); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { - if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } - } - - vk_log(VK_ERROR, "failed to find suitable memory type!\n"); - return 9999; -} - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, @@ -1139,38 +1316,14 @@ createBuffer(VkDeviceSize size, VK_CHECK(vkBindBufferMemory(s.vk_device, *buffer, *bufferMemory, 0)); } -void -copy_buffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { - VkCommandBufferAllocateInfo allocInfo = {0}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = s.vk_command_pool; - allocInfo.commandBufferCount = 1; - - VkCommandBuffer commandBuffer; - VK_CHECK(vkAllocateCommandBuffers(s.vk_device, &allocInfo, &commandBuffer)); - - VkCommandBufferBeginInfo beginInfo = {0}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - VK_CHECK(vkBeginCommandBuffer(commandBuffer, &beginInfo)); +void copy_buffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); VkBufferCopy copyRegion = {0}; copyRegion.srcOffset = 0; // Optional copyRegion.dstOffset = 0; // Optional copyRegion.size = size; vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region); - VK_CHECK(vkEndCommandBuffer(commandBuffer)); - - VkSubmitInfo submitInfo = {0}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; - - VK_CHECK(vkQueueSubmit(s.vk_graphics_queue, 1, &submitInfo, VK_NULL_HANDLE)); - VK_CHECK(vkQueueWaitIdle(s.vk_graphics_queue)); - - vkFreeCommandBuffers(s.vk_device, s.vk_command_pool, 1, &commandBuffer); + endSingleTimeCommands(commandBuffer); } void @@ -1242,10 +1395,19 @@ vulkan_create_descriptor_set_layout() //uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; uboLayoutBinding.pImmutableSamplers = NULL; // optional + VkDescriptorSetLayoutBinding samplerLayoutBinding = {0}; + samplerLayoutBinding.binding = 1; + samplerLayoutBinding.descriptorCount = 1; + samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + samplerLayoutBinding.pImmutableSamplers = NULL; + samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkDescriptorSetLayoutBinding bindings[2] = {uboLayoutBinding, samplerLayoutBinding}; + VkDescriptorSetLayoutCreateInfo layoutInfo = {0}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = 1; - layoutInfo.pBindings = &uboLayoutBinding; + layoutInfo.bindingCount = VK_ARRAY_LEN(bindings); + layoutInfo.pBindings = bindings; VK_CHECK(vkCreateDescriptorSetLayout(s.vk_device, &layoutInfo, NULL, &s.vk_descriptor_set_layout)); } @@ -1268,20 +1430,21 @@ vulkan_create_uniform_buffers() void vulkan_create_descriptor_pool() { - VkDescriptorPoolSize poolSize = {0}; - poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - poolSize.descriptorCount = MAX_FRAMES_IN_FLIGHT; + VkDescriptorPoolSize poolSizes[2] = {0}; + poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT; + poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT; VkDescriptorPoolCreateInfo poolInfo = {0}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = 1; - poolInfo.pPoolSizes = &poolSize; + poolInfo.poolSizeCount = VK_ARRAY_LEN(poolSizes); + poolInfo.pPoolSizes = poolSizes; poolInfo.maxSets = MAX_FRAMES_IN_FLIGHT; VK_CHECK(vkCreateDescriptorPool(s.vk_device, &poolInfo, NULL, &s.vk_descriptor_pool)); } -VkDescriptorSet * temp_set; void vulkan_create_descriptor_sets() { @@ -1308,24 +1471,39 @@ vulkan_create_descriptor_sets() bufferInfo.offset = 0; bufferInfo.range = sizeof(UniformBufferObject); - VkWriteDescriptorSet descriptorWrite = {0}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = s.frames[i].vk_descriptor_set; - descriptorWrite.dstBinding = 0; - descriptorWrite.dstArrayElement = 0; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pBufferInfo = &bufferInfo; - descriptorWrite.pImageInfo = NULL; // Optional - descriptorWrite.pTexelBufferView = NULL; // Optional - - vkUpdateDescriptorSets(s.vk_device, 1, &descriptorWrite, 0, NULL); + VkDescriptorImageInfo imageInfo = {0}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = s.vk_texture_image_view; + imageInfo.sampler = s.vk_texture_sampler; + + VkWriteDescriptorSet descriptorWrites[2] = {0}; + descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[0].dstSet = s.frames[i].vk_descriptor_set; + descriptorWrites[0].dstBinding = 0; + descriptorWrites[0].dstArrayElement = 0; + descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrites[0].descriptorCount = 1; + descriptorWrites[0].pBufferInfo = &bufferInfo; + + descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[1].dstSet = s.frames[i].vk_descriptor_set; + descriptorWrites[1].dstBinding = 1; + descriptorWrites[1].dstArrayElement = 0; + descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrites[1].descriptorCount = 1; + descriptorWrites[1].pImageInfo = &imageInfo; + + vkUpdateDescriptorSets(s.vk_device, VK_ARRAY_LEN(descriptorWrites), descriptorWrites, 0, NULL); } } void cleanupSwapChain() { + vkDestroyImageView(s.vk_device, s.vk_depth_image_view, NULL); + vkDestroyImage(s.vk_device, s.vk_depth_image, NULL); + vkFreeMemory(s.vk_device, s.vk_depth_image_memory, NULL); + for (uint32_t i = 0; i < s.vk_swap_chain_image_count; i++) { vkDestroyImageView(s.vk_device, s.vk_swap_chain_image_views[i], NULL); } @@ -1341,6 +1519,7 @@ recreateSwapChain() vulkan_create_swap_chain(); vulkan_create_image_views(); + vulkan_create_depth_resources(); } void @@ -1416,6 +1595,114 @@ handle_input(bool * quit) } } +void +copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, + uint32_t height) +{ + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + 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 = (VkOffset3D){0, 0, 0}; + region.imageExtent = (VkExtent3D){width, height, 1}; + + vkCmdCopyBufferToImage(commandBuffer, + buffer, + image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ®ion + ); + + endSingleTimeCommands(commandBuffer); +} + +void +vulkan_create_texture_image() +{ + int texWidth, texHeight, texChannels; + stbi_uc* pixels = stbi_load("assets/texture.jpg", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + VkDeviceSize imageSize = texWidth * texHeight * 4; + + if (!pixels) { + vk_log(VK_ERROR, "failed to load texture image!\n"); + } + + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + + createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffer, &stagingBufferMemory); + void* data; + vkMapMemory(s.vk_device, stagingBufferMemory, 0, imageSize, 0, &data); + memcpy(data, pixels, (size_t)imageSize); + vkUnmapMemory(s.vk_device, stagingBufferMemory); + + stbi_image_free(pixels); + + createImage(texWidth, texHeight, 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, &s.vk_texture_image, + &s.vk_texture_image_memory); + + transitionImageLayout( + s.vk_texture_image, VK_FORMAT_R8G8B8A8_SRGB, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + copyBufferToImage(stagingBuffer, s.vk_texture_image, (uint32_t)texWidth, + (uint32_t)texHeight); + transitionImageLayout( + s.vk_texture_image, VK_FORMAT_R8G8B8A8_SRGB, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vkDestroyBuffer(s.vk_device, stagingBuffer, NULL); + vkFreeMemory(s.vk_device, stagingBufferMemory, NULL); +} + +void +vulkan_create_texture_image_view() +{ + s.vk_texture_image_view = create_image_view(s.vk_texture_image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT); +} + +void vulkan_create_texture_sampler() { + VkSamplerCreateInfo samplerInfo = {0}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.anisotropyEnable = VK_TRUE; + + VkPhysicalDeviceProperties properties = {0}; + vkGetPhysicalDeviceProperties(s.vk_physical_device, &properties); + + samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy; + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.0f; + + VK_CHECK(vkCreateSampler(s.vk_device, &samplerInfo, NULL, &s.vk_texture_sampler)); +} + void init_vulkan() { @@ -1433,6 +1720,10 @@ init_vulkan() vulkan_create_descriptor_set_layout(); vulkan_create_graphics_pipeline(); vulkan_create_command_pool(); + vulkan_create_depth_resources(); + vulkan_create_texture_image(); + vulkan_create_texture_image_view(); + vulkan_create_texture_sampler(); vulkan_create_vertex_buffer(); vulkan_create_index_buffer(); vulkan_create_uniform_buffers(); @@ -1457,6 +1748,12 @@ close_vulkan() cleanupSwapChain(); + vkDestroySampler(s.vk_device, s.vk_texture_sampler, NULL); + vkDestroyImageView(s.vk_device, s.vk_texture_image_view, NULL); + + vkDestroyImage(s.vk_device, s.vk_texture_image, NULL); + vkFreeMemory(s.vk_device, s.vk_texture_image_memory, NULL); + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { vkDestroyBuffer(s.vk_device, s.frames[i].vk_uniform_buffer, NULL); vkFreeMemory(s.vk_device, s.frames[i].vk_uniform_buffer_memory, NULL); @@ -1504,6 +1801,7 @@ current_time() return (currentTime.tv_sec - startTime.tv_sec) + (currentTime.tv_nsec - startTime.tv_nsec) / 1e9f; } + void updateUniformBuffer(uint32_t currentImage) { @@ -1529,7 +1827,7 @@ updateUniformBuffer(uint32_t currentImage) /* glm_lookat(eye, center, GLM_ZUP, ubo.view); */ float aspect = s.vk_swap_chain_extent.width / (float)s.vk_swap_chain_extent.height; - glm_perspective(glm_rad(55.0f - s.zoom ), aspect, 0.1f, 100.0f, ubo.proj); + glm_perspective(glm_rad(45.0f ), aspect, 1.0f, 10.0f, ubo.proj); // Inverting the Y axis for Vulkan ubo.proj[1][1] *= -1; @@ -1648,4 +1946,5 @@ main(int argc, char* args[]) closeSDL(); return 0; + } -- cgit v1.2.3