summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorGravatar Fernando S2022-10-06 21:29:53 +0200
committerGravatar GitHub2022-10-06 21:29:53 +0200
commit1effa578f12f79d7816e3543291f302f126cc1d2 (patch)
tree14803b31b6817294d40d57446f6fa94c5ff3fe9a /src/video_core/renderer_vulkan
parentMerge pull request #9025 from FernandoS27/slava-ukrayini (diff)
parentvulkan_blitter: Fix pool allocation double free. (diff)
downloadyuzu-1effa578f12f79d7816e3543291f302f126cc1d2.tar.gz
yuzu-1effa578f12f79d7816e3543291f302f126cc1d2.tar.xz
yuzu-1effa578f12f79d7816e3543291f302f126cc1d2.zip
Merge pull request #8467 from FernandoS27/yfc-rel-1
Project yuzu Fried Chicken (Y.F.C.) Part 1
Diffstat (limited to 'src/video_core/renderer_vulkan')
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp2
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp13
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp18
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h28
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp34
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp123
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h29
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.cpp18
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.h27
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp32
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h5
21 files changed, 240 insertions, 159 deletions
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 6703b8e68..e7104d377 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -184,7 +184,7 @@ struct FormatTuple {
184 {VK_FORMAT_BC3_SRGB_BLOCK}, // BC3_SRGB 184 {VK_FORMAT_BC3_SRGB_BLOCK}, // BC3_SRGB
185 {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7_SRGB 185 {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7_SRGB
186 {VK_FORMAT_R4G4B4A4_UNORM_PACK16, Attachable}, // A4B4G4R4_UNORM 186 {VK_FORMAT_R4G4B4A4_UNORM_PACK16, Attachable}, // A4B4G4R4_UNORM
187 {VK_FORMAT_R4G4_UNORM_PACK8}, // R4G4_UNORM 187 {VK_FORMAT_R4G4_UNORM_PACK8}, // G4R4_UNORM
188 {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB 188 {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB
189 {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB 189 {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB
190 {VK_FORMAT_ASTC_8x5_SRGB_BLOCK}, // ASTC_2D_8X5_SRGB 190 {VK_FORMAT_ASTC_8x5_SRGB_BLOCK}, // ASTC_2D_8X5_SRGB
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 7c78d0299..d8131232a 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -102,13 +102,13 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
102 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), 102 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
103 surface(CreateSurface(instance, render_window)), 103 surface(CreateSurface(instance, render_window)),
104 device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), 104 device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false),
105 state_tracker(gpu), scheduler(device, state_tracker), 105 state_tracker(), scheduler(device, state_tracker),
106 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, 106 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
107 render_window.GetFramebufferLayout().height, false), 107 render_window.GetFramebufferLayout().height, false),
108 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler, 108 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler,
109 screen_info), 109 screen_info),
110 rasterizer(render_window, gpu, gpu.MemoryManager(), cpu_memory, screen_info, device, 110 rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator,
111 memory_allocator, state_tracker, scheduler) { 111 state_tracker, scheduler) {
112 Report(); 112 Report();
113} catch (const vk::Exception& exception) { 113} catch (const vk::Exception& exception) {
114 LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what()); 114 LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what());
@@ -142,7 +142,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
142 const auto recreate_swapchain = [&] { 142 const auto recreate_swapchain = [&] {
143 if (!has_been_recreated) { 143 if (!has_been_recreated) {
144 has_been_recreated = true; 144 has_been_recreated = true;
145 scheduler.WaitWorker(); 145 scheduler.Finish();
146 } 146 }
147 const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); 147 const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
148 swapchain.Create(layout.width, layout.height, is_srgb); 148 swapchain.Create(layout.width, layout.height, is_srgb);
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 444c29f68..cb7fa2078 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -145,6 +145,11 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
145 // Finish any pending renderpass 145 // Finish any pending renderpass
146 scheduler.RequestOutsideRenderPassOperationContext(); 146 scheduler.RequestOutsideRenderPassOperationContext();
147 147
148 if (const auto swapchain_images = swapchain.GetImageCount(); swapchain_images != image_count) {
149 image_count = swapchain_images;
150 Recreate();
151 }
152
148 const std::size_t image_index = swapchain.GetImageIndex(); 153 const std::size_t image_index = swapchain.GetImageIndex();
149 154
150 scheduler.Wait(resource_ticks[image_index]); 155 scheduler.Wait(resource_ticks[image_index]);
@@ -448,15 +453,15 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkE
448 453
449void BlitScreen::CreateStaticResources() { 454void BlitScreen::CreateStaticResources() {
450 CreateShaders(); 455 CreateShaders();
456 CreateSampler();
457}
458
459void BlitScreen::CreateDynamicResources() {
451 CreateSemaphores(); 460 CreateSemaphores();
452 CreateDescriptorPool(); 461 CreateDescriptorPool();
453 CreateDescriptorSetLayout(); 462 CreateDescriptorSetLayout();
454 CreateDescriptorSets(); 463 CreateDescriptorSets();
455 CreatePipelineLayout(); 464 CreatePipelineLayout();
456 CreateSampler();
457}
458
459void BlitScreen::CreateDynamicResources() {
460 CreateRenderPass(); 465 CreateRenderPass();
461 CreateFramebuffers(); 466 CreateFramebuffers();
462 CreateGraphicsPipeline(); 467 CreateGraphicsPipeline();
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index b8c67bef0..29e2ea925 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -109,7 +109,7 @@ private:
109 MemoryAllocator& memory_allocator; 109 MemoryAllocator& memory_allocator;
110 Swapchain& swapchain; 110 Swapchain& swapchain;
111 Scheduler& scheduler; 111 Scheduler& scheduler;
112 const std::size_t image_count; 112 std::size_t image_count;
113 const ScreenInfo& screen_info; 113 const ScreenInfo& screen_info;
114 114
115 vk::ShaderModule vertex_shader; 115 vk::ShaderModule vertex_shader;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index f17a5ccd6..241d7573e 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -26,8 +26,6 @@
26 26
27namespace Vulkan { 27namespace Vulkan {
28 28
29using Tegra::Texture::SWIZZLE_TABLE;
30
31namespace { 29namespace {
32 30
33constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0; 31constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 6447210e2..7906e11a8 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -126,8 +126,8 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
126 const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset}; 126 const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset};
127 const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() + 127 const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() +
128 secondary_offset}; 128 secondary_offset};
129 const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; 129 const u32 lhs_raw{gpu_memory.Read<u32>(addr) << desc.shift_left};
130 const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; 130 const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr) << desc.secondary_shift_left};
131 return TexturePair(lhs_raw | rhs_raw, via_header_index); 131 return TexturePair(lhs_raw | rhs_raw, via_header_index);
132 } 132 }
133 } 133 }
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index c249b34d4..0214b103a 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -11,11 +11,8 @@
11 11
12namespace Vulkan { 12namespace Vulkan {
13 13
14InnerFence::InnerFence(Scheduler& scheduler_, u32 payload_, bool is_stubbed_) 14InnerFence::InnerFence(Scheduler& scheduler_, bool is_stubbed_)
15 : FenceBase{payload_, is_stubbed_}, scheduler{scheduler_} {} 15 : FenceBase{is_stubbed_}, scheduler{scheduler_} {}
16
17InnerFence::InnerFence(Scheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_)
18 : FenceBase{address_, payload_, is_stubbed_}, scheduler{scheduler_} {}
19 16
20InnerFence::~InnerFence() = default; 17InnerFence::~InnerFence() = default;
21 18
@@ -48,12 +45,8 @@ FenceManager::FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::G
48 : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, 45 : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_},
49 scheduler{scheduler_} {} 46 scheduler{scheduler_} {}
50 47
51Fence FenceManager::CreateFence(u32 value, bool is_stubbed) { 48Fence FenceManager::CreateFence(bool is_stubbed) {
52 return std::make_shared<InnerFence>(scheduler, value, is_stubbed); 49 return std::make_shared<InnerFence>(scheduler, is_stubbed);
53}
54
55Fence FenceManager::CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) {
56 return std::make_shared<InnerFence>(scheduler, addr, value, is_stubbed);
57} 50}
58 51
59void FenceManager::QueueFence(Fence& fence) { 52void FenceManager::QueueFence(Fence& fence) {
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h
index 7c0bbd80a..7fe2afcd9 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.h
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.h
@@ -25,8 +25,7 @@ class Scheduler;
25 25
26class InnerFence : public VideoCommon::FenceBase { 26class InnerFence : public VideoCommon::FenceBase {
27public: 27public:
28 explicit InnerFence(Scheduler& scheduler_, u32 payload_, bool is_stubbed_); 28 explicit InnerFence(Scheduler& scheduler_, bool is_stubbed_);
29 explicit InnerFence(Scheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_);
30 ~InnerFence(); 29 ~InnerFence();
31 30
32 void Queue(); 31 void Queue();
@@ -50,8 +49,7 @@ public:
50 QueryCache& query_cache, const Device& device, Scheduler& scheduler); 49 QueryCache& query_cache, const Device& device, Scheduler& scheduler);
51 50
52protected: 51protected:
53 Fence CreateFence(u32 value, bool is_stubbed) override; 52 Fence CreateFence(bool is_stubbed) override;
54 Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override;
55 void QueueFence(Fence& fence) override; 53 void QueueFence(Fence& fence) override;
56 bool IsFenceSignaled(Fence& fence) const override; 54 bool IsFenceSignaled(Fence& fence) const override;
57 void WaitFence(Fence& fence) override; 55 void WaitFence(Fence& fence) override;
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 5aca8f038..f47786f48 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -215,15 +215,14 @@ ConfigureFuncPtr ConfigureFunc(const std::array<vk::ShaderModule, NUM_STAGES>& m
215} // Anonymous namespace 215} // Anonymous namespace
216 216
217GraphicsPipeline::GraphicsPipeline( 217GraphicsPipeline::GraphicsPipeline(
218 Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_, Scheduler& scheduler_, 218 Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_,
219 BufferCache& buffer_cache_, TextureCache& texture_cache_,
220 VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, 219 VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool,
221 UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, 220 UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread,
222 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, 221 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
223 const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages, 222 const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,
224 const std::array<const Shader::Info*, NUM_STAGES>& infos) 223 const std::array<const Shader::Info*, NUM_STAGES>& infos)
225 : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_}, 224 : key{key_}, device{device_}, texture_cache{texture_cache_},
226 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_}, 225 buffer_cache{buffer_cache_}, scheduler{scheduler_},
227 update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} { 226 update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} {
228 if (shader_notify) { 227 if (shader_notify) {
229 shader_notify->MarkShaderBuilding(); 228 shader_notify->MarkShaderBuilding();
@@ -288,7 +287,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
288 287
289 buffer_cache.SetUniformBuffersState(enabled_uniform_buffer_masks, &uniform_buffer_sizes); 288 buffer_cache.SetUniformBuffersState(enabled_uniform_buffer_masks, &uniform_buffer_sizes);
290 289
291 const auto& regs{maxwell3d.regs}; 290 const auto& regs{maxwell3d->regs};
292 const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex}; 291 const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex};
293 const auto config_stage{[&](size_t stage) LAMBDA_FORCEINLINE { 292 const auto config_stage{[&](size_t stage) LAMBDA_FORCEINLINE {
294 const Shader::Info& info{stage_infos[stage]}; 293 const Shader::Info& info{stage_infos[stage]};
@@ -302,7 +301,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
302 ++ssbo_index; 301 ++ssbo_index;
303 } 302 }
304 } 303 }
305 const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers}; 304 const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers};
306 const auto read_handle{[&](const auto& desc, u32 index) { 305 const auto read_handle{[&](const auto& desc, u32 index) {
307 ASSERT(cbufs[desc.cbuf_index].enabled); 306 ASSERT(cbufs[desc.cbuf_index].enabled);
308 const u32 index_offset{index << desc.size_shift}; 307 const u32 index_offset{index << desc.size_shift};
@@ -315,13 +314,14 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
315 const u32 second_offset{desc.secondary_cbuf_offset + index_offset}; 314 const u32 second_offset{desc.secondary_cbuf_offset + index_offset};
316 const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address + 315 const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address +
317 second_offset}; 316 second_offset};
318 const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; 317 const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left};
319 const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; 318 const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr)
319 << desc.secondary_shift_left};
320 const u32 raw{lhs_raw | rhs_raw}; 320 const u32 raw{lhs_raw | rhs_raw};
321 return TexturePair(raw, via_header_index); 321 return TexturePair(raw, via_header_index);
322 } 322 }
323 } 323 }
324 return TexturePair(gpu_memory.Read<u32>(addr), via_header_index); 324 return TexturePair(gpu_memory->Read<u32>(addr), via_header_index);
325 }}; 325 }};
326 const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE { 326 const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE {
327 for (u32 index = 0; index < desc.count; ++index) { 327 for (u32 index = 0; index < desc.count; ++index) {
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index e8949a9ab..85602592b 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -69,15 +69,16 @@ class GraphicsPipeline {
69 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 69 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
70 70
71public: 71public:
72 explicit GraphicsPipeline( 72 explicit GraphicsPipeline(Scheduler& scheduler, BufferCache& buffer_cache,
73 Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, 73 TextureCache& texture_cache, VideoCore::ShaderNotify* shader_notify,
74 Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, 74 const Device& device, DescriptorPool& descriptor_pool,
75 VideoCore::ShaderNotify* shader_notify, const Device& device, 75 UpdateDescriptorQueue& update_descriptor_queue,
76 DescriptorPool& descriptor_pool, UpdateDescriptorQueue& update_descriptor_queue, 76 Common::ThreadWorker* worker_thread,
77 Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics, 77 PipelineStatistics* pipeline_statistics,
78 RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key, 78 RenderPassCache& render_pass_cache,
79 std::array<vk::ShaderModule, NUM_STAGES> stages, 79 const GraphicsPipelineCacheKey& key,
80 const std::array<const Shader::Info*, NUM_STAGES>& infos); 80 std::array<vk::ShaderModule, NUM_STAGES> stages,
81 const std::array<const Shader::Info*, NUM_STAGES>& infos);
81 82
82 GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; 83 GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
83 GraphicsPipeline(GraphicsPipeline&&) noexcept = delete; 84 GraphicsPipeline(GraphicsPipeline&&) noexcept = delete;
@@ -109,6 +110,11 @@ public:
109 return [](GraphicsPipeline* pl, bool is_indexed) { pl->ConfigureImpl<Spec>(is_indexed); }; 110 return [](GraphicsPipeline* pl, bool is_indexed) { pl->ConfigureImpl<Spec>(is_indexed); };
110 } 111 }
111 112
113 void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) {
114 maxwell3d = maxwell3d_;
115 gpu_memory = gpu_memory_;
116 }
117
112private: 118private:
113 template <typename Spec> 119 template <typename Spec>
114 void ConfigureImpl(bool is_indexed); 120 void ConfigureImpl(bool is_indexed);
@@ -120,8 +126,8 @@ private:
120 void Validate(); 126 void Validate();
121 127
122 const GraphicsPipelineCacheKey key; 128 const GraphicsPipelineCacheKey key;
123 Tegra::Engines::Maxwell3D& maxwell3d; 129 Tegra::Engines::Maxwell3D* maxwell3d;
124 Tegra::MemoryManager& gpu_memory; 130 Tegra::MemoryManager* gpu_memory;
125 const Device& device; 131 const Device& device;
126 TextureCache& texture_cache; 132 TextureCache& texture_cache;
127 BufferCache& buffer_cache; 133 BufferCache& buffer_cache;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index accbfc8e1..732e7b6f2 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -259,17 +259,15 @@ bool GraphicsPipelineCacheKey::operator==(const GraphicsPipelineCacheKey& rhs) c
259 return std::memcmp(&rhs, this, Size()) == 0; 259 return std::memcmp(&rhs, this, Size()) == 0;
260} 260}
261 261
262PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxwell3D& maxwell3d_, 262PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device_,
263 Tegra::Engines::KeplerCompute& kepler_compute_,
264 Tegra::MemoryManager& gpu_memory_, const Device& device_,
265 Scheduler& scheduler_, DescriptorPool& descriptor_pool_, 263 Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
266 UpdateDescriptorQueue& update_descriptor_queue_, 264 UpdateDescriptorQueue& update_descriptor_queue_,
267 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_, 265 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_,
268 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_) 266 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_)
269 : VideoCommon::ShaderCache{rasterizer_, gpu_memory_, maxwell3d_, kepler_compute_}, 267 : VideoCommon::ShaderCache{rasterizer_}, device{device_}, scheduler{scheduler_},
270 device{device_}, scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, 268 descriptor_pool{descriptor_pool_}, update_descriptor_queue{update_descriptor_queue_},
271 update_descriptor_queue{update_descriptor_queue_}, render_pass_cache{render_pass_cache_}, 269 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_},
272 buffer_cache{buffer_cache_}, texture_cache{texture_cache_}, shader_notify{shader_notify_}, 270 texture_cache{texture_cache_}, shader_notify{shader_notify_},
273 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, 271 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
274 workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"), 272 workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"),
275 serialization_thread(1, "VkPipelineSerialization") { 273 serialization_thread(1, "VkPipelineSerialization") {
@@ -337,7 +335,7 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() {
337 current_pipeline = nullptr; 335 current_pipeline = nullptr;
338 return nullptr; 336 return nullptr;
339 } 337 }
340 graphics_key.state.Refresh(maxwell3d, device.IsExtExtendedDynamicStateSupported(), 338 graphics_key.state.Refresh(*maxwell3d, device.IsExtExtendedDynamicStateSupported(),
341 device.IsExtVertexInputDynamicStateSupported()); 339 device.IsExtVertexInputDynamicStateSupported());
342 340
343 if (current_pipeline) { 341 if (current_pipeline) {
@@ -357,7 +355,7 @@ ComputePipeline* PipelineCache::CurrentComputePipeline() {
357 if (!shader) { 355 if (!shader) {
358 return nullptr; 356 return nullptr;
359 } 357 }
360 const auto& qmd{kepler_compute.launch_description}; 358 const auto& qmd{kepler_compute->launch_description};
361 const ComputePipelineCacheKey key{ 359 const ComputePipelineCacheKey key{
362 .unique_hash = shader->unique_hash, 360 .unique_hash = shader->unique_hash,
363 .shared_memory_size = qmd.shared_alloc, 361 .shared_memory_size = qmd.shared_alloc,
@@ -486,13 +484,13 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const
486 } 484 }
487 // If something is using depth, we can assume that games are not rendering anything which 485 // If something is using depth, we can assume that games are not rendering anything which
488 // will be used one time. 486 // will be used one time.
489 if (maxwell3d.regs.zeta_enable) { 487 if (maxwell3d->regs.zeta_enable) {
490 return nullptr; 488 return nullptr;
491 } 489 }
492 // If games are using a small index count, we can assume these are full screen quads. 490 // If games are using a small index count, we can assume these are full screen quads.
493 // Usually these shaders are only used once for building textures so we can assume they 491 // Usually these shaders are only used once for building textures so we can assume they
494 // can't be built async 492 // can't be built async
495 if (maxwell3d.regs.index_array.count <= 6 || maxwell3d.regs.vertex_buffer.count <= 6) { 493 if (maxwell3d->regs.index_array.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) {
496 return pipeline; 494 return pipeline;
497 } 495 }
498 return nullptr; 496 return nullptr;
@@ -557,10 +555,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
557 previous_stage = &program; 555 previous_stage = &program;
558 } 556 }
559 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 557 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
560 return std::make_unique<GraphicsPipeline>( 558 return std::make_unique<GraphicsPipeline>(scheduler, buffer_cache, texture_cache,
561 maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, &shader_notify, device, 559 &shader_notify, device, descriptor_pool,
562 descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key, 560 update_descriptor_queue, thread_worker, statistics,
563 std::move(modules), infos); 561 render_pass_cache, key, std::move(modules), infos);
564 562
565} catch (const Shader::Exception& exception) { 563} catch (const Shader::Exception& exception) {
566 LOG_ERROR(Render_Vulkan, "{}", exception.what()); 564 LOG_ERROR(Render_Vulkan, "{}", exception.what());
@@ -592,9 +590,9 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() {
592 590
593std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( 591std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
594 const ComputePipelineCacheKey& key, const ShaderInfo* shader) { 592 const ComputePipelineCacheKey& key, const ShaderInfo* shader) {
595 const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()}; 593 const GPUVAddr program_base{kepler_compute->regs.code_loc.Address()};
596 const auto& qmd{kepler_compute.launch_description}; 594 const auto& qmd{kepler_compute->launch_description};
597 ComputeEnvironment env{kepler_compute, gpu_memory, program_base, qmd.program_start}; 595 ComputeEnvironment env{*kepler_compute, *gpu_memory, program_base, qmd.program_start};
598 env.SetCachedSize(shader->size_bytes); 596 env.SetCachedSize(shader->size_bytes);
599 597
600 main_pools.ReleaseContents(); 598 main_pools.ReleaseContents();
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 127957dbf..61f9e9366 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -100,10 +100,8 @@ struct ShaderPools {
100 100
101class PipelineCache : public VideoCommon::ShaderCache { 101class PipelineCache : public VideoCommon::ShaderCache {
102public: 102public:
103 explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d, 103 explicit PipelineCache(RasterizerVulkan& rasterizer, const Device& device, Scheduler& scheduler,
104 Tegra::Engines::KeplerCompute& kepler_compute, 104 DescriptorPool& descriptor_pool,
105 Tegra::MemoryManager& gpu_memory, const Device& device,
106 Scheduler& scheduler, DescriptorPool& descriptor_pool,
107 UpdateDescriptorQueue& update_descriptor_queue, 105 UpdateDescriptorQueue& update_descriptor_queue,
108 RenderPassCache& render_pass_cache, BufferCache& buffer_cache, 106 RenderPassCache& render_pass_cache, BufferCache& buffer_cache,
109 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_); 107 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_);
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 2b859c6b8..7cb02631c 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -65,10 +65,9 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) {
65 usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false; 65 usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false;
66} 66}
67 67
68QueryCache::QueryCache(VideoCore::RasterizerInterface& rasterizer_, 68QueryCache::QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_,
69 Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_, 69 Scheduler& scheduler_)
70 const Device& device_, Scheduler& scheduler_) 70 : QueryCacheBase{rasterizer_}, device{device_}, scheduler{scheduler_},
71 : QueryCacheBase{rasterizer_, maxwell3d_, gpu_memory_}, device{device_}, scheduler{scheduler_},
72 query_pools{ 71 query_pools{
73 QueryPool{device_, scheduler_, QueryType::SamplesPassed}, 72 QueryPool{device_, scheduler_, QueryType::SamplesPassed},
74 } {} 73 } {}
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h
index b0d86c4f8..26762ee09 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.h
+++ b/src/video_core/renderer_vulkan/vk_query_cache.h
@@ -52,9 +52,8 @@ private:
52class QueryCache final 52class QueryCache final
53 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { 53 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> {
54public: 54public:
55 explicit QueryCache(VideoCore::RasterizerInterface& rasterizer_, 55 explicit QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_,
56 Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_, 56 Scheduler& scheduler_);
57 const Device& device_, Scheduler& scheduler_);
58 ~QueryCache(); 57 ~QueryCache();
59 58
60 std::pair<VkQueryPool, u32> AllocateQuery(VideoCore::QueryType type); 59 std::pair<VkQueryPool, u32> AllocateQuery(VideoCore::QueryType type);
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 7e40c2df1..acfd5da7d 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -11,6 +11,7 @@
11#include "common/microprofile.h" 11#include "common/microprofile.h"
12#include "common/scope_exit.h" 12#include "common/scope_exit.h"
13#include "common/settings.h" 13#include "common/settings.h"
14#include "video_core/control/channel_state.h"
14#include "video_core/engines/kepler_compute.h" 15#include "video_core/engines/kepler_compute.h"
15#include "video_core/engines/maxwell_3d.h" 16#include "video_core/engines/maxwell_3d.h"
16#include "video_core/renderer_vulkan/blit_image.h" 17#include "video_core/renderer_vulkan/blit_image.h"
@@ -148,14 +149,11 @@ DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_instan
148} // Anonymous namespace 149} // Anonymous namespace
149 150
150RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 151RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
151 Tegra::MemoryManager& gpu_memory_,
152 Core::Memory::Memory& cpu_memory_, ScreenInfo& screen_info_, 152 Core::Memory::Memory& cpu_memory_, ScreenInfo& screen_info_,
153 const Device& device_, MemoryAllocator& memory_allocator_, 153 const Device& device_, MemoryAllocator& memory_allocator_,
154 StateTracker& state_tracker_, Scheduler& scheduler_) 154 StateTracker& state_tracker_, Scheduler& scheduler_)
155 : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, 155 : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, screen_info{screen_info_}, device{device_},
156 gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, 156 memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_},
157 screen_info{screen_info_}, device{device_}, memory_allocator{memory_allocator_},
158 state_tracker{state_tracker_}, scheduler{scheduler_},
159 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), 157 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
160 update_descriptor_queue(device, scheduler), 158 update_descriptor_queue(device, scheduler),
161 blit_image(device, scheduler, state_tracker, descriptor_pool), 159 blit_image(device, scheduler, state_tracker, descriptor_pool),
@@ -165,14 +163,13 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
165 memory_allocator, staging_pool, 163 memory_allocator, staging_pool,
166 blit_image, astc_decoder_pass, 164 blit_image, astc_decoder_pass,
167 render_pass_cache}, 165 render_pass_cache},
168 texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), 166 texture_cache(texture_cache_runtime, *this),
169 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool, 167 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
170 update_descriptor_queue, descriptor_pool), 168 update_descriptor_queue, descriptor_pool),
171 buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime), 169 buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
172 pipeline_cache(*this, maxwell3d, kepler_compute, gpu_memory, device, scheduler, 170 pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue,
173 descriptor_pool, update_descriptor_queue, render_pass_cache, buffer_cache, 171 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()),
174 texture_cache, gpu.ShaderNotify()), 172 query_cache{*this, device, scheduler}, accelerate_dma{buffer_cache},
175 query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, accelerate_dma{buffer_cache},
176 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), 173 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
177 wfi_event(device.GetLogical().CreateEvent()) { 174 wfi_event(device.GetLogical().CreateEvent()) {
178 scheduler.SetQueryCache(query_cache); 175 scheduler.SetQueryCache(query_cache);
@@ -193,14 +190,16 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
193 return; 190 return;
194 } 191 }
195 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; 192 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
193 // update engine as channel may be different.
194 pipeline->SetEngine(maxwell3d, gpu_memory);
196 pipeline->Configure(is_indexed); 195 pipeline->Configure(is_indexed);
197 196
198 BeginTransformFeedback(); 197 BeginTransformFeedback();
199 198
200 UpdateDynamicStates(); 199 UpdateDynamicStates();
201 200
202 const auto& regs{maxwell3d.regs}; 201 const auto& regs{maxwell3d->regs};
203 const u32 num_instances{maxwell3d.mme_draw.instance_count}; 202 const u32 num_instances{maxwell3d->mme_draw.instance_count};
204 const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_instanced, is_indexed)}; 203 const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_instanced, is_indexed)};
205 scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { 204 scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
206 if (draw_params.is_indexed) { 205 if (draw_params.is_indexed) {
@@ -218,14 +217,14 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
218void RasterizerVulkan::Clear() { 217void RasterizerVulkan::Clear() {
219 MICROPROFILE_SCOPE(Vulkan_Clearing); 218 MICROPROFILE_SCOPE(Vulkan_Clearing);
220 219
221 if (!maxwell3d.ShouldExecute()) { 220 if (!maxwell3d->ShouldExecute()) {
222 return; 221 return;
223 } 222 }
224 FlushWork(); 223 FlushWork();
225 224
226 query_cache.UpdateCounters(); 225 query_cache.UpdateCounters();
227 226
228 auto& regs = maxwell3d.regs; 227 auto& regs = maxwell3d->regs;
229 const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || 228 const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
230 regs.clear_buffers.A; 229 regs.clear_buffers.A;
231 const bool use_depth = regs.clear_buffers.Z; 230 const bool use_depth = regs.clear_buffers.Z;
@@ -248,8 +247,15 @@ void RasterizerVulkan::Clear() {
248 } 247 }
249 UpdateViewportsState(regs); 248 UpdateViewportsState(regs);
250 249
250 VkRect2D default_scissor;
251 default_scissor.offset.x = 0;
252 default_scissor.offset.y = 0;
253 default_scissor.extent.width = std::numeric_limits<s32>::max();
254 default_scissor.extent.height = std::numeric_limits<s32>::max();
255
251 VkClearRect clear_rect{ 256 VkClearRect clear_rect{
252 .rect = GetScissorState(regs, 0, up_scale, down_shift), 257 .rect = regs.clear_flags.scissor ? GetScissorState(regs, 0, up_scale, down_shift)
258 : default_scissor,
253 .baseArrayLayer = regs.clear_buffers.layer, 259 .baseArrayLayer = regs.clear_buffers.layer,
254 .layerCount = 1, 260 .layerCount = 1,
255 }; 261 };
@@ -339,9 +345,9 @@ void RasterizerVulkan::DispatchCompute() {
339 return; 345 return;
340 } 346 }
341 std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex}; 347 std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex};
342 pipeline->Configure(kepler_compute, gpu_memory, scheduler, buffer_cache, texture_cache); 348 pipeline->Configure(*kepler_compute, *gpu_memory, scheduler, buffer_cache, texture_cache);
343 349
344 const auto& qmd{kepler_compute.launch_description}; 350 const auto& qmd{kepler_compute->launch_description};
345 const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z}; 351 const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
346 scheduler.RequestOutsideRenderPassOperationContext(); 352 scheduler.RequestOutsideRenderPassOperationContext();
347 scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); }); 353 scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); });
@@ -422,7 +428,7 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
422 } 428 }
423} 429}
424 430
425void RasterizerVulkan::SyncGuestHost() { 431void RasterizerVulkan::InvalidateGPUCache() {
426 pipeline_cache.SyncGuestHost(); 432 pipeline_cache.SyncGuestHost();
427 { 433 {
428 std::scoped_lock lock{buffer_cache.mutex}; 434 std::scoped_lock lock{buffer_cache.mutex};
@@ -442,40 +448,30 @@ void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) {
442 pipeline_cache.OnCPUWrite(addr, size); 448 pipeline_cache.OnCPUWrite(addr, size);
443} 449}
444 450
445void RasterizerVulkan::ModifyGPUMemory(GPUVAddr addr, u64 size) { 451void RasterizerVulkan::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {
446 { 452 {
447 std::scoped_lock lock{texture_cache.mutex}; 453 std::scoped_lock lock{texture_cache.mutex};
448 texture_cache.UnmapGPUMemory(addr, size); 454 texture_cache.UnmapGPUMemory(as_id, addr, size);
449 } 455 }
450} 456}
451 457
452void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { 458void RasterizerVulkan::SignalFence(std::function<void()>&& func) {
453 if (!gpu.IsAsync()) { 459 fence_manager.SignalFence(std::move(func));
454 gpu_memory.Write<u32>(addr, value); 460}
455 return; 461
456 } 462void RasterizerVulkan::SyncOperation(std::function<void()>&& func) {
457 fence_manager.SignalSemaphore(addr, value); 463 fence_manager.SyncOperation(std::move(func));
458} 464}
459 465
460void RasterizerVulkan::SignalSyncPoint(u32 value) { 466void RasterizerVulkan::SignalSyncPoint(u32 value) {
461 if (!gpu.IsAsync()) {
462 gpu.IncrementSyncPoint(value);
463 return;
464 }
465 fence_manager.SignalSyncPoint(value); 467 fence_manager.SignalSyncPoint(value);
466} 468}
467 469
468void RasterizerVulkan::SignalReference() { 470void RasterizerVulkan::SignalReference() {
469 if (!gpu.IsAsync()) {
470 return;
471 }
472 fence_manager.SignalOrdering(); 471 fence_manager.SignalOrdering();
473} 472}
474 473
475void RasterizerVulkan::ReleaseFences() { 474void RasterizerVulkan::ReleaseFences() {
476 if (!gpu.IsAsync()) {
477 return;
478 }
479 fence_manager.WaitPendingFences(); 475 fence_manager.WaitPendingFences();
480} 476}
481 477
@@ -552,13 +548,13 @@ Tegra::Engines::AccelerateDMAInterface& RasterizerVulkan::AccessAccelerateDMA()
552} 548}
553 549
554void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, 550void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
555 std::span<u8> memory) { 551 std::span<const u8> memory) {
556 auto cpu_addr = gpu_memory.GpuToCpuAddress(address); 552 auto cpu_addr = gpu_memory->GpuToCpuAddress(address);
557 if (!cpu_addr) [[unlikely]] { 553 if (!cpu_addr) [[unlikely]] {
558 gpu_memory.WriteBlock(address, memory.data(), copy_size); 554 gpu_memory->WriteBlock(address, memory.data(), copy_size);
559 return; 555 return;
560 } 556 }
561 gpu_memory.WriteBlockUnsafe(address, memory.data(), copy_size); 557 gpu_memory->WriteBlockUnsafe(address, memory.data(), copy_size);
562 { 558 {
563 std::unique_lock<std::mutex> lock{buffer_cache.mutex}; 559 std::unique_lock<std::mutex> lock{buffer_cache.mutex};
564 if (!buffer_cache.InlineMemory(*cpu_addr, copy_size, memory)) { 560 if (!buffer_cache.InlineMemory(*cpu_addr, copy_size, memory)) {
@@ -627,7 +623,7 @@ bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64
627} 623}
628 624
629void RasterizerVulkan::UpdateDynamicStates() { 625void RasterizerVulkan::UpdateDynamicStates() {
630 auto& regs = maxwell3d.regs; 626 auto& regs = maxwell3d->regs;
631 UpdateViewportsState(regs); 627 UpdateViewportsState(regs);
632 UpdateScissorsState(regs); 628 UpdateScissorsState(regs);
633 UpdateDepthBias(regs); 629 UpdateDepthBias(regs);
@@ -651,7 +647,7 @@ void RasterizerVulkan::UpdateDynamicStates() {
651} 647}
652 648
653void RasterizerVulkan::BeginTransformFeedback() { 649void RasterizerVulkan::BeginTransformFeedback() {
654 const auto& regs = maxwell3d.regs; 650 const auto& regs = maxwell3d->regs;
655 if (regs.tfb_enabled == 0) { 651 if (regs.tfb_enabled == 0) {
656 return; 652 return;
657 } 653 }
@@ -667,7 +663,7 @@ void RasterizerVulkan::BeginTransformFeedback() {
667} 663}
668 664
669void RasterizerVulkan::EndTransformFeedback() { 665void RasterizerVulkan::EndTransformFeedback() {
670 const auto& regs = maxwell3d.regs; 666 const auto& regs = maxwell3d->regs;
671 if (regs.tfb_enabled == 0) { 667 if (regs.tfb_enabled == 0) {
672 return; 668 return;
673 } 669 }
@@ -917,7 +913,7 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs&
917} 913}
918 914
919void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) { 915void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) {
920 auto& dirty{maxwell3d.dirty.flags}; 916 auto& dirty{maxwell3d->dirty.flags};
921 if (!dirty[Dirty::VertexInput]) { 917 if (!dirty[Dirty::VertexInput]) {
922 return; 918 return;
923 } 919 }
@@ -974,4 +970,41 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
974 }); 970 });
975} 971}
976 972
973void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {
974 CreateChannel(channel);
975 {
976 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
977 texture_cache.CreateChannel(channel);
978 buffer_cache.CreateChannel(channel);
979 }
980 pipeline_cache.CreateChannel(channel);
981 query_cache.CreateChannel(channel);
982 state_tracker.SetupTables(channel);
983}
984
985void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) {
986 const s32 channel_id = channel.bind_id;
987 BindToChannel(channel_id);
988 {
989 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
990 texture_cache.BindToChannel(channel_id);
991 buffer_cache.BindToChannel(channel_id);
992 }
993 pipeline_cache.BindToChannel(channel_id);
994 query_cache.BindToChannel(channel_id);
995 state_tracker.ChangeChannel(channel);
996 state_tracker.InvalidateState();
997}
998
999void RasterizerVulkan::ReleaseChannel(s32 channel_id) {
1000 EraseChannel(channel_id);
1001 {
1002 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
1003 texture_cache.EraseChannel(channel_id);
1004 buffer_cache.EraseChannel(channel_id);
1005 }
1006 pipeline_cache.EraseChannel(channel_id);
1007 query_cache.EraseChannel(channel_id);
1008}
1009
977} // namespace Vulkan 1010} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 0370ea39b..4cde3c983 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -8,6 +8,7 @@
8#include <boost/container/static_vector.hpp> 8#include <boost/container/static_vector.hpp>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/control/channel_state_cache.h"
11#include "video_core/engines/maxwell_dma.h" 12#include "video_core/engines/maxwell_dma.h"
12#include "video_core/rasterizer_accelerated.h" 13#include "video_core/rasterizer_accelerated.h"
13#include "video_core/rasterizer_interface.h" 14#include "video_core/rasterizer_interface.h"
@@ -54,13 +55,13 @@ private:
54 BufferCache& buffer_cache; 55 BufferCache& buffer_cache;
55}; 56};
56 57
57class RasterizerVulkan final : public VideoCore::RasterizerAccelerated { 58class RasterizerVulkan final : public VideoCore::RasterizerAccelerated,
59 protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
58public: 60public:
59 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 61 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
60 Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, 62 Core::Memory::Memory& cpu_memory_, ScreenInfo& screen_info_,
61 ScreenInfo& screen_info_, const Device& device_, 63 const Device& device_, MemoryAllocator& memory_allocator_,
62 MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, 64 StateTracker& state_tracker_, Scheduler& scheduler_);
63 Scheduler& scheduler_);
64 ~RasterizerVulkan() override; 65 ~RasterizerVulkan() override;
65 66
66 void Draw(bool is_indexed, bool is_instanced) override; 67 void Draw(bool is_indexed, bool is_instanced) override;
@@ -75,10 +76,11 @@ public:
75 bool MustFlushRegion(VAddr addr, u64 size) override; 76 bool MustFlushRegion(VAddr addr, u64 size) override;
76 void InvalidateRegion(VAddr addr, u64 size) override; 77 void InvalidateRegion(VAddr addr, u64 size) override;
77 void OnCPUWrite(VAddr addr, u64 size) override; 78 void OnCPUWrite(VAddr addr, u64 size) override;
78 void SyncGuestHost() override; 79 void InvalidateGPUCache() override;
79 void UnmapMemory(VAddr addr, u64 size) override; 80 void UnmapMemory(VAddr addr, u64 size) override;
80 void ModifyGPUMemory(GPUVAddr addr, u64 size) override; 81 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
81 void SignalSemaphore(GPUVAddr addr, u32 value) override; 82 void SignalFence(std::function<void()>&& func) override;
83 void SyncOperation(std::function<void()>&& func) override;
82 void SignalSyncPoint(u32 value) override; 84 void SignalSyncPoint(u32 value) override;
83 void SignalReference() override; 85 void SignalReference() override;
84 void ReleaseFences() override; 86 void ReleaseFences() override;
@@ -93,12 +95,18 @@ public:
93 const Tegra::Engines::Fermi2D::Config& copy_config) override; 95 const Tegra::Engines::Fermi2D::Config& copy_config) override;
94 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; 96 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
95 void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, 97 void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
96 std::span<u8> memory) override; 98 std::span<const u8> memory) override;
97 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 99 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
98 u32 pixel_stride) override; 100 u32 pixel_stride) override;
99 void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 101 void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
100 const VideoCore::DiskResourceLoadCallback& callback) override; 102 const VideoCore::DiskResourceLoadCallback& callback) override;
101 103
104 void InitializeChannel(Tegra::Control::ChannelState& channel) override;
105
106 void BindChannel(Tegra::Control::ChannelState& channel) override;
107
108 void ReleaseChannel(s32 channel_id) override;
109
102private: 110private:
103 static constexpr size_t MAX_TEXTURES = 192; 111 static constexpr size_t MAX_TEXTURES = 192;
104 static constexpr size_t MAX_IMAGES = 48; 112 static constexpr size_t MAX_IMAGES = 48;
@@ -134,9 +142,6 @@ private:
134 void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); 142 void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs);
135 143
136 Tegra::GPU& gpu; 144 Tegra::GPU& gpu;
137 Tegra::MemoryManager& gpu_memory;
138 Tegra::Engines::Maxwell3D& maxwell3d;
139 Tegra::Engines::KeplerCompute& kepler_compute;
140 145
141 ScreenInfo& screen_info; 146 ScreenInfo& screen_info;
142 const Device& device; 147 const Device& device;
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
index 9ad096431..f234e1a31 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
@@ -7,9 +7,9 @@
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "video_core/control/channel_state.h"
10#include "video_core/dirty_flags.h" 11#include "video_core/dirty_flags.h"
11#include "video_core/engines/maxwell_3d.h" 12#include "video_core/engines/maxwell_3d.h"
12#include "video_core/gpu.h"
13#include "video_core/renderer_vulkan/vk_state_tracker.h" 13#include "video_core/renderer_vulkan/vk_state_tracker.h"
14 14
15#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name) 15#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
@@ -174,9 +174,8 @@ void SetupDirtyVertexBindings(Tables& tables) {
174} 174}
175} // Anonymous namespace 175} // Anonymous namespace
176 176
177StateTracker::StateTracker(Tegra::GPU& gpu) 177void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
178 : flags{gpu.Maxwell3D().dirty.flags}, invalidation_flags{MakeInvalidationFlags()} { 178 auto& tables{channel_state.maxwell_3d->dirty.tables};
179 auto& tables{gpu.Maxwell3D().dirty.tables};
180 SetupDirtyFlags(tables); 179 SetupDirtyFlags(tables);
181 SetupDirtyViewports(tables); 180 SetupDirtyViewports(tables);
182 SetupDirtyScissors(tables); 181 SetupDirtyScissors(tables);
@@ -199,4 +198,15 @@ StateTracker::StateTracker(Tegra::GPU& gpu)
199 SetupDirtyVertexBindings(tables); 198 SetupDirtyVertexBindings(tables);
200} 199}
201 200
201void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) {
202 flags = &channel_state.maxwell_3d->dirty.flags;
203}
204
205void StateTracker::InvalidateState() {
206 flags->set();
207}
208
209StateTracker::StateTracker()
210 : flags{&default_flags}, default_flags{}, invalidation_flags{MakeInvalidationFlags()} {}
211
202} // namespace Vulkan 212} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h
index a85bc1c10..2296dea60 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.h
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.h
@@ -10,6 +10,12 @@
10#include "video_core/dirty_flags.h" 10#include "video_core/dirty_flags.h"
11#include "video_core/engines/maxwell_3d.h" 11#include "video_core/engines/maxwell_3d.h"
12 12
13namespace Tegra {
14namespace Control {
15struct ChannelState;
16}
17} // namespace Tegra
18
13namespace Vulkan { 19namespace Vulkan {
14 20
15namespace Dirty { 21namespace Dirty {
@@ -53,19 +59,19 @@ class StateTracker {
53 using Maxwell = Tegra::Engines::Maxwell3D::Regs; 59 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
54 60
55public: 61public:
56 explicit StateTracker(Tegra::GPU& gpu); 62 explicit StateTracker();
57 63
58 void InvalidateCommandBufferState() { 64 void InvalidateCommandBufferState() {
59 flags |= invalidation_flags; 65 (*flags) |= invalidation_flags;
60 current_topology = INVALID_TOPOLOGY; 66 current_topology = INVALID_TOPOLOGY;
61 } 67 }
62 68
63 void InvalidateViewports() { 69 void InvalidateViewports() {
64 flags[Dirty::Viewports] = true; 70 (*flags)[Dirty::Viewports] = true;
65 } 71 }
66 72
67 void InvalidateScissors() { 73 void InvalidateScissors() {
68 flags[Dirty::Scissors] = true; 74 (*flags)[Dirty::Scissors] = true;
69 } 75 }
70 76
71 bool TouchViewports() { 77 bool TouchViewports() {
@@ -139,16 +145,23 @@ public:
139 return has_changed; 145 return has_changed;
140 } 146 }
141 147
148 void SetupTables(Tegra::Control::ChannelState& channel_state);
149
150 void ChangeChannel(Tegra::Control::ChannelState& channel_state);
151
152 void InvalidateState();
153
142private: 154private:
143 static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u); 155 static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u);
144 156
145 bool Exchange(std::size_t id, bool new_value) const noexcept { 157 bool Exchange(std::size_t id, bool new_value) const noexcept {
146 const bool is_dirty = flags[id]; 158 const bool is_dirty = (*flags)[id];
147 flags[id] = new_value; 159 (*flags)[id] = new_value;
148 return is_dirty; 160 return is_dirty;
149 } 161 }
150 162
151 Tegra::Engines::Maxwell3D::DirtyState::Flags& flags; 163 Tegra::Engines::Maxwell3D::DirtyState::Flags* flags;
164 Tegra::Engines::Maxwell3D::DirtyState::Flags default_flags;
152 Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags; 165 Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
153 Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY; 166 Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY;
154}; 167};
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index a69ae7725..706d9ba74 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -36,7 +36,8 @@ VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) {
36 // Mailbox (triple buffering) doesn't lock the application like fifo (vsync), 36 // Mailbox (triple buffering) doesn't lock the application like fifo (vsync),
37 // prefer it if vsync option is not selected 37 // prefer it if vsync option is not selected
38 const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); 38 const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR);
39 if (found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) { 39 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Borderless &&
40 found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) {
40 return VK_PRESENT_MODE_MAILBOX_KHR; 41 return VK_PRESENT_MODE_MAILBOX_KHR;
41 } 42 }
42 if (!Settings::values.use_speed_limit.GetValue()) { 43 if (!Settings::values.use_speed_limit.GetValue()) {
@@ -156,8 +157,16 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u3
156 present_mode = ChooseSwapPresentMode(present_modes); 157 present_mode = ChooseSwapPresentMode(present_modes);
157 158
158 u32 requested_image_count{capabilities.minImageCount + 1}; 159 u32 requested_image_count{capabilities.minImageCount + 1};
159 if (capabilities.maxImageCount > 0 && requested_image_count > capabilities.maxImageCount) { 160 // Ensure Tripple buffering if possible.
160 requested_image_count = capabilities.maxImageCount; 161 if (capabilities.maxImageCount > 0) {
162 if (requested_image_count > capabilities.maxImageCount) {
163 requested_image_count = capabilities.maxImageCount;
164 } else {
165 requested_image_count =
166 std::max(requested_image_count, std::min(3U, capabilities.maxImageCount));
167 }
168 } else {
169 requested_image_count = std::max(requested_image_count, 3U);
161 } 170 }
162 VkSwapchainCreateInfoKHR swapchain_ci{ 171 VkSwapchainCreateInfoKHR swapchain_ci{
163 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 172 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index caca79d79..305ad8aee 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -592,7 +592,7 @@ void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4
592 case PixelFormat::A5B5G5R1_UNORM: 592 case PixelFormat::A5B5G5R1_UNORM:
593 std::ranges::transform(swizzle, swizzle.begin(), SwapSpecial); 593 std::ranges::transform(swizzle, swizzle.begin(), SwapSpecial);
594 break; 594 break;
595 case PixelFormat::R4G4_UNORM: 595 case PixelFormat::G4R4_UNORM:
596 std::ranges::transform(swizzle, swizzle.begin(), SwapGreenRed); 596 std::ranges::transform(swizzle, swizzle.begin(), SwapGreenRed);
597 break; 597 break;
598 default: 598 default:
@@ -1474,13 +1474,14 @@ bool Image::BlitScaleHelper(bool scale_up) {
1474 }; 1474 };
1475 const VkExtent2D extent{ 1475 const VkExtent2D extent{
1476 .width = std::max(scaled_width, info.size.width), 1476 .width = std::max(scaled_width, info.size.width),
1477 .height = std::max(scaled_height, info.size.width), 1477 .height = std::max(scaled_height, info.size.height),
1478 }; 1478 };
1479 1479
1480 auto* view_ptr = blit_view.get(); 1480 auto* view_ptr = blit_view.get();
1481 if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) { 1481 if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) {
1482 if (!blit_framebuffer) { 1482 if (!blit_framebuffer) {
1483 blit_framebuffer = std::make_unique<Framebuffer>(*runtime, view_ptr, nullptr, extent); 1483 blit_framebuffer =
1484 std::make_unique<Framebuffer>(*runtime, view_ptr, nullptr, extent, scale_up);
1484 } 1485 }
1485 const auto color_view = blit_view->Handle(Shader::TextureType::Color2D); 1486 const auto color_view = blit_view->Handle(Shader::TextureType::Color2D);
1486 1487
@@ -1488,7 +1489,8 @@ bool Image::BlitScaleHelper(bool scale_up) {
1488 src_region, operation, BLIT_OPERATION); 1489 src_region, operation, BLIT_OPERATION);
1489 } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { 1490 } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
1490 if (!blit_framebuffer) { 1491 if (!blit_framebuffer) {
1491 blit_framebuffer = std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent); 1492 blit_framebuffer =
1493 std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent, scale_up);
1492 } 1494 }
1493 runtime->blit_image_helper.BlitDepthStencil(blit_framebuffer.get(), blit_view->DepthView(), 1495 runtime->blit_image_helper.BlitDepthStencil(blit_framebuffer.get(), blit_view->DepthView(),
1494 blit_view->StencilView(), dst_region, 1496 blit_view->StencilView(), dst_region,
@@ -1756,34 +1758,42 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1756 .width = key.size.width, 1758 .width = key.size.width,
1757 .height = key.size.height, 1759 .height = key.size.height,
1758 }} { 1760 }} {
1759 CreateFramebuffer(runtime, color_buffers, depth_buffer); 1761 CreateFramebuffer(runtime, color_buffers, depth_buffer, key.is_rescaled);
1760 if (runtime.device.HasDebuggingToolAttached()) { 1762 if (runtime.device.HasDebuggingToolAttached()) {
1761 framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str()); 1763 framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
1762 } 1764 }
1763} 1765}
1764 1766
1765Framebuffer::Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer, 1767Framebuffer::Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer,
1766 ImageView* depth_buffer, VkExtent2D extent) 1768 ImageView* depth_buffer, VkExtent2D extent, bool is_rescaled)
1767 : render_area{extent} { 1769 : render_area{extent} {
1768 std::array<ImageView*, NUM_RT> color_buffers{color_buffer}; 1770 std::array<ImageView*, NUM_RT> color_buffers{color_buffer};
1769 CreateFramebuffer(runtime, color_buffers, depth_buffer); 1771 CreateFramebuffer(runtime, color_buffers, depth_buffer, is_rescaled);
1770} 1772}
1771 1773
1772Framebuffer::~Framebuffer() = default; 1774Framebuffer::~Framebuffer() = default;
1773 1775
1774void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, 1776void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
1775 std::span<ImageView*, NUM_RT> color_buffers, 1777 std::span<ImageView*, NUM_RT> color_buffers,
1776 ImageView* depth_buffer) { 1778 ImageView* depth_buffer, bool is_rescaled) {
1777 std::vector<VkImageView> attachments; 1779 std::vector<VkImageView> attachments;
1778 RenderPassKey renderpass_key{}; 1780 RenderPassKey renderpass_key{};
1779 s32 num_layers = 1; 1781 s32 num_layers = 1;
1780 1782
1783 const auto& resolution = runtime.resolution;
1784
1785 u32 width = 0;
1786 u32 height = 0;
1781 for (size_t index = 0; index < NUM_RT; ++index) { 1787 for (size_t index = 0; index < NUM_RT; ++index) {
1782 const ImageView* const color_buffer = color_buffers[index]; 1788 const ImageView* const color_buffer = color_buffers[index];
1783 if (!color_buffer) { 1789 if (!color_buffer) {
1784 renderpass_key.color_formats[index] = PixelFormat::Invalid; 1790 renderpass_key.color_formats[index] = PixelFormat::Invalid;
1785 continue; 1791 continue;
1786 } 1792 }
1793 width = std::max(width, is_rescaled ? resolution.ScaleUp(color_buffer->size.width)
1794 : color_buffer->size.width);
1795 height = std::max(height, is_rescaled ? resolution.ScaleUp(color_buffer->size.height)
1796 : color_buffer->size.height);
1787 attachments.push_back(color_buffer->RenderTarget()); 1797 attachments.push_back(color_buffer->RenderTarget());
1788 renderpass_key.color_formats[index] = color_buffer->format; 1798 renderpass_key.color_formats[index] = color_buffer->format;
1789 num_layers = std::max(num_layers, color_buffer->range.extent.layers); 1799 num_layers = std::max(num_layers, color_buffer->range.extent.layers);
@@ -1794,6 +1804,10 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
1794 } 1804 }
1795 const size_t num_colors = attachments.size(); 1805 const size_t num_colors = attachments.size();
1796 if (depth_buffer) { 1806 if (depth_buffer) {
1807 width = std::max(width, is_rescaled ? resolution.ScaleUp(depth_buffer->size.width)
1808 : depth_buffer->size.width);
1809 height = std::max(height, is_rescaled ? resolution.ScaleUp(depth_buffer->size.height)
1810 : depth_buffer->size.height);
1797 attachments.push_back(depth_buffer->RenderTarget()); 1811 attachments.push_back(depth_buffer->RenderTarget());
1798 renderpass_key.depth_format = depth_buffer->format; 1812 renderpass_key.depth_format = depth_buffer->format;
1799 num_layers = std::max(num_layers, depth_buffer->range.extent.layers); 1813 num_layers = std::max(num_layers, depth_buffer->range.extent.layers);
@@ -1810,6 +1824,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
1810 renderpass_key.samples = samples; 1824 renderpass_key.samples = samples;
1811 1825
1812 renderpass = runtime.render_pass_cache.Get(renderpass_key); 1826 renderpass = runtime.render_pass_cache.Get(renderpass_key);
1827 render_area.width = std::min(render_area.width, width);
1828 render_area.height = std::min(render_area.height, height);
1813 1829
1814 num_color_buffers = static_cast<u32>(num_colors); 1830 num_color_buffers = static_cast<u32>(num_colors);
1815 framebuffer = runtime.device.GetLogical().CreateFramebuffer({ 1831 framebuffer = runtime.device.GetLogical().CreateFramebuffer({
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 69f06ee7b..0b7ac0df1 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -268,7 +268,7 @@ public:
268 ImageView* depth_buffer, const VideoCommon::RenderTargets& key); 268 ImageView* depth_buffer, const VideoCommon::RenderTargets& key);
269 269
270 explicit Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer, 270 explicit Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer,
271 ImageView* depth_buffer, VkExtent2D extent); 271 ImageView* depth_buffer, VkExtent2D extent, bool is_rescaled);
272 272
273 ~Framebuffer(); 273 ~Framebuffer();
274 274
@@ -279,7 +279,8 @@ public:
279 Framebuffer& operator=(Framebuffer&&) = default; 279 Framebuffer& operator=(Framebuffer&&) = default;
280 280
281 void CreateFramebuffer(TextureCacheRuntime& runtime, 281 void CreateFramebuffer(TextureCacheRuntime& runtime,
282 std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer); 282 std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer,
283 bool is_rescaled = false);
283 284
284 [[nodiscard]] VkFramebuffer Handle() const noexcept { 285 [[nodiscard]] VkFramebuffer Handle() const noexcept {
285 return *framebuffer; 286 return *framebuffer;