From c26cb68a0c225ac30768376f0e3a115bb6cab54d Mon Sep 17 00:00:00 2001 From: GPUCode Date: Fri, 3 Mar 2023 16:24:10 +0200 Subject: [PATCH] vk_renderpass_cache: Commonize setup between renderpass and dynamic rendering implementations * Also fix small issue that caused broken rendering on the latter --- .../renderer_vulkan/renderer_vulkan.cpp | 4 +- .../renderer_vulkan/vk_blit_helper.cpp | 4 +- .../vk_format_reinterpreter.cpp | 2 +- .../renderer_vulkan/vk_rasterizer.cpp | 2 +- .../renderer_vulkan/vk_renderpass_cache.cpp | 170 ++++++++---------- .../renderer_vulkan/vk_renderpass_cache.h | 13 +- .../renderer_vulkan/vk_scheduler.cpp | 2 +- .../renderer_vulkan/vk_texture_runtime.cpp | 18 +- .../renderer_vulkan/vk_texture_runtime.h | 4 + 9 files changed, 99 insertions(+), 120 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index bd7103165..63727e9cf 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -236,7 +236,7 @@ void RendererVulkan::BeginRendering(Frame* frame) { instance.GetDevice().updateDescriptorSetWithTemplate(set, present_update_template, present_textures[0]); - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); scheduler.Record([this, framebuffer = frame->framebuffer, width = frame->width, height = frame->height, set, pipeline_index = current_pipeline](vk::CommandBuffer cmdbuf) { @@ -569,7 +569,7 @@ void RendererVulkan::LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color }, }; - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); scheduler.Record([image = texture.image, clear_color](vk::CommandBuffer cmdbuf) { const vk::ImageSubresourceRange range = { .aspectMask = vk::ImageAspectFlagBits::eColor, diff --git a/src/video_core/renderer_vulkan/vk_blit_helper.cpp b/src/video_core/renderer_vulkan/vk_blit_helper.cpp index 43e0178ed..9608ac685 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_helper.cpp @@ -331,7 +331,7 @@ bool BlitHelper::BlitDepthStencil(Surface& source, Surface& dest, vk::DescriptorSet set = desc_manager.AllocateSet(two_textures_descriptor_layout); device.updateDescriptorSetWithTemplate(set, two_textures_update_template, textures[0]); - renderpass_cache.EnterRenderpass(nullptr, &dest, dst_render_area); + renderpass_cache.BeginRendering(nullptr, &dest, dst_render_area); scheduler.Record([blit, set, this](vk::CommandBuffer cmdbuf) { const vk::PipelineLayout layout = two_textures_pipeline_layout; @@ -364,7 +364,7 @@ void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest, vk::DescriptorSet set = desc_manager.AllocateSet(compute_descriptor_layout); device.updateDescriptorSetWithTemplate(set, compute_update_template, textures[0]); - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); scheduler.Record([this, set, blit, src_image = source.Image(), dst_image = dest.Image()](vk::CommandBuffer cmdbuf) { const std::array pre_barriers = { diff --git a/src/video_core/renderer_vulkan/vk_format_reinterpreter.cpp b/src/video_core/renderer_vulkan/vk_format_reinterpreter.cpp index 49d66f829..238d77005 100644 --- a/src/video_core/renderer_vulkan/vk_format_reinterpreter.cpp +++ b/src/video_core/renderer_vulkan/vk_format_reinterpreter.cpp @@ -163,7 +163,7 @@ void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surf vk::DescriptorSet set = desc_manager.AllocateSet(descriptor_layout); device.updateDescriptorSetWithTemplate(set, update_template, textures[0]); - runtime.GetRenderpassCache().ExitRenderpass(); + runtime.GetRenderpassCache().EndRendering(); scheduler.Record([this, set, src_rect, src_image = source.Image(), dst_image = dest.Image()](vk::CommandBuffer cmdbuf) { const std::array pre_barriers = { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index de13a5520..261e000e6 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -496,7 +496,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { UploadUniforms(accelerate); // Begin the renderpass - renderpass_cache.EnterRenderpass(framebuffer); + renderpass_cache.BeginRendering(framebuffer); // Sync the viewport // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp index 327a01f42..28b2a35c8 100644 --- a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp @@ -43,17 +43,13 @@ void RenderpassCache::ClearFramebuffers() { framebuffers.clear(); } -void RenderpassCache::EnterRenderpass(Surface* const color, Surface* const depth_stencil, +void RenderpassCache::BeginRendering(Surface* const color, Surface* const depth_stencil, vk::Rect2D render_area, bool do_clear, vk::ClearValue clear) { - return EnterRenderpass(Framebuffer{color, depth_stencil, render_area}, do_clear, clear); + return BeginRendering(Framebuffer{color, depth_stencil, render_area}, do_clear, clear); } -void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer, bool do_clear, +void RenderpassCache::BeginRendering(const Framebuffer& framebuffer, bool do_clear, vk::ClearValue clear) { - if (dynamic_rendering) { - return BeginRendering(framebuffer, do_clear, clear); - } - RenderingInfo new_info = { .color{ .aspect = vk::ImageAspectFlagBits::eColor, @@ -63,30 +59,84 @@ void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer, bool do_cl .depth{ .aspect = vk::ImageAspectFlagBits::eDepth, .image = framebuffer.Image(SurfaceType::DepthStencil), - .image_view = framebuffer.ImageView(SurfaceType::Color), + .image_view = framebuffer.ImageView(SurfaceType::DepthStencil), }, .render_area = framebuffer.RenderArea(), .clear = clear, .do_clear = do_clear, }; - const PixelFormat color_format = framebuffer.Format(SurfaceType::Color); - const PixelFormat depth_format = framebuffer.Format(SurfaceType::DepthStencil); - if (depth_format == PixelFormat::D24S8) { + if (framebuffer.HasStencil()) { new_info.depth.aspect |= vk::ImageAspectFlagBits::eStencil; } - const bool is_dirty = scheduler.IsStateDirty(StateFlags::Renderpass); - if (info == new_info && rendering && !is_dirty) { + // If the provided rendering context is active we are done + if (info == new_info && rendering) { cmd_count++; return; } - const vk::RenderPass renderpass = GetRenderpass(color_format, depth_format, do_clear); + EndRendering(); + info = new_info; + rendering = true; + + // Begin the render scope + if (dynamic_rendering) { + DynamicRendering(framebuffer); + } else { + EnterRenderpass(framebuffer); + } +} + +void RenderpassCache::DynamicRendering(const Framebuffer& framebuffer) { + const bool has_stencil = framebuffer.HasStencil(); + scheduler.Record([info = info, has_stencil](vk::CommandBuffer cmdbuf) { + u32 cursor = 0; + std::array infos{}; + + const auto Prepare = [&](vk::ImageView image_view) { + if (!image_view) { + cursor++; + return; + } + + infos[cursor++] = vk::RenderingAttachmentInfoKHR{ + .imageView = image_view, + .imageLayout = vk::ImageLayout::eGeneral, + .loadOp = + info.do_clear ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, + .storeOp = vk::AttachmentStoreOp::eStore, + .clearValue = info.clear, + }; + }; + + Prepare(info.color.image_view); + Prepare(info.depth.image_view); + + const u32 color_attachment_count = info.color ? 1u : 0u; + const vk::RenderingAttachmentInfoKHR* depth_info = info.depth ? &infos[1] : nullptr; + const vk::RenderingAttachmentInfoKHR* stencil_info = has_stencil ? &infos[1] : nullptr; + const vk::RenderingInfoKHR rendering_info = { + .renderArea = info.render_area, + .layerCount = 1, + .colorAttachmentCount = color_attachment_count, + .pColorAttachments = &infos[0], + .pDepthAttachment = depth_info, + .pStencilAttachment = stencil_info, + }; + + cmdbuf.beginRenderingKHR(rendering_info); + }); +} + +void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer) { + const PixelFormat color_format = framebuffer.Format(SurfaceType::Color); + const PixelFormat depth_format = framebuffer.Format(SurfaceType::DepthStencil); + const vk::RenderPass renderpass = GetRenderpass(color_format, depth_format, info.do_clear); const FramebufferInfo framebuffer_info = { - .color = new_info.color.image_view, - .depth = new_info.depth.image_view, + .color = info.color.image_view, + .depth = info.depth.image_view, .width = framebuffer.Width(), .height = framebuffer.Height(), }; @@ -96,10 +146,7 @@ void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer, bool do_cl it->second = CreateFramebuffer(framebuffer_info, renderpass); } - if (rendering) { - ExitRenderpass(); - } - scheduler.Record([render_area = new_info.render_area, clear, renderpass, + scheduler.Record([render_area = info.render_area, clear = info.clear, renderpass, framebuffer = it->second](vk::CommandBuffer cmdbuf) { const vk::RenderPassBeginInfo renderpass_begin_info = { .renderPass = renderpass, @@ -111,13 +158,9 @@ void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer, bool do_cl cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline); }); - - scheduler.MarkStateNonDirty(StateFlags::Renderpass); - info = new_info; - rendering = true; } -void RenderpassCache::ExitRenderpass() { +void RenderpassCache::EndRendering() { if (!rendering) { return; } @@ -191,81 +234,6 @@ void RenderpassCache::ExitRenderpass() { } } -void RenderpassCache::BeginRendering(const Framebuffer& framebuffer, bool do_clear, - vk::ClearValue clear) { - RenderingInfo new_info = { - .color{ - .aspect = vk::ImageAspectFlagBits::eColor, - .image = framebuffer.Image(SurfaceType::Color), - .image_view = framebuffer.ImageView(SurfaceType::Color), - }, - .depth{ - .aspect = vk::ImageAspectFlagBits::eDepth, - .image = framebuffer.Image(SurfaceType::DepthStencil), - .image_view = framebuffer.ImageView(SurfaceType::DepthStencil), - }, - .render_area = framebuffer.RenderArea(), - .clear = clear, - .do_clear = do_clear, - }; - - const bool has_stencil = framebuffer.Format(SurfaceType::DepthStencil) == PixelFormat::D24S8; - if (has_stencil) { - new_info.depth.aspect |= vk::ImageAspectFlagBits::eStencil; - } - - const bool is_dirty = scheduler.IsStateDirty(StateFlags::Renderpass); - if (info == new_info && rendering && !is_dirty) { - cmd_count++; - return; - } - - if (rendering) { - ExitRenderpass(); - } - scheduler.Record([new_info, has_stencil](vk::CommandBuffer cmdbuf) { - u32 cursor = 0; - std::array infos{}; - - const auto Prepare = [&](vk::ImageView image_view) { - if (!image_view) { - cursor++; - return; - } - - infos[cursor++] = vk::RenderingAttachmentInfoKHR{ - .imageView = image_view, - .imageLayout = vk::ImageLayout::eGeneral, - .loadOp = - new_info.do_clear ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, - .storeOp = vk::AttachmentStoreOp::eStore, - .clearValue = new_info.clear, - }; - }; - - Prepare(new_info.color.image_view); - Prepare(new_info.depth.image_view); - - const u32 color_attachment_count = new_info.color ? 1u : 0u; - const vk::RenderingAttachmentInfoKHR* depth_info = new_info.depth ? &infos[1] : nullptr; - const vk::RenderingAttachmentInfoKHR* stencil_info = has_stencil ? &infos[1] : nullptr; - const vk::RenderingInfoKHR rendering_info = { - .renderArea = new_info.render_area, - .layerCount = 1, - .colorAttachmentCount = color_attachment_count, - .pColorAttachments = &infos[0], - .pDepthAttachment = depth_info, - .pStencilAttachment = stencil_info, - }; - - cmdbuf.beginRenderingKHR(rendering_info); - }); - - scheduler.MarkStateNonDirty(StateFlags::Renderpass); - info = new_info; - rendering = true; -} - void RenderpassCache::CreatePresentRenderpass(vk::Format format) { if (!present_renderpass) { present_renderpass = @@ -276,6 +244,8 @@ void RenderpassCache::CreatePresentRenderpass(vk::Format format) { vk::RenderPass RenderpassCache::GetRenderpass(VideoCore::PixelFormat color, VideoCore::PixelFormat depth, bool is_clear) { + std::scoped_lock lock{cache_mutex}; + const u32 color_index = color == VideoCore::PixelFormat::Invalid ? MAX_COLOR_FORMATS : static_cast(color); const u32 depth_index = depth == VideoCore::PixelFormat::Invalid diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.h b/src/video_core/renderer_vulkan/vk_renderpass_cache.h index c6b27023a..507eaf69a 100644 --- a/src/video_core/renderer_vulkan/vk_renderpass_cache.h +++ b/src/video_core/renderer_vulkan/vk_renderpass_cache.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "common/hash.h" #include "video_core/rasterizer_cache/pixel_format.h" @@ -53,13 +54,13 @@ public: void ClearFramebuffers(); /// Begins a new renderpass only when no other renderpass is currently active - void EnterRenderpass(const Framebuffer& framebuffer, bool do_clear = false, + void BeginRendering(const Framebuffer& framebuffer, bool do_clear = false, vk::ClearValue clear = {}); - void EnterRenderpass(Surface* const color, Surface* const depth_stencil, vk::Rect2D render_area, + void BeginRendering(Surface* const color, Surface* const depth_stencil, vk::Rect2D render_area, bool do_clear = false, vk::ClearValue clear = {}); /// Exits from any currently active renderpass instance - void ExitRenderpass(); + void EndRendering(); /// Creates the renderpass used when rendering to the swapchain void CreatePresentRenderpass(vk::Format format); @@ -75,7 +76,10 @@ public: private: /// Begins a new rendering scope using dynamic rendering - void BeginRendering(const Framebuffer& framebuffer, bool do_clear, vk::ClearValue clear); + void DynamicRendering(const Framebuffer& framebuffer); + + /// Begins a new rendering scope using renderpasses + void EnterRenderpass(const Framebuffer& framebuffer); /// Creates a renderpass configured appropriately and stores it in cached_renderpasses vk::RenderPass CreateRenderPass(vk::Format color, vk::Format depth, @@ -123,6 +127,7 @@ private: bool rendering = false; bool dynamic_rendering = false; u32 cmd_count{}; + std::mutex cache_mutex; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 680cfd356..32944021d 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -121,7 +121,7 @@ void Scheduler::SubmitExecution(vk::Semaphore signal_semaphore, vk::Semaphore wa const u64 signal_value = master_semaphore.NextTick(); state = StateFlags::AllDirty; - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); Record( [signal_semaphore, wait_semaphore, handle, signal_value, this](vk::CommandBuffer cmdbuf) { MICROPROFILE_SCOPE(Vulkan_Submit); diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp index 89475488a..10b909079 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp @@ -263,7 +263,7 @@ Allocation TextureRuntime::Allocate(u32 width, u32 height, u32 levels, bool is_m vk::Device device = instance.GetDevice(); vk::UniqueImageView image_view = device.createImageViewUnique(view_info); - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); scheduler.Record([image, aspect](vk::CommandBuffer cmdbuf) { const vk::ImageMemoryBarrier init_barrier = { .srcAccessMask = vk::AccessFlagBits::eNone, @@ -305,7 +305,7 @@ void TextureRuntime::Recycle(const HostTextureTag tag, Allocation&& alloc) { } bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) { - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); const RecordParams params = { .aspect = surface.alloc.aspect, @@ -445,9 +445,9 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface, }, }; - renderpass_cache.EnterRenderpass(color_surface, depth_surface, render_area, true, + renderpass_cache.BeginRendering(color_surface, depth_surface, render_area, true, MakeClearValue(clear.value)); - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); scheduler.Record([params, access_flag, pipeline_flags](vk::CommandBuffer cmdbuf) { const vk::ImageMemoryBarrier post_barrier = { @@ -474,7 +474,7 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface, bool TextureRuntime::CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy) { - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); const RecordParams params = { .aspect = source.alloc.aspect, @@ -603,7 +603,7 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, return blit_helper.BlitDepthStencil(source, dest, blit); } - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); const RecordParams params = { .aspect = source.alloc.aspect, @@ -735,7 +735,7 @@ void TextureRuntime::GenerateMipmaps(Surface& surface) { return; } - renderpass_cache.ExitRenderpass(); + renderpass_cache.EndRendering(); // Always use the allocation width on custom textures u32 current_width = surface.alloc.width; @@ -823,7 +823,7 @@ Surface::~Surface() { } void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) { - runtime->renderpass_cache.ExitRenderpass(); + runtime->renderpass_cache.EndRendering(); const bool is_scaled = res_scale != 1; if (is_scaled) { @@ -919,7 +919,7 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa } void Surface::Download(const VideoCore::BufferTextureCopy& download, const StagingData& staging) { - runtime->renderpass_cache.ExitRenderpass(); + runtime->renderpass_cache.EndRendering(); // For depth stencil downloads always use the compute shader fallback // to avoid having the interleave the data later. These should(?) be diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.h b/src/video_core/renderer_vulkan/vk_texture_runtime.h index 564dec1a0..49526a345 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.h +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.h @@ -263,6 +263,10 @@ public: return static_cast(image_views[Index(type)]); } + bool HasStencil() const noexcept { + return Format(VideoCore::SurfaceType::DepthStencil) == VideoCore::PixelFormat::D24S8; + } + u32 Width() const noexcept { return width; }