diff --git a/include/render/vulkan.h b/include/render/vulkan.h index de1195b8f..c00b1122b 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -212,6 +212,7 @@ struct wlr_vk_render_format_setup { bool use_blending_buffer; bool use_srgb; VkRenderPass render_pass; + VkRenderPass render_pass_clear; VkPipeline output_pipe_identity; VkPipeline output_pipe_srgb; diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index b250543ce..38be3320b 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -429,33 +429,32 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { } if (pass->two_pass) { - // The render pass changes the blend image layout from - // color attachment to read only, so on each frame, before - // the render pass starts, we change it back - VkImageLayout blend_src_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - if (!render_buffer->two_pass.blend_transitioned) { - blend_src_layout = VK_IMAGE_LAYOUT_UNDEFINED; + // On the first frame the clear render pass transitions the blend + // image from undefined and we just mark it transitioned. On every + // frame after, the previous frame left it read-only, so we change + // it back to a color attachment before the render pass starts + if (render_buffer->two_pass.blend_transitioned) { + VkImageMemoryBarrier blend_acq_barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = render_buffer->two_pass.blend_image, + .oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .srcAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .layerCount = 1, + .levelCount = 1, + }, + }; + vkCmdPipelineBarrier(stage_cb->vk, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + 0, 0, NULL, 0, NULL, 1, &blend_acq_barrier); + } else { render_buffer->two_pass.blend_transitioned = true; } - - VkImageMemoryBarrier blend_acq_barrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = render_buffer->two_pass.blend_image, - .oldLayout = blend_src_layout, - .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .srcAccessMask = VK_ACCESS_SHADER_READ_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .layerCount = 1, - .levelCount = 1, - }, - }; - vkCmdPipelineBarrier(stage_cb->vk, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - 0, 0, NULL, 0, NULL, 1, &blend_acq_barrier); } // acquire render buffer before rendering @@ -1334,11 +1333,15 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend int height = buffer->wlr_buffer->height; VkRect2D rect = { .extent = { width, height } }; + bool blend_first_use = pass->two_pass && !buffer->two_pass.blend_transitioned; + VkClearValue clear_value = {0}; VkRenderPassBeginInfo rp_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderArea = rect, - .clearValueCount = 0, - .renderPass = render_setup->render_pass, + .clearValueCount = blend_first_use ? 1 : 0, + .pClearValues = blend_first_use ? &clear_value : NULL, + .renderPass = blend_first_use ? + render_setup->render_pass_clear : render_setup->render_pass, .framebuffer = buffer_out->framebuffer, }; vkCmdBeginRenderPass(cb->vk, &rp_info, VK_SUBPASS_CONTENTS_INLINE); diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index d342dee2c..44f4d39d8 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -169,6 +169,7 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer, VkDevice dev = renderer->dev->dev; vkDestroyRenderPass(dev, setup->render_pass, NULL); + vkDestroyRenderPass(dev, setup->render_pass_clear, NULL); vkDestroyPipeline(dev, setup->output_pipe_identity, NULL); vkDestroyPipeline(dev, setup->output_pipe_srgb, NULL); vkDestroyPipeline(dev, setup->output_pipe_pq, NULL); @@ -2585,6 +2586,14 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( goto error; } + attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + res = vkCreateRenderPass(dev, &rp_info, NULL, &setup->render_pass_clear); + if (res != VK_SUCCESS) { + wlr_vk_error("Failed to create 2-step clear render pass", res); + goto error; + } + // this is only well defined if render pass has a 2nd subpass if (!init_blend_to_output_pipeline( renderer, setup->render_pass, renderer->output_pipe_layout,