diff --git a/gpu.c b/gpu.c index e05fa67..54eb81d 100644 --- a/gpu.c +++ b/gpu.c @@ -47,30 +47,16 @@ load_shader_module(VkDevice dev, const char *code, size_t code_size) return mod; } -static void create_buffer( - const gpu_ctx_t *ctx, VkDeviceSize size, VkBufferUsageFlags usage, - VkMemoryPropertyFlags props, VkBuffer *buf_out, VkDeviceMemory *mem_out) +static void alloc_dev_mem( + const gpu_ctx_t *ctx, VkMemoryRequirements reqs, + VkMemoryPropertyFlags props, VkDeviceMemory *mem_out) { - VkResult result; - - // Create buffer - const VkBufferCreateInfo buf_config = { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .size = size, - .usage = usage, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - }; - result = vkCreateBuffer(ctx->dev, &buf_config, nullptr, buf_out); - assert(result == VK_SUCCESS); - // Find appropriate memory type - VkMemoryRequirements requirements; - vkGetBufferMemoryRequirements(ctx->dev, *buf_out, &requirements); VkPhysicalDeviceMemoryProperties mem_props; vkGetPhysicalDeviceMemoryProperties(ctx->physical_dev, &mem_props); uint32_t mem_type = UINT32_MAX; for (unsigned i = 0; i < mem_props.memoryTypeCount; ++i) { - if ((requirements.memoryTypeBits & (1 << i)) == 0) + if ((reqs.memoryTypeBits & (1 << i)) == 0) continue; if ((mem_props.memoryTypes[i].propertyFlags & props) == props) { mem_type = i; @@ -80,14 +66,35 @@ static void create_buffer( assert(mem_type != UINT32_MAX); // Allocate memory - VkMemoryAllocateInfo allocate_config = { + VkMemoryAllocateInfo alloc_config = { .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .allocationSize = requirements.size, + .allocationSize = reqs.size, .memoryTypeIndex = mem_type, }; - result = vkAllocateMemory(ctx->dev, &allocate_config, nullptr, mem_out); + const VkResult result + = vkAllocateMemory(ctx->dev, &alloc_config, nullptr, mem_out); + assert(result == VK_SUCCESS); +} + +static void create_buffer( + const gpu_ctx_t *ctx, VkDeviceSize size, VkBufferUsageFlags usage, + VkMemoryPropertyFlags props, VkBuffer *buf_out, VkDeviceMemory *mem_out) +{ + // Create buffer + const VkBufferCreateInfo buf_config = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = size, + .usage = usage, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + const VkResult result + = vkCreateBuffer(ctx->dev, &buf_config, nullptr, buf_out); assert(result == VK_SUCCESS); + // Allocate and bind memory + VkMemoryRequirements mem_reqs; + vkGetBufferMemoryRequirements(ctx->dev, *buf_out, &mem_reqs); + alloc_dev_mem(ctx, mem_reqs, props, mem_out); vkBindBufferMemory(ctx->dev, *buf_out, *mem_out, 0); } @@ -337,6 +344,51 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) assert(result == VK_SUCCESS); } + // Set up depth image + const VkFormat depth_img_fmt = VK_FORMAT_D32_SFLOAT; + const VkImageCreateInfo depth_img_config = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .extent = { + .width = ctx->swapchain_extent.width, + .height = ctx->swapchain_extent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .format = depth_img_fmt, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + .samples = VK_SAMPLE_COUNT_1_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + result = vkCreateImage( + ctx->dev, &depth_img_config, nullptr, &ctx->depth_img); + assert(result == VK_SUCCESS); + VkMemoryRequirements mem_reqs; + vkGetImageMemoryRequirements(ctx->dev, ctx->depth_img, &mem_reqs); + alloc_dev_mem( + ctx, mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + &ctx->depth_img_mem); + vkBindImageMemory(ctx->dev, ctx->depth_img, ctx->depth_img_mem, 0); + + // Create depth image view + const VkImageViewCreateInfo depth_img_view_config = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = ctx->depth_img, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = depth_img_fmt, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, + .levelCount = 1, + .layerCount = 1, + }, + }; + result = vkCreateImageView( + ctx->dev, &depth_img_view_config, nullptr, &ctx->depth_img_view); + assert(result == VK_SUCCESS); + // Load vertex and fragment shader modules ctx->vert_shader = load_shader_module(ctx->dev, vert_shader, sizeof(vert_shader)); @@ -369,7 +421,7 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) { .binding = 0, .location = 0, - .format = VK_FORMAT_R32G32_SFLOAT, + .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(vertex_t, position), }, { @@ -395,6 +447,8 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) const VkViewport viewport = { .width = (float)ctx->swapchain_extent.width, .height = (float)ctx->swapchain_extent.height, + .minDepth = 0.0, + .maxDepth = 1.0, }; const VkRect2D scissor = { .extent = ctx->swapchain_extent }; VkPipelineViewportStateCreateInfo viewport_config = { @@ -465,27 +519,49 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }; - const VkSubpassDescription subpass = { - .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .colorAttachmentCount = 1, - .pColorAttachments = &colour_attachment_ref, + + // Set up depth attatchment + const VkAttachmentDescription depth_attatchment = { + .format = depth_img_fmt, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + }; + VkAttachmentReference depth_attachment_ref = { + .attachment = 1, + .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }; // Create render pass + const VkAttachmentDescription attachment_descs[] = { + colour_attachment, + depth_attatchment, + }; const VkSubpassDependency dependency = { .srcSubpass = VK_SUBPASS_EXTERNAL, - .dstSubpass = 0, - .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .srcAccessMask = 0, - .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, }; const VkRenderPassCreateInfo render_pass_config = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = &colour_attachment, + .attachmentCount = 2, + .pAttachments = attachment_descs, .subpassCount = 1, - .pSubpasses = &subpass, + .pSubpasses = &(VkSubpassDescription){ + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &colour_attachment_ref, + .pDepthStencilAttachment = &depth_attachment_ref, + }, .dependencyCount = 1, .pDependencies = &dependency, }; @@ -494,6 +570,14 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) assert(result == VK_SUCCESS); // Create pipeline + const VkPipelineDepthStencilStateCreateInfo depth_stencil_config = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_TRUE, + .depthWriteEnable = VK_TRUE, + .depthCompareOp = VK_COMPARE_OP_LESS, + .depthBoundsTestEnable = VK_FALSE, + .stencilTestEnable = VK_FALSE, + }; const VkGraphicsPipelineCreateInfo pipeline_config = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .stageCount = 2, @@ -507,6 +591,7 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) .layout = ctx->pipeline_layout, .renderPass = ctx->render_pass, .subpass = 0, + .pDepthStencilState = &depth_stencil_config, }; result = vkCreateGraphicsPipelines( ctx->dev, VK_NULL_HANDLE, 1, &pipeline_config, nullptr, @@ -515,11 +600,15 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) // Create framebuffers for (unsigned i = 0; i < swapchain_img_count; ++i) { + VkImageView attachments[] = { + ctx->swapchain_img_views[i], + ctx->depth_img_view, + }; const VkFramebufferCreateInfo framebuffer_config = { .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, .renderPass = ctx->render_pass, - .attachmentCount = 1, - .pAttachments = ctx->swapchain_img_views + i, + .attachmentCount = 2, + .pAttachments = attachments, .width = ctx->swapchain_extent.width, .height = ctx->swapchain_extent.height, .layers = 1, @@ -636,6 +725,10 @@ void gpu_cleanup(const gpu_ctx_t *ctx) vkDestroyShaderModule(ctx->dev, ctx->vert_shader, nullptr); vkDestroyShaderModule(ctx->dev, ctx->frag_shader, nullptr); + vkDestroyImageView(ctx->dev, ctx->depth_img_view, nullptr); + vkDestroyImage(ctx->dev, ctx->depth_img, nullptr); + vkFreeMemory(ctx->dev, ctx->depth_img_mem, nullptr); + for (unsigned i = 0; i < ctx->swapchain_img_count; ++i) { vkDestroyFramebuffer(ctx->dev, ctx->framebuffers[i], nullptr); vkDestroyImageView(ctx->dev, ctx->swapchain_img_views[i], nullptr); @@ -671,14 +764,17 @@ void gpu_render(const gpu_ctx_t *ctx, const mvp_t *mvp) assert(result == VK_SUCCESS); // Start render pass - VkClearValue clear_value = { { { 0.0, 0.0, 0.0, 1.0 } } }; + VkClearValue clear_values[] = { + [0] = { .color = { { 0.0, 0.0, 0.0, 1.0 } } }, + [1] = { .depthStencil = { 1.0, 0.0 } }, + }; VkRenderPassBeginInfo render_pass_begin = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderPass = ctx->render_pass, .framebuffer = ctx->framebuffers[img_index], .renderArea.extent = ctx->swapchain_extent, - .clearValueCount = 1, - .pClearValues = &clear_value, + .clearValueCount = 2, + .pClearValues = clear_values, }; vkCmdBeginRenderPass( ctx->cmd_buf, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); diff --git a/gpu.h b/gpu.h index 8bb2fc4..8fb4572 100644 --- a/gpu.h +++ b/gpu.h @@ -31,6 +31,9 @@ typedef struct { VkExtent2D swapchain_extent; uint32_t swapchain_img_count; VkImageView swapchain_img_views[SWAPCHAIN_IMG_BUFFER_SIZE]; + VkImage depth_img; + VkDeviceMemory depth_img_mem; + VkImageView depth_img_view; VkFramebuffer framebuffers[SWAPCHAIN_IMG_BUFFER_SIZE]; VkShaderModule vert_shader; VkShaderModule frag_shader;