diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 0d37b70d1..8f80a3cff 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -335,6 +335,24 @@ void RendererVulkan::BeginRendering() { command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, present_pipeline_layout, 0, 1, &set, 0, nullptr); + + const vk::ClearValue clear_value = { + .color = clear_color + }; + + const auto& layout = render_window.GetFramebufferLayout(); + const vk::RenderPassBeginInfo begin_info = { + .renderPass = renderpass_cache.GetPresentRenderpass(), + .framebuffer = swapchain.GetFramebuffer(), + .renderArea = vk::Rect2D{ + .offset = {0, 0}, + .extent = {layout.width, layout.height} + }, + .clearValueCount = 1, + .pClearValues = &clear_value, + }; + + command_buffer.beginRenderPass(begin_info, vk::SubpassContents::eInline); } void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, @@ -686,27 +704,8 @@ void RendererVulkan::DrawSingleScreenRotated(u32 screen_id, float x, float y, fl vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex, 0, sizeof(draw_info), &draw_info); - const vk::ClearValue clear_value = { - .color = clear_color - }; - - const auto& layout = render_window.GetFramebufferLayout(); - const vk::RenderPassBeginInfo begin_info = { - .renderPass = renderpass_cache.GetPresentRenderpass(), - .framebuffer = swapchain.GetFramebuffer(), - .renderArea = vk::Rect2D{ - .offset = {0, 0}, - .extent = {layout.width, layout.height} - }, - .clearValueCount = 1, - .pClearValues = &clear_value, - }; - - command_buffer.beginRenderPass(begin_info, vk::SubpassContents::eInline); - command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(), {0}); command_buffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0); - command_buffer.endRenderPass(); } void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w, float h) { @@ -930,7 +929,6 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f } } - return; draw_info.layer = 0; if (layout.bottom_screen_enabled) { if (layout.is_rotated) { @@ -993,6 +991,9 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f } } } + + vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); + command_buffer.endRenderPass(); } void RendererVulkan::SwapBuffers() { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 66beb380d..9b0aebe64 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -124,7 +124,7 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instan default_texture = runtime.Allocate(1, 1, VideoCore::PixelFormat::RGBA8, VideoCore::TextureType::Texture2D); runtime.Transition(scheduler.GetUploadCommandBuffer(), default_texture, - vk::ImageLayout::eGeneral, 0, 1); + vk::ImageLayout::eShaderReadOnlyOptimal, 0, 1); uniform_block_data.lighting_lut_dirty.fill(true); @@ -822,6 +822,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { .pClearValues = nullptr }; + renderpass_cache.EnterRenderpass(renderpass_begin); + // Draw the vertex batch bool succeeded = true; if (accelerate) { @@ -848,9 +850,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { std::memcpy(array_ptr, vertex_batch.data() + base_vertex, vertex_size); vertex_buffer.Commit(vertex_size); - renderpass_cache.EnterRenderpass(renderpass_begin); command_buffer.draw(vertices, 1, base_vertex, 0); - renderpass_cache.ExitRenderpass(); } } diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp index f1fecef77..fdd38bcdf 100644 --- a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp @@ -77,11 +77,12 @@ RenderpassCache::~RenderpassCache() { } void RenderpassCache::EnterRenderpass(const vk::RenderPassBeginInfo begin_info) { + vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); + if (renderpass_active) { - return; + command_buffer.endRenderPass(); } - vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); command_buffer.beginRenderPass(begin_info, vk::SubpassContents::eInline); renderpass_active = true; } diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp index 9c142e5ba..010b3b37a 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp @@ -130,11 +130,20 @@ std::tuple StreamBuffer::Map(u32 size, u32 alignment) { // Have we run out of available space? bool invalidate = false; if (available_size < size) { - // Flush any pending writes before continuing - Flush(); - // If we are at the end of the buffer, start over if (buffer_offset + size > total_size) { + // Flush any pending writes before looping back + Flush(); + + // Since new regions are discovered based on locks, insert a lock + // that reaches the end of the buffer to avoid having an empty region + const LockedRegion region = { + .size = total_size - buffer_offset, + .fence_counter = scheduler.GetFenceCounter() + }; + + regions.emplace(buffer_offset, region); + Invalidate(); invalidate = true; } @@ -154,26 +163,8 @@ std::tuple StreamBuffer::Map(u32 size, u32 alignment) { } void StreamBuffer::Commit(u32 size) { - if (size > 0) { - vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); - - auto [access_mask, stage_mask] = ToVkAccessStageFlags(usage); - const vk::BufferMemoryBarrier buffer_barrier = { - .srcAccessMask = vk::AccessFlagBits::eTransferWrite, - .dstAccessMask = access_mask, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .buffer = buffer, - .offset = buffer_offset, - .size = size - }; - - command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_mask, - vk::DependencyFlagBits::eByRegion, {}, buffer_barrier, {}); - - buffer_offset += size; - available_size -= size; - } + buffer_offset += size; + available_size -= size; } void StreamBuffer::Flush() { @@ -199,6 +190,22 @@ void StreamBuffer::Flush() { }; regions.emplace(flush_start, region); + + // Add pipeline barrier for the flushed region + auto [access_mask, stage_mask] = ToVkAccessStageFlags(usage); + const vk::BufferMemoryBarrier buffer_barrier = { + .srcAccessMask = vk::AccessFlagBits::eTransferWrite, + .dstAccessMask = access_mask, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = buffer, + .offset = flush_start, + .size = flush_size + }; + + command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_mask, + vk::DependencyFlagBits::eByRegion, {}, buffer_barrier, {}); + flush_start = buffer_offset; } } @@ -225,7 +232,7 @@ bool StreamBuffer::UnlockFreeRegions(u32 target_size) { } // If that wasn't enough, try waiting for some fences - while (available_size < target_size) { + while (it != regions.end() && available_size < target_size) { const auto& [offset, region] = *it; if (region.fence_counter > scheduler.GetFenceCounter()) { diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp index 04b55a568..549c4156e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp @@ -513,6 +513,8 @@ MICROPROFILE_DEFINE(Vulkan_Upload, "VulkanSurface", "Texture Upload", MP_RGB(128 void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) { MICROPROFILE_SCOPE(Vulkan_Upload); + runtime.renderpass_cache.ExitRenderpass(); + const bool is_scaled = res_scale != 1; if (is_scaled) { ScaledUpload(upload); @@ -551,6 +553,8 @@ MICROPROFILE_DEFINE(Vulkan_Download, "VulkanSurface", "Texture Download", MP_RGB void Surface::Download(const VideoCore::BufferTextureCopy& download, const StagingData& staging) { MICROPROFILE_SCOPE(Vulkan_Download); + runtime.renderpass_cache.ExitRenderpass(); + const bool is_scaled = res_scale != 1; if (is_scaled) { ScaledDownload(download);