diff --git a/gpu.c b/gpu.c index 7bd3a5c..5233956 100644 --- a/gpu.c +++ b/gpu.c @@ -160,8 +160,9 @@ static void load_buffer( static void create_img( const gpu_ctx_t *ctx, VkFormat fmt, uint32_t width, uint32_t height, - VkImageUsageFlags usage, VkImageAspectFlags aspect, VkImage *img, - VkDeviceMemory *mem, VkImageView *view) + VkImageUsageFlags usage, VkSampleCountFlags samples, + VkImageAspectFlags aspect, VkImage *img, VkDeviceMemory *mem, + VkImageView *view) { VkResult result; @@ -176,7 +177,7 @@ static void create_img( .tiling = VK_IMAGE_TILING_OPTIMAL, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .usage = usage, - .samples = VK_SAMPLE_COUNT_1_BIT, + .samples = samples, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, }; result = vkCreateImage(ctx->dev, &img_config, nullptr, img); @@ -241,6 +242,14 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) ctx->inst, &dev_count, &ctx->physical_dev); assert(result == VK_SUCCESS || result == VK_INCOMPLETE); + // Check that the physics device supports 8 samples + VkPhysicalDeviceProperties physical_dev_props; + vkGetPhysicalDeviceProperties(ctx->physical_dev, &physical_dev_props); + const VkSampleCountFlags sample_counts + = physical_dev_props.limits.framebufferColorSampleCounts + & physical_dev_props.limits.framebufferDepthSampleCounts; + assert((sample_counts & VK_SAMPLE_COUNT_8_BIT) != 0); + // Select queue family uint32_t queue_family_count = QUEUE_FAMILY_PROP_BUFFER_SIZE; VkQueueFamilyProperties @@ -409,14 +418,23 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) ctx, VK_FORMAT_D32_SFLOAT, SHADOW_IMG_SIZE, SHADOW_IMG_SIZE, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - VK_IMAGE_ASPECT_DEPTH_BIT, &ctx->shadow_img, &ctx->shadow_mem, - &ctx->shadow_view); + VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_ASPECT_DEPTH_BIT, &ctx->shadow_img, + &ctx->shadow_mem, &ctx->shadow_view); + + // Create colour image (for multisampling) + create_img( + ctx, surface_fmt.format, ctx->swapchain_extent.width, + ctx->swapchain_extent.height, + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT + | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_ASPECT_COLOR_BIT, &ctx->colour_img, + &ctx->colour_mem, &ctx->colour_view); // Set up depth image create_img( ctx, VK_FORMAT_D32_SFLOAT, ctx->swapchain_extent.width, ctx->swapchain_extent.height, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_ASPECT_DEPTH_BIT, &ctx->depth_img, &ctx->depth_mem, &ctx->depth_view); @@ -437,16 +455,6 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) }; // Attachment configs - const VkAttachmentDescription colour_attachment = { - .format = surface_fmt.format, - .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - }; const VkAttachmentDescription shadow_depth_attachment = { .format = VK_FORMAT_D32_SFLOAT, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -457,9 +465,19 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }; + const VkAttachmentDescription colour_attachment = { + .format = surface_fmt.format, + .samples = VK_SAMPLE_COUNT_8_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; const VkAttachmentDescription render_depth_attachment = { .format = VK_FORMAT_D32_SFLOAT, - .samples = VK_SAMPLE_COUNT_1_BIT, + .samples = VK_SAMPLE_COUNT_8_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, @@ -467,6 +485,16 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }; + const VkAttachmentDescription colour_resolve_attachment = { + .format = surface_fmt.format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + }; // Create shadow pass const VkRenderPassCreateInfo shadow_pass_config = { @@ -495,24 +523,14 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) assert(result == VK_SUCCESS); // Create render pass - const VkAttachmentDescription attachment_descs[] = { - colour_attachment, - render_depth_attachment, - }; - const VkSubpassDependency dependency = { - .srcSubpass = VK_SUBPASS_EXTERNAL, - .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 = NELEMS(attachment_descs), - .pAttachments = attachment_descs, + .attachmentCount = 3, + .pAttachments = (VkAttachmentDescription[]) { + colour_attachment, + render_depth_attachment, + colour_resolve_attachment, + }, .subpassCount = 1, .pSubpasses = &(VkSubpassDescription){ .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, @@ -525,9 +543,23 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) .attachment = 1, .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }, + .pResolveAttachments = &(VkAttachmentReference) { + .attachment = 2, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }, }, .dependencyCount = 1, - .pDependencies = &dependency, + .pDependencies = &(VkSubpassDependency) { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT + | 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, + }, }; result = vkCreateRenderPass( ctx->dev, &render_pass_config, nullptr, &ctx->render_pass); @@ -555,13 +587,6 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) ctx->dev, &desc_pool_config, nullptr, &ctx->desc_pool); assert(result == VK_SUCCESS); - // Populate multisampling configuration - const VkPipelineMultisampleStateCreateInfo multisampling_config = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .sampleShadingEnable = VK_FALSE, - .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, - }; - // Set up colour blending configuration const VkPipelineColorBlendAttachmentState colour_blend_attatchment = { .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT @@ -672,7 +697,12 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) }, .pViewportState = &viewport_config, .pRasterizationState = &floor_rasterizer_config, - .pMultisampleState = &multisampling_config, + .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) { + .sType + = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_8_BIT, + }, .pColorBlendState = &colour_blend_config, .layout = ctx->floor_pipeline_layout, .renderPass = ctx->render_pass, @@ -816,7 +846,12 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) .pInputAssemblyState = &input_assembly_config, .pViewportState = &shadow_viewport_config, .pRasterizationState = &shadow_rasterizer_config, - .pMultisampleState = &multisampling_config, + .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) { + .sType + = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + }, .layout = ctx->model_pipeline_layout, .renderPass = ctx->shadow_pass, .subpass = 0, @@ -859,7 +894,12 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) .pInputAssemblyState = &input_assembly_config, .pViewportState = &viewport_config, .pRasterizationState = &model_rasterizer_config, - .pMultisampleState = &multisampling_config, + .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) { + .sType + = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_8_BIT, + }, .pColorBlendState = &colour_blend_config, .layout = ctx->model_pipeline_layout, .renderPass = ctx->render_pass, @@ -902,15 +942,15 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) ctx->dev, &shadow_framebuf_config, nullptr, &ctx->shadow_framebuf); assert(result == VK_SUCCESS); for (unsigned i = 0; i < ctx->swapchain_img_count; ++i) { - VkImageView attachments[] = { - ctx->swapchain_img_views[i], - ctx->depth_view, - }; const VkFramebufferCreateInfo framebuffer_config = { .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, .renderPass = ctx->render_pass, - .attachmentCount = 2, - .pAttachments = attachments, + .attachmentCount = 3, + .pAttachments = (VkImageView[]) { + ctx->colour_view, + ctx->depth_view, + ctx->swapchain_img_views[i], + }, .width = ctx->swapchain_extent.width, .height = ctx->swapchain_extent.height, .layers = 1, @@ -1048,6 +1088,10 @@ void gpu_cleanup(const gpu_ctx_t *ctx) vkDestroyRenderPass(ctx->dev, ctx->shadow_pass, nullptr); vkDestroyRenderPass(ctx->dev, ctx->render_pass, nullptr); + vkDestroyImageView(ctx->dev, ctx->colour_view, nullptr); + vkDestroyImage(ctx->dev, ctx->colour_img, nullptr); + vkFreeMemory(ctx->dev, ctx->colour_mem, nullptr); + vkDestroyImageView(ctx->dev, ctx->shadow_view, nullptr); vkDestroyImage(ctx->dev, ctx->shadow_img, nullptr); vkFreeMemory(ctx->dev, ctx->shadow_mem, nullptr); diff --git a/gpu.h b/gpu.h index fea7ed4..ab1d797 100644 --- a/gpu.h +++ b/gpu.h @@ -39,6 +39,9 @@ typedef struct { VkDescriptorSetLayout floor_desc_set_layout; VkDescriptorSetLayout desc_set_layout; VkDescriptorPool desc_pool; + VkImage colour_img; + VkDeviceMemory colour_mem; + VkImageView colour_view; VkRenderPass shadow_pass; VkRenderPass render_pass; VkDescriptorSet floor_desc_sets[MAX_FRAMES_IN_FLIGHT];