From 8baf98e4397ad3ed244d8cf9ee8a056b17042ae2 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 23 Feb 2020 03:51:37 -0300
Subject: [PATCH] vk_rasterizer: Reimplement clears with vkCmdClearAttachments

---
 .../renderer_vulkan/vk_pipeline_cache.cpp     |  5 +-
 .../renderer_vulkan/vk_pipeline_cache.h       |  6 +-
 .../renderer_vulkan/vk_rasterizer.cpp         | 88 ++++++++++---------
 .../renderer_vulkan/vk_rasterizer.h           |  1 +
 4 files changed, 54 insertions(+), 46 deletions(-)

diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 056ef495c6..91e7b77913 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -179,10 +179,11 @@ Tegra::Engines::ConstBufferEngineInterface& CachedShader::GetEngine(
 VKPipelineCache::VKPipelineCache(Core::System& system, RasterizerVulkan& rasterizer,
                                  const VKDevice& device, VKScheduler& scheduler,
                                  VKDescriptorPool& descriptor_pool,
-                                 VKUpdateDescriptorQueue& update_descriptor_queue)
+                                 VKUpdateDescriptorQueue& update_descriptor_queue,
+                                 VKRenderPassCache& renderpass_cache)
     : RasterizerCache{rasterizer}, system{system}, device{device}, scheduler{scheduler},
       descriptor_pool{descriptor_pool}, update_descriptor_queue{update_descriptor_queue},
-      renderpass_cache(device) {}
+      renderpass_cache{renderpass_cache} {}
 
 VKPipelineCache::~VKPipelineCache() = default;
 
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 21340c9a4b..c4c112290e 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -161,7 +161,8 @@ public:
     explicit VKPipelineCache(Core::System& system, RasterizerVulkan& rasterizer,
                              const VKDevice& device, VKScheduler& scheduler,
                              VKDescriptorPool& descriptor_pool,
-                             VKUpdateDescriptorQueue& update_descriptor_queue);
+                             VKUpdateDescriptorQueue& update_descriptor_queue,
+                             VKRenderPassCache& renderpass_cache);
     ~VKPipelineCache();
 
     std::array<Shader, Maxwell::MaxShaderProgram> GetShaders();
@@ -184,8 +185,7 @@ private:
     VKScheduler& scheduler;
     VKDescriptorPool& descriptor_pool;
     VKUpdateDescriptorQueue& update_descriptor_queue;
-
-    VKRenderPassCache renderpass_cache;
+    VKRenderPassCache& renderpass_cache;
 
     std::array<Shader, Maxwell::MaxShaderProgram> last_shaders;
 
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index f889019c1d..8c043fc090 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -287,12 +287,13 @@ RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWind
       screen_info{screen_info}, device{device}, resource_manager{resource_manager},
       memory_manager{memory_manager}, state_tracker{state_tracker}, scheduler{scheduler},
       staging_pool(device, memory_manager, scheduler), descriptor_pool(device),
-      update_descriptor_queue(device, scheduler),
+      update_descriptor_queue(device, scheduler), renderpass_cache(device),
       quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
       uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
       texture_cache(system, *this, device, resource_manager, memory_manager, scheduler,
                     staging_pool),
-      pipeline_cache(system, *this, device, scheduler, descriptor_pool, update_descriptor_queue),
+      pipeline_cache(system, *this, device, scheduler, descriptor_pool, update_descriptor_queue,
+                     renderpass_cache),
       buffer_cache(*this, system, device, memory_manager, scheduler, staging_pool),
       sampler_cache(device), query_cache(system, *this, device, scheduler) {
     scheduler.SetQueryCache(query_cache);
@@ -365,13 +366,16 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
 void RasterizerVulkan::Clear() {
     MICROPROFILE_SCOPE(Vulkan_Clearing);
 
-    query_cache.UpdateCounters();
-
     const auto& gpu = system.GPU().Maxwell3D();
     if (!system.GPU().Maxwell3D().ShouldExecute()) {
         return;
     }
 
+    sampled_views.clear();
+    image_views.clear();
+
+    query_cache.UpdateCounters();
+
     const auto& regs = gpu.regs;
     const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
                            regs.clear_buffers.A;
@@ -380,52 +384,54 @@ void RasterizerVulkan::Clear() {
     if (!use_color && !use_depth && !use_stencil) {
         return;
     }
-    // Clearing images requires to be out of a renderpass
-    scheduler.RequestOutsideRenderPassOperationContext();
 
-    // TODO(Rodrigo): Implement clears rendering a quad or using beginning a renderpass.
+    [[maybe_unused]] const auto texceptions = UpdateAttachments();
+    DEBUG_ASSERT(texceptions.none());
+    SetupImageTransitions(0, color_attachments, zeta_attachment);
+
+    const vk::RenderPass renderpass = renderpass_cache.GetRenderPass(GetRenderPassParams(0));
+    const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass);
+    scheduler.RequestRenderpass({renderpass, framebuffer, {{0, 0}, render_area}, 0, nullptr});
+
+    const auto& scissor = regs.scissor_test[0];
+    const vk::Offset2D scissor_offset(scissor.min_x, scissor.min_y);
+    vk::Extent2D scissor_extent{scissor.max_x - scissor.min_x, scissor.max_y - scissor.min_y};
+    scissor_extent.width = std::min(scissor_extent.width, render_area.width);
+    scissor_extent.height = std::min(scissor_extent.height, render_area.height);
+
+    // TODO(Rodrigo): Implement layer clears
+    const vk::ClearRect clear_rect({scissor_offset, scissor_extent}, 0, 1);
 
     if (use_color) {
-        View color_view;
-        {
-            MICROPROFILE_SCOPE(Vulkan_RenderTargets);
-            color_view = texture_cache.GetColorBufferSurface(regs.clear_buffers.RT.Value(), false);
-        }
-
-        color_view->Transition(vk::ImageLayout::eTransferDstOptimal,
-                               vk::PipelineStageFlagBits::eTransfer,
-                               vk::AccessFlagBits::eTransferWrite);
-
         const std::array clear_color = {regs.clear_color[0], regs.clear_color[1],
                                         regs.clear_color[2], regs.clear_color[3]};
-        const vk::ClearColorValue clear(clear_color);
-        scheduler.Record([image = color_view->GetImage(),
-                          subresource = color_view->GetImageSubresourceRange(),
-                          clear](auto cmdbuf, auto& dld) {
-            cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal, clear, subresource,
-                                   dld);
+        const vk::ClearValue clear_value{clear_color};
+        const u32 color_attachment = regs.clear_buffers.RT;
+        scheduler.Record([color_attachment, clear_value, clear_rect](auto cmdbuf, auto& dld) {
+            const vk::ClearAttachment attachment(vk::ImageAspectFlagBits::eColor, color_attachment,
+                                                 clear_value);
+            cmdbuf.clearAttachments(1, &attachment, 1, &clear_rect, dld);
         });
     }
-    if (use_depth || use_stencil) {
-        View zeta_surface;
-        {
-            MICROPROFILE_SCOPE(Vulkan_RenderTargets);
-            zeta_surface = texture_cache.GetDepthBufferSurface(false);
-        }
 
-        zeta_surface->Transition(vk::ImageLayout::eTransferDstOptimal,
-                                 vk::PipelineStageFlagBits::eTransfer,
-                                 vk::AccessFlagBits::eTransferWrite);
-
-        const vk::ClearDepthStencilValue clear(regs.clear_depth,
-                                               static_cast<u32>(regs.clear_stencil));
-        scheduler.Record([image = zeta_surface->GetImage(),
-                          subresource = zeta_surface->GetImageSubresourceRange(),
-                          clear](auto cmdbuf, auto& dld) {
-            cmdbuf.clearDepthStencilImage(image, vk::ImageLayout::eTransferDstOptimal, clear,
-                                          subresource, dld);
-        });
+    if (!use_depth && !use_stencil) {
+        return;
     }
+    vk::ImageAspectFlags aspect_flags;
+    if (use_depth) {
+        aspect_flags |= vk::ImageAspectFlagBits::eDepth;
+    }
+    if (use_stencil) {
+        aspect_flags |= vk::ImageAspectFlagBits::eStencil;
+    }
+
+    scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil,
+                      clear_rect, aspect_flags](auto cmdbuf, auto& dld) {
+        const vk::ClearDepthStencilValue clear_zeta(clear_depth, clear_stencil);
+        const vk::ClearValue clear_value{clear_zeta};
+        const vk::ClearAttachment attachment(aspect_flags, 0, clear_value);
+        cmdbuf.clearAttachments(1, &attachment, 1, &clear_rect, dld);
+    });
 }
 
 void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index b2e73d98da..3185868e91 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -253,6 +253,7 @@ private:
     VKStagingBufferPool staging_pool;
     VKDescriptorPool descriptor_pool;
     VKUpdateDescriptorQueue update_descriptor_queue;
+    VKRenderPassCache renderpass_cache;
     QuadArrayPass quad_array_pass;
     Uint8Pass uint8_pass;