summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/scripts/merge/apply-patches-by-label-private.py2
-rw-r--r--.ci/scripts/merge/apply-patches-by-label.py2
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/common/bit_util.h7
-rw-r--r--src/core/hle/service/pm/pm.cpp47
-rw-r--r--src/video_core/gpu.h1
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt6
-rw-r--r--src/video_core/host_shaders/convert_abgr8_to_d24s8.frag17
-rw-r--r--src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag19
-rw-r--r--src/video_core/host_shaders/convert_d24s8_to_abgr8.frag21
-rw-r--r--src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag21
-rw-r--r--src/video_core/host_shaders/convert_d24s8_to_r16g16.frag21
-rw-r--r--src/video_core/host_shaders/convert_r16g16_to_d24s8.frag18
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp103
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h27
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h1
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp171
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h39
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp204
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h10
-rw-r--r--src/video_core/surface.cpp7
-rw-r--r--src/video_core/surface.h14
-rw-r--r--src/video_core/texture_cache/formatter.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h18
-rw-r--r--src/video_core/texture_cache/types.h1
-rw-r--r--src/video_core/texture_cache/util.cpp29
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp10
-rw-r--r--src/yuzu/configuration/configure_graphics.ui2
-rw-r--r--src/yuzu/hotkeys.cpp2
-rw-r--r--src/yuzu/main.cpp16
31 files changed, 765 insertions, 78 deletions
diff --git a/.ci/scripts/merge/apply-patches-by-label-private.py b/.ci/scripts/merge/apply-patches-by-label-private.py
index fe0acd510..16b45043e 100644
--- a/.ci/scripts/merge/apply-patches-by-label-private.py
+++ b/.ci/scripts/merge/apply-patches-by-label-private.py
@@ -25,7 +25,7 @@ def check_individual(repo_id, pr_id):
25 25
26def merge_pr(pn, ref): 26def merge_pr(pn, ref):
27 print("Matched PR# %s" % pn) 27 print("Matched PR# %s" % pn)
28 print(subprocess.check_output(["git", "fetch", "https://%sdev.azure.com/%s/_git/%s" % (user, org, repo), ref, "-f"])) 28 print(subprocess.check_output(["git", "fetch", "https://%sdev.azure.com/%s/_git/%s" % (user, org, repo), ref, "-f", "--no-recurse-submodules"]))
29 print(subprocess.check_output(["git", "merge", "--squash", 'origin/' + ref.replace('refs/heads/','')])) 29 print(subprocess.check_output(["git", "merge", "--squash", 'origin/' + ref.replace('refs/heads/','')]))
30 print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)])) 30 print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)]))
31 31
diff --git a/.ci/scripts/merge/apply-patches-by-label.py b/.ci/scripts/merge/apply-patches-by-label.py
index b2e430ac7..c288a70a1 100644
--- a/.ci/scripts/merge/apply-patches-by-label.py
+++ b/.ci/scripts/merge/apply-patches-by-label.py
@@ -25,7 +25,7 @@ def do_page(page):
25 if (check_individual(pr["labels"])): 25 if (check_individual(pr["labels"])):
26 pn = pr["number"] 26 pn = pr["number"]
27 print("Matched PR# %s" % pn) 27 print("Matched PR# %s" % pn)
28 print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", "pull/%s/head:pr-%s" % (pn, pn), "-f"])) 28 print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", "pull/%s/head:pr-%s" % (pn, pn), "-f", "--no-recurse-submodules"]))
29 print(subprocess.check_output(["git", "merge", "--squash", "pr-%s" % pn])) 29 print(subprocess.check_output(["git", "merge", "--squash", "pr-%s" % pn]))
30 print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)])) 30 print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)]))
31 31
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6044e311a..2c044c1ea 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,7 +57,7 @@ function(check_submodules_present)
57 string(REGEX REPLACE "path *= *" "" module ${module}) 57 string(REGEX REPLACE "path *= *" "" module ${module})
58 if (NOT EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git") 58 if (NOT EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git")
59 message(FATAL_ERROR "Git submodule ${module} not found. " 59 message(FATAL_ERROR "Git submodule ${module} not found. "
60 "Please run: git submodule update --init --recursive") 60 "Please run: \ngit submodule update --init --recursive")
61 endif() 61 endif()
62 endforeach() 62 endforeach()
63endfunction() 63endfunction()
diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index 64520ca4e..eef8c1c5a 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -7,6 +7,7 @@
7#include <bit> 7#include <bit>
8#include <climits> 8#include <climits>
9#include <cstddef> 9#include <cstddef>
10#include <type_traits>
10 11
11#include "common/common_types.h" 12#include "common/common_types.h"
12 13
@@ -44,4 +45,10 @@ template <typename T>
44 return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL)); 45 return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL));
45} 46}
46 47
48template <typename T>
49requires std::is_integral_v<T>
50[[nodiscard]] T NextPow2(T value) {
51 return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
52}
53
47} // namespace Common 54} // namespace Common
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 88fc5b5cc..277abc17a 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -13,7 +13,12 @@ namespace Service::PM {
13 13
14namespace { 14namespace {
15 15
16constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1}; 16constexpr ResultCode ResultProcessNotFound{ErrorModule::PM, 1};
17[[maybe_unused]] constexpr ResultCode ResultAlreadyStarted{ErrorModule::PM, 2};
18[[maybe_unused]] constexpr ResultCode ResultNotTerminated{ErrorModule::PM, 3};
19[[maybe_unused]] constexpr ResultCode ResultDebugHookInUse{ErrorModule::PM, 4};
20[[maybe_unused]] constexpr ResultCode ResultApplicationRunning{ErrorModule::PM, 5};
21[[maybe_unused]] constexpr ResultCode ResultInvalidSize{ErrorModule::PM, 6};
17 22
18constexpr u64 NO_PROCESS_FOUND_PID{0}; 23constexpr u64 NO_PROCESS_FOUND_PID{0};
19 24
@@ -95,18 +100,18 @@ public:
95private: 100private:
96 void GetProcessId(Kernel::HLERequestContext& ctx) { 101 void GetProcessId(Kernel::HLERequestContext& ctx) {
97 IPC::RequestParser rp{ctx}; 102 IPC::RequestParser rp{ctx};
98 const auto title_id = rp.PopRaw<u64>(); 103 const auto program_id = rp.PopRaw<u64>();
99 104
100 LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id); 105 LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
101 106
102 const auto process = 107 const auto process =
103 SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) { 108 SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) {
104 return proc->GetProgramID() == title_id; 109 return proc->GetProgramID() == program_id;
105 }); 110 });
106 111
107 if (!process.has_value()) { 112 if (!process.has_value()) {
108 IPC::ResponseBuilder rb{ctx, 2}; 113 IPC::ResponseBuilder rb{ctx, 2};
109 rb.Push(ERROR_PROCESS_NOT_FOUND); 114 rb.Push(ResultProcessNotFound);
110 return; 115 return;
111 } 116 }
112 117
@@ -128,13 +133,16 @@ public:
128 explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) 133 explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_)
129 : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { 134 : ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
130 static const FunctionInfo functions[] = { 135 static const FunctionInfo functions[] = {
131 {0, &Info::GetTitleId, "GetTitleId"}, 136 {0, &Info::GetProgramId, "GetProgramId"},
137 {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"},
138 {65001, nullptr, "AtmosphereHasLaunchedProgram"},
139 {65002, nullptr, "AtmosphereGetProcessInfo"},
132 }; 140 };
133 RegisterHandlers(functions); 141 RegisterHandlers(functions);
134 } 142 }
135 143
136private: 144private:
137 void GetTitleId(Kernel::HLERequestContext& ctx) { 145 void GetProgramId(Kernel::HLERequestContext& ctx) {
138 IPC::RequestParser rp{ctx}; 146 IPC::RequestParser rp{ctx};
139 const auto process_id = rp.PopRaw<u64>(); 147 const auto process_id = rp.PopRaw<u64>();
140 148
@@ -146,7 +154,7 @@ private:
146 154
147 if (!process.has_value()) { 155 if (!process.has_value()) {
148 IPC::ResponseBuilder rb{ctx, 2}; 156 IPC::ResponseBuilder rb{ctx, 2};
149 rb.Push(ERROR_PROCESS_NOT_FOUND); 157 rb.Push(ResultProcessNotFound);
150 return; 158 return;
151 } 159 }
152 160
@@ -155,6 +163,27 @@ private:
155 rb.Push((*process)->GetProgramID()); 163 rb.Push((*process)->GetProgramID());
156 } 164 }
157 165
166 void AtmosphereGetProcessId(Kernel::HLERequestContext& ctx) {
167 IPC::RequestParser rp{ctx};
168 const auto program_id = rp.PopRaw<u64>();
169
170 LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
171
172 const auto process = SearchProcessList(process_list, [program_id](const auto& proc) {
173 return proc->GetProgramID() == program_id;
174 });
175
176 if (!process.has_value()) {
177 IPC::ResponseBuilder rb{ctx, 2};
178 rb.Push(ResultProcessNotFound);
179 return;
180 }
181
182 IPC::ResponseBuilder rb{ctx, 4};
183 rb.Push(ResultSuccess);
184 rb.Push((*process)->GetProcessID());
185 }
186
158 const std::vector<Kernel::KProcess*>& process_list; 187 const std::vector<Kernel::KProcess*>& process_list;
159}; 188};
160 189
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 05e5c94f3..c89a5d693 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -83,6 +83,7 @@ enum class DepthFormat : u32 {
83 S8_UINT_Z24_UNORM = 0x14, 83 S8_UINT_Z24_UNORM = 0x14,
84 D24X8_UNORM = 0x15, 84 D24X8_UNORM = 0x15,
85 D24S8_UNORM = 0x16, 85 D24S8_UNORM = 0x16,
86 S8_UINT = 0x17,
86 D24C8_UNORM = 0x18, 87 D24C8_UNORM = 0x18,
87 D32_FLOAT_S8X24_UINT = 0x19, 88 D32_FLOAT_S8X24_UINT = 0x19,
88}; 89};
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index d779a967a..1c91999d7 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -10,8 +10,14 @@ set(SHADER_FILES
10 astc_decoder.comp 10 astc_decoder.comp
11 block_linear_unswizzle_2d.comp 11 block_linear_unswizzle_2d.comp
12 block_linear_unswizzle_3d.comp 12 block_linear_unswizzle_3d.comp
13 convert_abgr8_to_d24s8.frag
14 convert_b10g11r11_to_d24s8.frag
15 convert_d24s8_to_abgr8.frag
16 convert_d24s8_to_b10g11r11.frag
17 convert_d24s8_to_r16g16.frag
13 convert_depth_to_float.frag 18 convert_depth_to_float.frag
14 convert_float_to_depth.frag 19 convert_float_to_depth.frag
20 convert_r16g16_to_d24s8.frag
15 full_screen_triangle.vert 21 full_screen_triangle.vert
16 fxaa.frag 22 fxaa.frag
17 fxaa.vert 23 fxaa.vert
diff --git a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag
new file mode 100644
index 000000000..4e4ab6a26
--- /dev/null
+++ b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag
@@ -0,0 +1,17 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 450
6#extension GL_ARB_shader_stencil_export : require
7
8layout(binding = 0) uniform sampler2D color_texture;
9
10void main() {
11 ivec2 coord = ivec2(gl_FragCoord.xy);
12 uvec4 color = uvec4(texelFetch(color_texture, coord, 0).rgba * (exp2(8) - 1.0f));
13 uint depth_unorm = (color.r << 16) | (color.g << 8) | color.b;
14
15 gl_FragDepth = float(depth_unorm) / (exp2(24.0) - 1.0f);
16 gl_FragStencilRefARB = int(color.a);
17}
diff --git a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
new file mode 100644
index 000000000..2999a84cf
--- /dev/null
+++ b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
@@ -0,0 +1,19 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 450
6#extension GL_ARB_shader_stencil_export : require
7
8layout(binding = 0) uniform sampler2D color_texture;
9
10void main() {
11 ivec2 coord = ivec2(gl_FragCoord.xy);
12 vec4 color = texelFetch(color_texture, coord, 0).rgba;
13 uint depth_stencil_unorm = (uint(color.b * (exp2(10) - 1.0f)) << 22)
14 | (uint(color.g * (exp2(11) - 1.0f)) << 11)
15 | (uint(color.r * (exp2(11) - 1.0f)));
16
17 gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
18 gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
19}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag
new file mode 100644
index 000000000..ff3bf8209
--- /dev/null
+++ b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag
@@ -0,0 +1,21 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 450
6
7layout(binding = 0) uniform sampler2D depth_tex;
8layout(binding = 1) uniform isampler2D stencil_tex;
9
10layout(location = 0) out vec4 color;
11
12void main() {
13 ivec2 coord = ivec2(gl_FragCoord.xy);
14 uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
15 uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
16
17 color.r = float(depth >> 16) / (exp2(8) - 1.0);
18 color.g = float((depth >> 8) & 0x00FF) / (exp2(8) - 1.0);
19 color.b = float(depth & 0x00FF) / (exp2(8) - 1.0);
20 color.a = float(stencil) / (exp2(8) - 1.0);
21}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
new file mode 100644
index 000000000..c743d3a13
--- /dev/null
+++ b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
@@ -0,0 +1,21 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 450
6
7layout(binding = 0) uniform sampler2D depth_tex;
8layout(binding = 1) uniform isampler2D stencil_tex;
9
10layout(location = 0) out vec4 color;
11
12void main() {
13 ivec2 coord = ivec2(gl_FragCoord.xy);
14 uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
15 uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
16
17 color.b = float(depth >> 22) / (exp2(10) - 1.0);
18 color.g = float((depth >> 11) & 0x00FF) / (exp2(11) - 1.0);
19 color.r = float(depth & 0x00FF) / (exp2(11) - 1.0);
20 color.a = 1.0f;
21}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
new file mode 100644
index 000000000..2a9443d3d
--- /dev/null
+++ b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
@@ -0,0 +1,21 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 450
6
7layout(binding = 0) uniform sampler2D depth_tex;
8layout(binding = 1) uniform isampler2D stencil_tex;
9
10layout(location = 0) out vec4 color;
11
12void main() {
13 ivec2 coord = ivec2(gl_FragCoord.xy);
14 uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
15 uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
16
17 color.r = float(depth >> 16) / (exp2(16) - 1.0);
18 color.g = float((depth >> 16) & 0x00FF) / (exp2(16) - 1.0);
19 color.b = 0.0f;
20 color.a = 1.0f;
21}
diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
new file mode 100644
index 000000000..3df70575e
--- /dev/null
+++ b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
@@ -0,0 +1,18 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 450
6#extension GL_ARB_shader_stencil_export : require
7
8layout(binding = 0) uniform sampler2D color_texture;
9
10void main() {
11 ivec2 coord = ivec2(gl_FragCoord.xy);
12 vec4 color = texelFetch(color_texture, coord, 0).rgba;
13 uint depth_stencil_unorm = (uint(color.r * (exp2(16) - 1.0f)) << 16)
14 | (uint(color.g * (exp2(16) - 1.0f)) << 16);
15
16 gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
17 gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
18}
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 2f7d98d8b..14e6522f2 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -9,6 +9,7 @@
9 9
10#include <glad/glad.h> 10#include <glad/glad.h>
11 11
12#include "common/bit_util.h"
12#include "common/literals.h" 13#include "common/literals.h"
13#include "common/settings.h" 14#include "common/settings.h"
14#include "video_core/renderer_opengl/gl_device.h" 15#include "video_core/renderer_opengl/gl_device.h"
@@ -148,6 +149,8 @@ GLenum AttachmentType(PixelFormat format) {
148 switch (const SurfaceType type = VideoCore::Surface::GetFormatType(format); type) { 149 switch (const SurfaceType type = VideoCore::Surface::GetFormatType(format); type) {
149 case SurfaceType::Depth: 150 case SurfaceType::Depth:
150 return GL_DEPTH_ATTACHMENT; 151 return GL_DEPTH_ATTACHMENT;
152 case SurfaceType::Stencil:
153 return GL_STENCIL_ATTACHMENT;
151 case SurfaceType::DepthStencil: 154 case SurfaceType::DepthStencil:
152 return GL_DEPTH_STENCIL_ATTACHMENT; 155 return GL_DEPTH_STENCIL_ATTACHMENT;
153 default: 156 default:
@@ -317,13 +320,12 @@ void AttachTexture(GLuint fbo, GLenum attachment, const ImageView* image_view) {
317 } 320 }
318} 321}
319 322
320OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_format) { 323OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_format,
324 GLsizei gl_num_levels) {
321 const GLenum target = ImageTarget(info); 325 const GLenum target = ImageTarget(info);
322 const GLsizei width = info.size.width; 326 const GLsizei width = info.size.width;
323 const GLsizei height = info.size.height; 327 const GLsizei height = info.size.height;
324 const GLsizei depth = info.size.depth; 328 const GLsizei depth = info.size.depth;
325 const int max_host_mip_levels = std::bit_width(info.size.width);
326 const GLsizei num_levels = std::min(info.resources.levels, max_host_mip_levels);
327 const GLsizei num_layers = info.resources.layers; 329 const GLsizei num_layers = info.resources.layers;
328 const GLsizei num_samples = info.num_samples; 330 const GLsizei num_samples = info.num_samples;
329 331
@@ -335,10 +337,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
335 } 337 }
336 switch (target) { 338 switch (target) {
337 case GL_TEXTURE_1D_ARRAY: 339 case GL_TEXTURE_1D_ARRAY:
338 glTextureStorage2D(handle, num_levels, gl_internal_format, width, num_layers); 340 glTextureStorage2D(handle, gl_num_levels, gl_internal_format, width, num_layers);
339 break; 341 break;
340 case GL_TEXTURE_2D_ARRAY: 342 case GL_TEXTURE_2D_ARRAY:
341 glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, num_layers); 343 glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, num_layers);
342 break; 344 break;
343 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: { 345 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: {
344 // TODO: Where should 'fixedsamplelocations' come from? 346 // TODO: Where should 'fixedsamplelocations' come from?
@@ -348,10 +350,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
348 break; 350 break;
349 } 351 }
350 case GL_TEXTURE_RECTANGLE: 352 case GL_TEXTURE_RECTANGLE:
351 glTextureStorage2D(handle, num_levels, gl_internal_format, width, height); 353 glTextureStorage2D(handle, gl_num_levels, gl_internal_format, width, height);
352 break; 354 break;
353 case GL_TEXTURE_3D: 355 case GL_TEXTURE_3D:
354 glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, depth); 356 glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, depth);
355 break; 357 break;
356 case GL_TEXTURE_BUFFER: 358 case GL_TEXTURE_BUFFER:
357 UNREACHABLE(); 359 UNREACHABLE();
@@ -396,6 +398,7 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
396 UNREACHABLE_MSG("Invalid image format={}", format); 398 UNREACHABLE_MSG("Invalid image format={}", format);
397 return GL_R32UI; 399 return GL_R32UI;
398} 400}
401
399} // Anonymous namespace 402} // Anonymous namespace
400 403
401ImageBufferMap::~ImageBufferMap() { 404ImageBufferMap::~ImageBufferMap() {
@@ -522,6 +525,12 @@ void TextureCacheRuntime::CopyImage(Image& dst_image, Image& src_image,
522 } 525 }
523} 526}
524 527
528void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
529 std::span<const VideoCommon::ImageCopy> copies) {
530 LOG_DEBUG(Render_OpenGL, "Converting {} to {}", src.info.format, dst.info.format);
531 format_conversion_pass.ConvertImage(dst, src, copies);
532}
533
525bool TextureCacheRuntime::CanImageBeCopied(const Image& dst, const Image& src) { 534bool TextureCacheRuntime::CanImageBeCopied(const Image& dst, const Image& src) {
526 if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) { 535 if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) {
527 return false; 536 return false;
@@ -538,7 +547,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src,
538 ASSERT(src.info.type == ImageType::e3D); 547 ASSERT(src.info.type == ImageType::e3D);
539 util_shaders.CopyBC4(dst, src, copies); 548 util_shaders.CopyBC4(dst, src, copies);
540 } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { 549 } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) {
541 bgr_copy_pass.CopyBGR(dst, src, copies); 550 format_conversion_pass.ConvertImage(dst, src, copies);
542 } else { 551 } else {
543 UNREACHABLE(); 552 UNREACHABLE();
544 } 553 }
@@ -686,7 +695,9 @@ Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_,
686 gl_format = tuple.format; 695 gl_format = tuple.format;
687 gl_type = tuple.type; 696 gl_type = tuple.type;
688 } 697 }
689 texture = MakeImage(info, gl_internal_format); 698 const int max_host_mip_levels = std::bit_width(info.size.width);
699 gl_num_levels = std::min(info.resources.levels, max_host_mip_levels);
700 texture = MakeImage(info, gl_internal_format, gl_num_levels);
690 current_texture = texture.handle; 701 current_texture = texture.handle;
691 if (runtime->device.HasDebuggingToolAttached()) { 702 if (runtime->device.HasDebuggingToolAttached()) {
692 const std::string name = VideoCommon::Name(*this); 703 const std::string name = VideoCommon::Name(*this);
@@ -714,6 +725,9 @@ void Image::UploadMemory(const ImageBufferMap& map,
714 u32 current_image_height = std::numeric_limits<u32>::max(); 725 u32 current_image_height = std::numeric_limits<u32>::max();
715 726
716 for (const VideoCommon::BufferImageCopy& copy : copies) { 727 for (const VideoCommon::BufferImageCopy& copy : copies) {
728 if (copy.image_subresource.base_level >= gl_num_levels) {
729 continue;
730 }
717 if (current_row_length != copy.buffer_row_length) { 731 if (current_row_length != copy.buffer_row_length) {
718 current_row_length = copy.buffer_row_length; 732 current_row_length = copy.buffer_row_length;
719 glPixelStorei(GL_UNPACK_ROW_LENGTH, current_row_length); 733 glPixelStorei(GL_UNPACK_ROW_LENGTH, current_row_length);
@@ -743,6 +757,9 @@ void Image::DownloadMemory(ImageBufferMap& map,
743 u32 current_image_height = std::numeric_limits<u32>::max(); 757 u32 current_image_height = std::numeric_limits<u32>::max();
744 758
745 for (const VideoCommon::BufferImageCopy& copy : copies) { 759 for (const VideoCommon::BufferImageCopy& copy : copies) {
760 if (copy.image_subresource.base_level >= gl_num_levels) {
761 continue;
762 }
746 if (current_row_length != copy.buffer_row_length) { 763 if (current_row_length != copy.buffer_row_length) {
747 current_row_length = copy.buffer_row_length; 764 current_row_length = copy.buffer_row_length;
748 glPixelStorei(GL_PACK_ROW_LENGTH, current_row_length); 765 glPixelStorei(GL_PACK_ROW_LENGTH, current_row_length);
@@ -782,7 +799,7 @@ GLuint Image::StorageHandle() noexcept {
782 } 799 }
783 store_view.Create(); 800 store_view.Create();
784 glTextureView(store_view.handle, ImageTarget(info), current_texture, GL_RGBA8, 0, 801 glTextureView(store_view.handle, ImageTarget(info), current_texture, GL_RGBA8, 0,
785 info.resources.levels, 0, info.resources.layers); 802 gl_num_levels, 0, info.resources.layers);
786 return store_view.handle; 803 return store_view.handle;
787 default: 804 default:
788 return current_texture; 805 return current_texture;
@@ -897,6 +914,8 @@ void Image::Scale(bool up_scale) {
897 return GL_COLOR_ATTACHMENT0; 914 return GL_COLOR_ATTACHMENT0;
898 case SurfaceType::Depth: 915 case SurfaceType::Depth:
899 return GL_DEPTH_ATTACHMENT; 916 return GL_DEPTH_ATTACHMENT;
917 case SurfaceType::Stencil:
918 return GL_STENCIL_ATTACHMENT;
900 case SurfaceType::DepthStencil: 919 case SurfaceType::DepthStencil:
901 return GL_DEPTH_STENCIL_ATTACHMENT; 920 return GL_DEPTH_STENCIL_ATTACHMENT;
902 default: 921 default:
@@ -910,8 +929,10 @@ void Image::Scale(bool up_scale) {
910 return GL_COLOR_BUFFER_BIT; 929 return GL_COLOR_BUFFER_BIT;
911 case SurfaceType::Depth: 930 case SurfaceType::Depth:
912 return GL_DEPTH_BUFFER_BIT; 931 return GL_DEPTH_BUFFER_BIT;
932 case SurfaceType::Stencil:
933 return GL_STENCIL_BUFFER_BIT;
913 case SurfaceType::DepthStencil: 934 case SurfaceType::DepthStencil:
914 return GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; 935 return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
915 default: 936 default:
916 UNREACHABLE(); 937 UNREACHABLE();
917 return GL_COLOR_BUFFER_BIT; 938 return GL_COLOR_BUFFER_BIT;
@@ -923,8 +944,10 @@ void Image::Scale(bool up_scale) {
923 return 0; 944 return 0;
924 case SurfaceType::Depth: 945 case SurfaceType::Depth:
925 return 1; 946 return 1;
926 case SurfaceType::DepthStencil: 947 case SurfaceType::Stencil:
927 return 2; 948 return 2;
949 case SurfaceType::DepthStencil:
950 return 3;
928 default: 951 default:
929 UNREACHABLE(); 952 UNREACHABLE();
930 return 0; 953 return 0;
@@ -946,7 +969,7 @@ void Image::Scale(bool up_scale) {
946 auto dst_info = info; 969 auto dst_info = info;
947 dst_info.size.width = scaled_width; 970 dst_info.size.width = scaled_width;
948 dst_info.size.height = scaled_height; 971 dst_info.size.height = scaled_height;
949 upscaled_backup = MakeImage(dst_info, gl_internal_format); 972 upscaled_backup = MakeImage(dst_info, gl_internal_format, gl_num_levels);
950 } 973 }
951 const u32 src_width = up_scale ? original_width : scaled_width; 974 const u32 src_width = up_scale ? original_width : scaled_width;
952 const u32 src_height = up_scale ? original_height : scaled_height; 975 const u32 src_height = up_scale ? original_height : scaled_height;
@@ -1254,10 +1277,20 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1254 } 1277 }
1255 1278
1256 if (const ImageView* const image_view = depth_buffer; image_view) { 1279 if (const ImageView* const image_view = depth_buffer; image_view) {
1257 if (GetFormatType(image_view->format) == SurfaceType::DepthStencil) { 1280 switch (GetFormatType(image_view->format)) {
1281 case SurfaceType::Depth:
1282 buffer_bits |= GL_DEPTH_BUFFER_BIT;
1283 break;
1284 case SurfaceType::Stencil:
1285 buffer_bits |= GL_STENCIL_BUFFER_BIT;
1286 break;
1287 case SurfaceType::DepthStencil:
1258 buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; 1288 buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
1259 } else { 1289 break;
1290 default:
1291 UNREACHABLE();
1260 buffer_bits |= GL_DEPTH_BUFFER_BIT; 1292 buffer_bits |= GL_DEPTH_BUFFER_BIT;
1293 break;
1261 } 1294 }
1262 const GLenum attachment = AttachmentType(image_view->format); 1295 const GLenum attachment = AttachmentType(image_view->format);
1263 AttachTexture(handle, attachment, image_view); 1296 AttachTexture(handle, attachment, image_view);
@@ -1286,35 +1319,37 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1286 1319
1287Framebuffer::~Framebuffer() = default; 1320Framebuffer::~Framebuffer() = default;
1288 1321
1289void BGRCopyPass::CopyBGR(Image& dst_image, Image& src_image, 1322void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,
1290 std::span<const VideoCommon::ImageCopy> copies) { 1323 std::span<const VideoCommon::ImageCopy> copies) {
1291 static constexpr VideoCommon::Offset3D zero_offset{0, 0, 0}; 1324 const GLenum dst_target = ImageTarget(dst_image.info);
1325 const GLenum src_target = ImageTarget(src_image.info);
1292 const u32 img_bpp = BytesPerBlock(src_image.info.format); 1326 const u32 img_bpp = BytesPerBlock(src_image.info.format);
1293 for (const ImageCopy& copy : copies) { 1327 for (const ImageCopy& copy : copies) {
1294 ASSERT(copy.src_offset == zero_offset); 1328 const auto src_origin = MakeCopyOrigin(copy.src_offset, copy.src_subresource, src_target);
1295 ASSERT(copy.dst_offset == zero_offset); 1329 const auto dst_origin = MakeCopyOrigin(copy.dst_offset, copy.dst_subresource, dst_target);
1296 const u32 num_src_layers = static_cast<u32>(copy.src_subresource.num_layers); 1330 const auto region = MakeCopyRegion(copy.extent, copy.dst_subresource, dst_target);
1297 const u32 copy_size = copy.extent.width * copy.extent.height * num_src_layers * img_bpp; 1331 const u32 copy_size = region.width * region.height * region.depth * img_bpp;
1298 if (bgr_pbo_size < copy_size) { 1332 if (pbo_size < copy_size) {
1299 bgr_pbo.Create(); 1333 intermediate_pbo.Create();
1300 bgr_pbo_size = copy_size; 1334 pbo_size = Common::NextPow2(copy_size);
1301 glNamedBufferData(bgr_pbo.handle, bgr_pbo_size, nullptr, GL_STREAM_COPY); 1335 glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY);
1302 } 1336 }
1303 // Copy from source to PBO 1337 // Copy from source to PBO
1304 glPixelStorei(GL_PACK_ALIGNMENT, 1); 1338 glPixelStorei(GL_PACK_ALIGNMENT, 1);
1305 glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width); 1339 glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width);
1306 glBindBuffer(GL_PIXEL_PACK_BUFFER, bgr_pbo.handle); 1340 glBindBuffer(GL_PIXEL_PACK_BUFFER, intermediate_pbo.handle);
1307 glGetTextureSubImage(src_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height, 1341 glGetTextureSubImage(src_image.Handle(), src_origin.level, src_origin.x, src_origin.y,
1308 num_src_layers, src_image.GlFormat(), src_image.GlType(), 1342 src_origin.z, region.width, region.height, region.depth,
1309 static_cast<GLsizei>(bgr_pbo_size), nullptr); 1343 src_image.GlFormat(), src_image.GlType(),
1344 static_cast<GLsizei>(pbo_size), nullptr);
1310 1345
1311 // Copy from PBO to destination in desired GL format 1346 // Copy from PBO to destination in desired GL format
1312 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 1347 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1313 glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width); 1348 glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width);
1314 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bgr_pbo.handle); 1349 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, intermediate_pbo.handle);
1315 glTextureSubImage3D(dst_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height, 1350 glTextureSubImage3D(dst_image.Handle(), dst_origin.level, dst_origin.x, dst_origin.y,
1316 copy.dst_subresource.num_layers, dst_image.GlFormat(), 1351 dst_origin.z, region.width, region.height, region.depth,
1317 dst_image.GlType(), nullptr); 1352 dst_image.GlFormat(), dst_image.GlType(), nullptr);
1318 } 1353 }
1319} 1354}
1320 1355
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 1bb762568..37d5e6a6b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -52,17 +52,17 @@ struct FormatProperties {
52 bool is_compressed; 52 bool is_compressed;
53}; 53};
54 54
55class BGRCopyPass { 55class FormatConversionPass {
56public: 56public:
57 BGRCopyPass() = default; 57 FormatConversionPass() = default;
58 ~BGRCopyPass() = default; 58 ~FormatConversionPass() = default;
59 59
60 void CopyBGR(Image& dst_image, Image& src_image, 60 void ConvertImage(Image& dst_image, Image& src_image,
61 std::span<const VideoCommon::ImageCopy> copies); 61 std::span<const VideoCommon::ImageCopy> copies);
62 62
63private: 63private:
64 OGLBuffer bgr_pbo; 64 OGLBuffer intermediate_pbo;
65 size_t bgr_pbo_size{}; 65 size_t pbo_size{};
66}; 66};
67 67
68class TextureCacheRuntime { 68class TextureCacheRuntime {
@@ -84,8 +84,14 @@ public:
84 84
85 u64 GetDeviceLocalMemory() const; 85 u64 GetDeviceLocalMemory() const;
86 86
87 bool ShouldReinterpret([[maybe_unused]] Image& dst, [[maybe_unused]] Image& src) {
88 return true;
89 }
90
87 void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); 91 void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
88 92
93 void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
94
89 void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) { 95 void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) {
90 UNIMPLEMENTED(); 96 UNIMPLEMENTED();
91 } 97 }
@@ -144,7 +150,7 @@ private:
144 const Device& device; 150 const Device& device;
145 StateTracker& state_tracker; 151 StateTracker& state_tracker;
146 UtilShaders util_shaders; 152 UtilShaders util_shaders;
147 BGRCopyPass bgr_copy_pass; 153 FormatConversionPass format_conversion_pass;
148 154
149 std::array<std::unordered_map<GLenum, FormatProperties>, 3> format_properties; 155 std::array<std::unordered_map<GLenum, FormatProperties>, 3> format_properties;
150 bool has_broken_texture_view_formats = false; 156 bool has_broken_texture_view_formats = false;
@@ -162,8 +168,8 @@ private:
162 168
163 std::array<GLuint, Shader::NUM_TEXTURE_TYPES> null_image_views{}; 169 std::array<GLuint, Shader::NUM_TEXTURE_TYPES> null_image_views{};
164 170
165 std::array<OGLFramebuffer, 3> rescale_draw_fbos; 171 std::array<OGLFramebuffer, 4> rescale_draw_fbos;
166 std::array<OGLFramebuffer, 3> rescale_read_fbos; 172 std::array<OGLFramebuffer, 4> rescale_read_fbos;
167 const Settings::ResolutionScalingInfo& resolution; 173 const Settings::ResolutionScalingInfo& resolution;
168}; 174};
169 175
@@ -219,6 +225,7 @@ private:
219 GLenum gl_internal_format = GL_NONE; 225 GLenum gl_internal_format = GL_NONE;
220 GLenum gl_format = GL_NONE; 226 GLenum gl_format = GL_NONE;
221 GLenum gl_type = GL_NONE; 227 GLenum gl_type = GL_NONE;
228 GLsizei gl_num_levels{};
222 TextureCacheRuntime* runtime{}; 229 TextureCacheRuntime* runtime{};
223 GLuint current_texture{}; 230 GLuint current_texture{};
224}; 231};
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 39158aa3e..daba42ed9 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -108,6 +108,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
108 {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT 108 {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT
109 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT 109 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT
110 {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM 110 {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM
111 {GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE}, // S8_UINT
111 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT 112 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT
112 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM 113 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM
113 {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, 114 {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL,
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index b3884a4f5..28b631f73 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -4,8 +4,14 @@
4 4
5#include <algorithm> 5#include <algorithm>
6 6
7#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
8#include "video_core/host_shaders/convert_b10g11r11_to_d24s8_frag_spv.h"
9#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
10#include "video_core/host_shaders/convert_d24s8_to_b10g11r11_frag_spv.h"
11#include "video_core/host_shaders/convert_d24s8_to_r16g16_frag_spv.h"
7#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" 12#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
8#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" 13#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
14#include "video_core/host_shaders/convert_r16g16_to_d24s8_frag_spv.h"
9#include "video_core/host_shaders/full_screen_triangle_vert_spv.h" 15#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
10#include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h" 16#include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h"
11#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" 17#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
@@ -354,6 +360,12 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
354 blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), 360 blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)),
355 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), 361 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
356 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), 362 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
363 convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
364 convert_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)),
365 convert_r16g16_to_d24s8_frag(BuildShader(device, CONVERT_R16G16_TO_D24S8_FRAG_SPV)),
366 convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
367 convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)),
368 convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)),
357 linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)), 369 linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
358 nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) { 370 nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {
359 if (device.IsExtShaderStencilExportSupported()) { 371 if (device.IsExtShaderStencilExportSupported()) {
@@ -448,6 +460,59 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
448 Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); 460 Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
449} 461}
450 462
463void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
464 const ImageView& src_image_view, u32 up_scale,
465 u32 down_shift) {
466 ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
467 convert_abgr8_to_d24s8_frag, true);
468 Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
469 down_shift);
470}
471
472void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
473 const ImageView& src_image_view, u32 up_scale,
474 u32 down_shift) {
475 ConvertPipelineDepthTargetEx(convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
476 convert_b10g11r11_to_d24s8_frag, true);
477 Convert(*convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
478 down_shift);
479}
480
481void BlitImageHelper::ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer,
482 const ImageView& src_image_view, u32 up_scale,
483 u32 down_shift) {
484 ConvertPipelineDepthTargetEx(convert_r16g16_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
485 convert_r16g16_to_d24s8_frag, true);
486 Convert(*convert_r16g16_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
487 down_shift);
488}
489
490void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
491 ImageView& src_image_view, u32 up_scale, u32 down_shift) {
492 ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
493 convert_d24s8_to_abgr8_frag, false);
494 ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view, up_scale,
495 down_shift);
496}
497
498void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer,
499 ImageView& src_image_view, u32 up_scale,
500 u32 down_shift) {
501 ConvertPipelineColorTargetEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(),
502 convert_d24s8_to_b10g11r11_frag, false);
503 ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view,
504 up_scale, down_shift);
505}
506
507void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer,
508 ImageView& src_image_view, u32 up_scale,
509 u32 down_shift) {
510 ConvertPipelineColorTargetEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(),
511 convert_d24s8_to_r16g16_frag, false);
512 ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view,
513 up_scale, down_shift);
514}
515
451void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, 516void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
452 const ImageView& src_image_view, u32 up_scale, u32 down_shift) { 517 const ImageView& src_image_view, u32 up_scale, u32 down_shift) {
453 const VkPipelineLayout layout = *one_texture_pipeline_layout; 518 const VkPipelineLayout layout = *one_texture_pipeline_layout;
@@ -495,6 +560,54 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb
495 scheduler.InvalidateState(); 560 scheduler.InvalidateState();
496} 561}
497 562
563void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
564 ImageView& src_image_view, u32 up_scale, u32 down_shift) {
565 const VkPipelineLayout layout = *two_textures_pipeline_layout;
566 const VkImageView src_depth_view = src_image_view.DepthView();
567 const VkImageView src_stencil_view = src_image_view.StencilView();
568 const VkSampler sampler = *nearest_sampler;
569 const VkExtent2D extent{
570 .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U),
571 .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U),
572 };
573 scheduler.RequestRenderpass(dst_framebuffer);
574 scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, up_scale,
575 down_shift, this](vk::CommandBuffer cmdbuf) {
576 const VkOffset2D offset{
577 .x = 0,
578 .y = 0,
579 };
580 const VkViewport viewport{
581 .x = 0.0f,
582 .y = 0.0f,
583 .width = static_cast<float>(extent.width),
584 .height = static_cast<float>(extent.height),
585 .minDepth = 0.0f,
586 .maxDepth = 0.0f,
587 };
588 const VkRect2D scissor{
589 .offset = offset,
590 .extent = extent,
591 };
592 const PushConstants push_constants{
593 .tex_scale = {viewport.width, viewport.height},
594 .tex_offset = {0.0f, 0.0f},
595 };
596 const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
597 UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
598 src_stencil_view);
599 // TODO: Barriers
600 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
601 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
602 nullptr);
603 cmdbuf.SetViewport(0, viewport);
604 cmdbuf.SetScissor(0, scissor);
605 cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
606 cmdbuf.Draw(3, 1, 0, 0);
607 });
608 scheduler.InvalidateState();
609}
610
498VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) { 611VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) {
499 const auto it = std::ranges::find(blit_color_keys, key); 612 const auto it = std::ranges::find(blit_color_keys, key);
500 if (it != blit_color_keys.end()) { 613 if (it != blit_color_keys.end()) {
@@ -636,4 +749,62 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
636 }); 749 });
637} 750}
638 751
752void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
753 vk::ShaderModule& module, bool single_texture) {
754 if (pipeline) {
755 return;
756 }
757 const std::array stages = MakeStages(*full_screen_vert, *module);
758 pipeline = device.GetLogical().CreateGraphicsPipeline({
759 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
760 .pNext = nullptr,
761 .flags = 0,
762 .stageCount = static_cast<u32>(stages.size()),
763 .pStages = stages.data(),
764 .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
765 .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
766 .pTessellationState = nullptr,
767 .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
768 .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
769 .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
770 .pDepthStencilState = nullptr,
771 .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
772 .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
773 .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
774 .renderPass = renderpass,
775 .subpass = 0,
776 .basePipelineHandle = VK_NULL_HANDLE,
777 .basePipelineIndex = 0,
778 });
779}
780
781void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
782 vk::ShaderModule& module, bool single_texture) {
783 if (pipeline) {
784 return;
785 }
786 const std::array stages = MakeStages(*full_screen_vert, *module);
787 pipeline = device.GetLogical().CreateGraphicsPipeline({
788 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
789 .pNext = nullptr,
790 .flags = 0,
791 .stageCount = static_cast<u32>(stages.size()),
792 .pStages = stages.data(),
793 .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
794 .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
795 .pTessellationState = nullptr,
796 .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
797 .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
798 .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
799 .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
800 .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
801 .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
802 .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
803 .renderPass = renderpass,
804 .subpass = 0,
805 .basePipelineHandle = VK_NULL_HANDLE,
806 .basePipelineIndex = 0,
807 });
808}
809
639} // namespace Vulkan 810} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index d77f76678..cec095341 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -56,10 +56,31 @@ public:
56 void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, 56 void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
57 u32 up_scale, u32 down_shift); 57 u32 up_scale, u32 down_shift);
58 58
59 void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
60 u32 up_scale, u32 down_shift);
61
62 void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
63 const ImageView& src_image_view, u32 up_scale, u32 down_shift);
64
65 void ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
66 u32 up_scale, u32 down_shift);
67
68 void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
69 u32 up_scale, u32 down_shift);
70
71 void ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
72 u32 up_scale, u32 down_shift);
73
74 void ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
75 u32 up_scale, u32 down_shift);
76
59private: 77private:
60 void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, 78 void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
61 const ImageView& src_image_view, u32 up_scale, u32 down_shift); 79 const ImageView& src_image_view, u32 up_scale, u32 down_shift);
62 80
81 void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
82 ImageView& src_image_view, u32 up_scale, u32 down_shift);
83
63 [[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key); 84 [[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key);
64 85
65 [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); 86 [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
@@ -68,6 +89,12 @@ private:
68 89
69 void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); 90 void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
70 91
92 void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
93 vk::ShaderModule& module, bool single_texture);
94
95 void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
96 vk::ShaderModule& module, bool single_texture);
97
71 const Device& device; 98 const Device& device;
72 VKScheduler& scheduler; 99 VKScheduler& scheduler;
73 StateTracker& state_tracker; 100 StateTracker& state_tracker;
@@ -83,6 +110,12 @@ private:
83 vk::ShaderModule blit_depth_stencil_frag; 110 vk::ShaderModule blit_depth_stencil_frag;
84 vk::ShaderModule convert_depth_to_float_frag; 111 vk::ShaderModule convert_depth_to_float_frag;
85 vk::ShaderModule convert_float_to_depth_frag; 112 vk::ShaderModule convert_float_to_depth_frag;
113 vk::ShaderModule convert_abgr8_to_d24s8_frag;
114 vk::ShaderModule convert_b10g11r11_to_d24s8_frag;
115 vk::ShaderModule convert_r16g16_to_d24s8_frag;
116 vk::ShaderModule convert_d24s8_to_abgr8_frag;
117 vk::ShaderModule convert_d24s8_to_b10g11r11_frag;
118 vk::ShaderModule convert_d24s8_to_r16g16_frag;
86 vk::Sampler linear_sampler; 119 vk::Sampler linear_sampler;
87 vk::Sampler nearest_sampler; 120 vk::Sampler nearest_sampler;
88 121
@@ -94,6 +127,12 @@ private:
94 vk::Pipeline convert_r32_to_d32_pipeline; 127 vk::Pipeline convert_r32_to_d32_pipeline;
95 vk::Pipeline convert_d16_to_r16_pipeline; 128 vk::Pipeline convert_d16_to_r16_pipeline;
96 vk::Pipeline convert_r16_to_d16_pipeline; 129 vk::Pipeline convert_r16_to_d16_pipeline;
130 vk::Pipeline convert_abgr8_to_d24s8_pipeline;
131 vk::Pipeline convert_b10g11r11_to_d24s8_pipeline;
132 vk::Pipeline convert_r16g16_to_d24s8_pipeline;
133 vk::Pipeline convert_d24s8_to_abgr8_pipeline;
134 vk::Pipeline convert_d24s8_to_b10g11r11_pipeline;
135 vk::Pipeline convert_d24s8_to_r16g16_pipeline;
97}; 136};
98 137
99} // namespace Vulkan 138} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 68a23b602..31adada56 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -208,6 +208,9 @@ struct FormatTuple {
208 {VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT 208 {VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT
209 {VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM 209 {VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM
210 210
211 // Stencil formats
212 {VK_FORMAT_S8_UINT, Attachable}, // S8_UINT
213
211 // DepthStencil formats 214 // DepthStencil formats
212 {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // D24_UNORM_S8_UINT 215 {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // D24_UNORM_S8_UINT
213 {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // S8_UINT_D24_UNORM (emulated) 216 {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // S8_UINT_D24_UNORM (emulated)
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 407fd2a15..3964424af 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -8,6 +8,7 @@
8#include <vector> 8#include <vector>
9 9
10#include "common/bit_cast.h" 10#include "common/bit_cast.h"
11#include "common/bit_util.h"
11#include "common/settings.h" 12#include "common/settings.h"
12 13
13#include "video_core/engines/fermi_2d.h" 14#include "video_core/engines/fermi_2d.h"
@@ -102,6 +103,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
102 usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 103 usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
103 break; 104 break;
104 case VideoCore::Surface::SurfaceType::Depth: 105 case VideoCore::Surface::SurfaceType::Depth:
106 case VideoCore::Surface::SurfaceType::Stencil:
105 case VideoCore::Surface::SurfaceType::DepthStencil: 107 case VideoCore::Surface::SurfaceType::DepthStencil:
106 usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; 108 usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
107 break; 109 break;
@@ -173,6 +175,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
173 return VK_IMAGE_ASPECT_COLOR_BIT; 175 return VK_IMAGE_ASPECT_COLOR_BIT;
174 case VideoCore::Surface::SurfaceType::Depth: 176 case VideoCore::Surface::SurfaceType::Depth:
175 return VK_IMAGE_ASPECT_DEPTH_BIT; 177 return VK_IMAGE_ASPECT_DEPTH_BIT;
178 case VideoCore::Surface::SurfaceType::Stencil:
179 return VK_IMAGE_ASPECT_STENCIL_BIT;
176 case VideoCore::Surface::SurfaceType::DepthStencil: 180 case VideoCore::Surface::SurfaceType::DepthStencil:
177 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; 181 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
178 default: 182 default:
@@ -195,6 +199,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
195 case PixelFormat::D16_UNORM: 199 case PixelFormat::D16_UNORM:
196 case PixelFormat::D32_FLOAT: 200 case PixelFormat::D32_FLOAT:
197 return VK_IMAGE_ASPECT_DEPTH_BIT; 201 return VK_IMAGE_ASPECT_DEPTH_BIT;
202 case PixelFormat::S8_UINT:
203 return VK_IMAGE_ASPECT_STENCIL_BIT;
198 default: 204 default:
199 return VK_IMAGE_ASPECT_COLOR_BIT; 205 return VK_IMAGE_ASPECT_COLOR_BIT;
200 } 206 }
@@ -308,6 +314,19 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
308 }; 314 };
309} 315}
310 316
317[[nodiscard]] VkBufferImageCopy MakeBufferImageCopy(const VideoCommon::ImageCopy& copy, bool is_src,
318 VkImageAspectFlags aspect_mask) noexcept {
319 return VkBufferImageCopy{
320 .bufferOffset = 0,
321 .bufferRowLength = 0,
322 .bufferImageHeight = 0,
323 .imageSubresource = MakeImageSubresourceLayers(
324 is_src ? copy.src_subresource : copy.dst_subresource, aspect_mask),
325 .imageOffset = MakeOffset3D(is_src ? copy.src_offset : copy.dst_offset),
326 .imageExtent = MakeExtent3D(copy.extent),
327 };
328}
329
311[[maybe_unused]] [[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies( 330[[maybe_unused]] [[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies(
312 std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) { 331 std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) {
313 std::vector<VkBufferCopy> result(copies.size()); 332 std::vector<VkBufferCopy> result(copies.size());
@@ -754,6 +773,163 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
754 return staging_buffer_pool.Request(size, MemoryUsage::Download); 773 return staging_buffer_pool.Request(size, MemoryUsage::Download);
755} 774}
756 775
776bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
777 if (VideoCore::Surface::GetFormatType(dst.info.format) ==
778 VideoCore::Surface::SurfaceType::DepthStencil) {
779 return !device.IsExtShaderStencilExportSupported();
780 }
781 return false;
782}
783
784VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
785 const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL);
786 if (buffer_commits[level]) {
787 return *buffers[level];
788 }
789 const auto new_size = Common::NextPow2(needed_size);
790 VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
791 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
792 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
793 buffers[level] = device.GetLogical().CreateBuffer({
794 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
795 .pNext = nullptr,
796 .flags = 0,
797 .size = new_size,
798 .usage = flags,
799 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
800 .queueFamilyIndexCount = 0,
801 .pQueueFamilyIndices = nullptr,
802 });
803 buffer_commits[level] = std::make_unique<MemoryCommit>(
804 memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal));
805 return *buffers[level];
806}
807
808void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
809 std::span<const VideoCommon::ImageCopy> copies) {
810 std::vector<VkBufferImageCopy> vk_in_copies(copies.size());
811 std::vector<VkBufferImageCopy> vk_out_copies(copies.size());
812 const VkImageAspectFlags src_aspect_mask = src.AspectMask();
813 const VkImageAspectFlags dst_aspect_mask = dst.AspectMask();
814
815 std::ranges::transform(copies, vk_in_copies.begin(), [src_aspect_mask](const auto& copy) {
816 return MakeBufferImageCopy(copy, true, src_aspect_mask);
817 });
818 std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) {
819 return MakeBufferImageCopy(copy, false, dst_aspect_mask);
820 });
821 const u32 img_bpp = BytesPerBlock(src.info.format);
822 size_t total_size = 0;
823 for (const auto& copy : copies) {
824 total_size += copy.extent.width * copy.extent.height * copy.extent.depth * img_bpp;
825 }
826 const VkBuffer copy_buffer = GetTemporaryBuffer(total_size);
827 const VkImage dst_image = dst.Handle();
828 const VkImage src_image = src.Handle();
829 scheduler.RequestOutsideRenderPassOperationContext();
830 scheduler.Record([dst_image, src_image, copy_buffer, src_aspect_mask, dst_aspect_mask,
831 vk_in_copies, vk_out_copies](vk::CommandBuffer cmdbuf) {
832 RangedBarrierRange dst_range;
833 RangedBarrierRange src_range;
834 for (const VkBufferImageCopy& copy : vk_in_copies) {
835 src_range.AddLayers(copy.imageSubresource);
836 }
837 for (const VkBufferImageCopy& copy : vk_out_copies) {
838 dst_range.AddLayers(copy.imageSubresource);
839 }
840 static constexpr VkMemoryBarrier READ_BARRIER{
841 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
842 .pNext = nullptr,
843 .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
844 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
845 };
846 static constexpr VkMemoryBarrier WRITE_BARRIER{
847 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
848 .pNext = nullptr,
849 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
850 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
851 };
852 const std::array pre_barriers{
853 VkImageMemoryBarrier{
854 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
855 .pNext = nullptr,
856 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
857 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
858 VK_ACCESS_TRANSFER_WRITE_BIT,
859 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
860 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
861 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
862 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
863 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
864 .image = src_image,
865 .subresourceRange = src_range.SubresourceRange(src_aspect_mask),
866 },
867 };
868 const std::array middle_in_barrier{
869 VkImageMemoryBarrier{
870 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
871 .pNext = nullptr,
872 .srcAccessMask = 0,
873 .dstAccessMask = 0,
874 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
875 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
876 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
877 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
878 .image = src_image,
879 .subresourceRange = src_range.SubresourceRange(src_aspect_mask),
880 },
881 };
882 const std::array middle_out_barrier{
883 VkImageMemoryBarrier{
884 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
885 .pNext = nullptr,
886 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
887 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
888 VK_ACCESS_TRANSFER_WRITE_BIT,
889 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
890 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
891 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
892 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
893 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
894 .image = dst_image,
895 .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
896 },
897 };
898 const std::array post_barriers{
899 VkImageMemoryBarrier{
900 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
901 .pNext = nullptr,
902 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
903 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
904 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
905 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
906 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
907 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
908 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
909 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
910 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
911 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
912 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
913 .image = dst_image,
914 .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
915 },
916 };
917 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
918 0, {}, {}, pre_barriers);
919
920 cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer,
921 vk_in_copies);
922 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
923 0, WRITE_BARRIER, nullptr, middle_in_barrier);
924
925 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
926 0, READ_BARRIER, {}, middle_out_barrier);
927 cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies);
928 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
929 0, {}, {}, post_barriers);
930 });
931}
932
757void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, 933void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
758 const Region2D& dst_region, const Region2D& src_region, 934 const Region2D& dst_region, const Region2D& src_region,
759 Tegra::Engines::Fermi2D::Filter filter, 935 Tegra::Engines::Fermi2D::Filter filter,
@@ -881,6 +1057,22 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
881 return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift); 1057 return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift);
882 } 1058 }
883 break; 1059 break;
1060 case PixelFormat::A8B8G8R8_UNORM:
1061 case PixelFormat::B8G8R8A8_UNORM:
1062 if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
1063 return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift);
1064 }
1065 break;
1066 case PixelFormat::B10G11R11_FLOAT:
1067 if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
1068 return blit_image_helper.ConvertD24S8ToB10G11R11(dst, src_view, up_scale, down_shift);
1069 }
1070 break;
1071 case PixelFormat::R16G16_UNORM:
1072 if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
1073 return blit_image_helper.ConvertD24S8ToR16G16(dst, src_view, up_scale, down_shift);
1074 }
1075 break;
884 case PixelFormat::R32_FLOAT: 1076 case PixelFormat::R32_FLOAT:
885 if (src_view.format == PixelFormat::D32_FLOAT) { 1077 if (src_view.format == PixelFormat::D32_FLOAT) {
886 return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift); 1078 return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift);
@@ -891,6 +1083,18 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
891 return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift); 1083 return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift);
892 } 1084 }
893 break; 1085 break;
1086 case PixelFormat::S8_UINT_D24_UNORM:
1087 if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
1088 src_view.format == PixelFormat::B8G8R8A8_UNORM) {
1089 return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift);
1090 }
1091 if (src_view.format == PixelFormat::B10G11R11_FLOAT) {
1092 return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift);
1093 }
1094 if (src_view.format == PixelFormat::R16G16_UNORM) {
1095 return blit_image_helper.ConvertR16G16ToD24S8(dst, src_view, up_scale, down_shift);
1096 }
1097 break;
894 case PixelFormat::D32_FLOAT: 1098 case PixelFormat::D32_FLOAT:
895 if (src_view.format == PixelFormat::R32_FLOAT) { 1099 if (src_view.format == PixelFormat::R32_FLOAT) {
896 return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift); 1100 return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift);
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index ff28b4e96..44e9dcee4 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -61,6 +61,10 @@ public:
61 61
62 void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); 62 void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
63 63
64 bool ShouldReinterpret(Image& dst, Image& src);
65
66 void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
67
64 void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled); 68 void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled);
65 69
66 bool CanAccelerateImageUpload(Image&) const noexcept { 70 bool CanAccelerateImageUpload(Image&) const noexcept {
@@ -82,6 +86,8 @@ public:
82 return true; 86 return true;
83 } 87 }
84 88
89 [[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size);
90
85 const Device& device; 91 const Device& device;
86 VKScheduler& scheduler; 92 VKScheduler& scheduler;
87 MemoryAllocator& memory_allocator; 93 MemoryAllocator& memory_allocator;
@@ -90,6 +96,10 @@ public:
90 ASTCDecoderPass& astc_decoder_pass; 96 ASTCDecoderPass& astc_decoder_pass;
91 RenderPassCache& render_pass_cache; 97 RenderPassCache& render_pass_cache;
92 const Settings::ResolutionScalingInfo& resolution; 98 const Settings::ResolutionScalingInfo& resolution;
99
100 constexpr static size_t indexing_slots = 8 * sizeof(size_t);
101 std::array<vk::Buffer, indexing_slots> buffers{};
102 std::array<std::unique_ptr<MemoryCommit>, indexing_slots> buffer_commits{};
93}; 103};
94 104
95class Image : public VideoCommon::ImageBase { 105class Image : public VideoCommon::ImageBase {
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 58d262446..a36015c8c 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -82,6 +82,8 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
82 return PixelFormat::D32_FLOAT; 82 return PixelFormat::D32_FLOAT;
83 case Tegra::DepthFormat::D16_UNORM: 83 case Tegra::DepthFormat::D16_UNORM:
84 return PixelFormat::D16_UNORM; 84 return PixelFormat::D16_UNORM;
85 case Tegra::DepthFormat::S8_UINT:
86 return PixelFormat::S8_UINT;
85 case Tegra::DepthFormat::D32_FLOAT_S8X24_UINT: 87 case Tegra::DepthFormat::D32_FLOAT_S8X24_UINT:
86 return PixelFormat::D32_FLOAT_S8_UINT; 88 return PixelFormat::D32_FLOAT_S8_UINT;
87 default: 89 default:
@@ -214,6 +216,11 @@ SurfaceType GetFormatType(PixelFormat pixel_format) {
214 } 216 }
215 217
216 if (static_cast<std::size_t>(pixel_format) < 218 if (static_cast<std::size_t>(pixel_format) <
219 static_cast<std::size_t>(PixelFormat::MaxStencilFormat)) {
220 return SurfaceType::Stencil;
221 }
222
223 if (static_cast<std::size_t>(pixel_format) <
217 static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) { 224 static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
218 return SurfaceType::DepthStencil; 225 return SurfaceType::DepthStencil;
219 } 226 }
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 2ce7c7d33..33e8d24ab 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -110,8 +110,12 @@ enum class PixelFormat {
110 110
111 MaxDepthFormat, 111 MaxDepthFormat,
112 112
113 // Stencil formats
114 S8_UINT = MaxDepthFormat,
115 MaxStencilFormat,
116
113 // DepthStencil formats 117 // DepthStencil formats
114 D24_UNORM_S8_UINT = MaxDepthFormat, 118 D24_UNORM_S8_UINT = MaxStencilFormat,
115 S8_UINT_D24_UNORM, 119 S8_UINT_D24_UNORM,
116 D32_FLOAT_S8_UINT, 120 D32_FLOAT_S8_UINT,
117 121
@@ -125,8 +129,9 @@ constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max
125enum class SurfaceType { 129enum class SurfaceType {
126 ColorTexture = 0, 130 ColorTexture = 0,
127 Depth = 1, 131 Depth = 1,
128 DepthStencil = 2, 132 Stencil = 2,
129 Invalid = 3, 133 DepthStencil = 3,
134 Invalid = 4,
130}; 135};
131 136
132enum class SurfaceTarget { 137enum class SurfaceTarget {
@@ -229,6 +234,7 @@ constexpr std::array<u32, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
229 1, // E5B9G9R9_FLOAT 234 1, // E5B9G9R9_FLOAT
230 1, // D32_FLOAT 235 1, // D32_FLOAT
231 1, // D16_UNORM 236 1, // D16_UNORM
237 1, // S8_UINT
232 1, // D24_UNORM_S8_UINT 238 1, // D24_UNORM_S8_UINT
233 1, // S8_UINT_D24_UNORM 239 1, // S8_UINT_D24_UNORM
234 1, // D32_FLOAT_S8_UINT 240 1, // D32_FLOAT_S8_UINT
@@ -328,6 +334,7 @@ constexpr std::array<u32, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
328 1, // E5B9G9R9_FLOAT 334 1, // E5B9G9R9_FLOAT
329 1, // D32_FLOAT 335 1, // D32_FLOAT
330 1, // D16_UNORM 336 1, // D16_UNORM
337 1, // S8_UINT
331 1, // D24_UNORM_S8_UINT 338 1, // D24_UNORM_S8_UINT
332 1, // S8_UINT_D24_UNORM 339 1, // S8_UINT_D24_UNORM
333 1, // D32_FLOAT_S8_UINT 340 1, // D32_FLOAT_S8_UINT
@@ -427,6 +434,7 @@ constexpr std::array<u32, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
427 32, // E5B9G9R9_FLOAT 434 32, // E5B9G9R9_FLOAT
428 32, // D32_FLOAT 435 32, // D32_FLOAT
429 16, // D16_UNORM 436 16, // D16_UNORM
437 8, // S8_UINT
430 32, // D24_UNORM_S8_UINT 438 32, // D24_UNORM_S8_UINT
431 32, // S8_UINT_D24_UNORM 439 32, // S8_UINT_D24_UNORM
432 64, // D32_FLOAT_S8_UINT 440 64, // D32_FLOAT_S8_UINT
diff --git a/src/video_core/texture_cache/formatter.h b/src/video_core/texture_cache/formatter.h
index c6cf0583f..b2c81057b 100644
--- a/src/video_core/texture_cache/formatter.h
+++ b/src/video_core/texture_cache/formatter.h
@@ -194,6 +194,8 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
194 return "D32_FLOAT"; 194 return "D32_FLOAT";
195 case PixelFormat::D16_UNORM: 195 case PixelFormat::D16_UNORM:
196 return "D16_UNORM"; 196 return "D16_UNORM";
197 case PixelFormat::S8_UINT:
198 return "S8_UINT";
197 case PixelFormat::D24_UNORM_S8_UINT: 199 case PixelFormat::D24_UNORM_S8_UINT:
198 return "D24_UNORM_S8_UINT"; 200 return "D24_UNORM_S8_UINT";
199 case PixelFormat::S8_UINT_D24_UNORM: 201 case PixelFormat::S8_UINT_D24_UNORM:
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 4d2874bf2..44a0d42ba 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -475,6 +475,7 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
475 const BlitImages images = GetBlitImages(dst, src); 475 const BlitImages images = GetBlitImages(dst, src);
476 const ImageId dst_id = images.dst_id; 476 const ImageId dst_id = images.dst_id;
477 const ImageId src_id = images.src_id; 477 const ImageId src_id = images.src_id;
478
478 PrepareImage(src_id, false, false); 479 PrepareImage(src_id, false, false);
479 PrepareImage(dst_id, true, false); 480 PrepareImage(dst_id, true, false);
480 481
@@ -758,7 +759,8 @@ ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
758 return ImageId{}; 759 return ImageId{};
759 } 760 }
760 } 761 }
761 const bool broken_views = runtime.HasBrokenTextureViewFormats(); 762 const bool broken_views =
763 runtime.HasBrokenTextureViewFormats() || True(options & RelaxedOptions::ForceBrokenViews);
762 const bool native_bgr = runtime.HasNativeBgr(); 764 const bool native_bgr = runtime.HasNativeBgr();
763 ImageId image_id; 765 ImageId image_id;
764 const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { 766 const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) {
@@ -1094,12 +1096,13 @@ typename TextureCache<P>::BlitImages TextureCache<P>::GetBlitImages(
1094 if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) { 1096 if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) {
1095 continue; 1097 continue;
1096 } 1098 }
1097 if (!dst_id) { 1099 RelaxedOptions find_options{};
1098 dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{}); 1100 if (src_info.num_samples > 1) {
1099 } 1101 // it's a resolve, we must enforce the same format.
1100 if (!src_id) { 1102 find_options = RelaxedOptions::ForceBrokenViews;
1101 src_id = InsertImage(src_info, src_addr, RelaxedOptions{});
1102 } 1103 }
1104 src_id = FindOrInsertImage(src_info, src_addr, find_options);
1105 dst_id = FindOrInsertImage(dst_info, dst_addr, find_options);
1103 } while (has_deleted_images); 1106 } while (has_deleted_images);
1104 return BlitImages{ 1107 return BlitImages{
1105 .dst_id = dst_id, 1108 .dst_id = dst_id,
@@ -1759,6 +1762,9 @@ void TextureCache<P>::CopyImage(ImageId dst_id, ImageId src_id, std::vector<Imag
1759 } 1762 }
1760 UNIMPLEMENTED_IF(dst.info.type != ImageType::e2D); 1763 UNIMPLEMENTED_IF(dst.info.type != ImageType::e2D);
1761 UNIMPLEMENTED_IF(src.info.type != ImageType::e2D); 1764 UNIMPLEMENTED_IF(src.info.type != ImageType::e2D);
1765 if (runtime.ShouldReinterpret(dst, src)) {
1766 return runtime.ReinterpretImage(dst, src, copies);
1767 }
1762 for (const ImageCopy& copy : copies) { 1768 for (const ImageCopy& copy : copies) {
1763 UNIMPLEMENTED_IF(copy.dst_subresource.num_layers != 1); 1769 UNIMPLEMENTED_IF(copy.dst_subresource.num_layers != 1);
1764 UNIMPLEMENTED_IF(copy.src_subresource.num_layers != 1); 1770 UNIMPLEMENTED_IF(copy.src_subresource.num_layers != 1);
diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h
index 5c274abdf..5ac27b3a7 100644
--- a/src/video_core/texture_cache/types.h
+++ b/src/video_core/texture_cache/types.h
@@ -54,6 +54,7 @@ enum class RelaxedOptions : u32 {
54 Size = 1 << 0, 54 Size = 1 << 0,
55 Format = 1 << 1, 55 Format = 1 << 1,
56 Samples = 1 << 2, 56 Samples = 1 << 2,
57 ForceBrokenViews = 1 << 3,
57}; 58};
58DECLARE_ENUM_FLAG_OPERATORS(RelaxedOptions) 59DECLARE_ENUM_FLAG_OPERATORS(RelaxedOptions)
59 60
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index ddc9fb13a..e4d82631e 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -1151,18 +1151,39 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr
1151 1151
1152void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, 1152void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst,
1153 const ImageBase* src) { 1153 const ImageBase* src) {
1154 if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) { 1154 bool is_resolve = false;
1155 src_info.format = src->info.format; 1155 const auto original_src_format = src_info.format;
1156 const auto original_dst_format = dst_info.format;
1157 if (src) {
1158 if (GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
1159 src_info.format = src->info.format;
1160 }
1161 is_resolve = src->info.num_samples > 1;
1162 src_info.num_samples = src->info.num_samples;
1163 src_info.size = src->info.size;
1156 } 1164 }
1157 if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { 1165 if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
1158 dst_info.format = dst->info.format; 1166 dst_info.format = dst->info.format;
1159 } 1167 }
1160 if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) { 1168 if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
1161 dst_info.format = src->info.format; 1169 if (dst) {
1170 if (GetFormatType(dst->info.format) == SurfaceType::ColorTexture) {
1171 src_info.format = original_src_format;
1172 }
1173 } else {
1174 dst_info.format = src->info.format;
1175 }
1162 } 1176 }
1163 if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) { 1177 if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
1164 src_info.format = dst->info.format; 1178 if (src) {
1179 if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) {
1180 dst_info.format = original_dst_format;
1181 }
1182 } else {
1183 src_info.format = dst->info.format;
1184 }
1165 } 1185 }
1186 ASSERT(!is_resolve || dst_info.format == src_info.format);
1166} 1187}
1167 1188
1168u32 MapSizeBytes(const ImageBase& image) { 1189u32 MapSizeBytes(const ImageBase& image) {
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 95106f88f..70c52aaac 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -21,6 +21,13 @@
21namespace Vulkan { 21namespace Vulkan {
22namespace { 22namespace {
23namespace Alternatives { 23namespace Alternatives {
24constexpr std::array STENCIL8_UINT{
25 VK_FORMAT_D16_UNORM_S8_UINT,
26 VK_FORMAT_D24_UNORM_S8_UINT,
27 VK_FORMAT_D32_SFLOAT_S8_UINT,
28 VK_FORMAT_UNDEFINED,
29};
30
24constexpr std::array DEPTH24_UNORM_STENCIL8_UINT{ 31constexpr std::array DEPTH24_UNORM_STENCIL8_UINT{
25 VK_FORMAT_D32_SFLOAT_S8_UINT, 32 VK_FORMAT_D32_SFLOAT_S8_UINT,
26 VK_FORMAT_D16_UNORM_S8_UINT, 33 VK_FORMAT_D16_UNORM_S8_UINT,
@@ -74,6 +81,8 @@ void SetNext(void**& next, T& data) {
74 81
75constexpr const VkFormat* GetFormatAlternatives(VkFormat format) { 82constexpr const VkFormat* GetFormatAlternatives(VkFormat format) {
76 switch (format) { 83 switch (format) {
84 case VK_FORMAT_S8_UINT:
85 return Alternatives::STENCIL8_UINT.data();
77 case VK_FORMAT_D24_UNORM_S8_UINT: 86 case VK_FORMAT_D24_UNORM_S8_UINT:
78 return Alternatives::DEPTH24_UNORM_STENCIL8_UINT.data(); 87 return Alternatives::DEPTH24_UNORM_STENCIL8_UINT.data();
79 case VK_FORMAT_D16_UNORM_S8_UINT: 88 case VK_FORMAT_D16_UNORM_S8_UINT:
@@ -145,6 +154,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
145 VK_FORMAT_R4G4B4A4_UNORM_PACK16, 154 VK_FORMAT_R4G4B4A4_UNORM_PACK16,
146 VK_FORMAT_D32_SFLOAT, 155 VK_FORMAT_D32_SFLOAT,
147 VK_FORMAT_D16_UNORM, 156 VK_FORMAT_D16_UNORM,
157 VK_FORMAT_S8_UINT,
148 VK_FORMAT_D16_UNORM_S8_UINT, 158 VK_FORMAT_D16_UNORM_S8_UINT,
149 VK_FORMAT_D24_UNORM_S8_UINT, 159 VK_FORMAT_D24_UNORM_S8_UINT,
150 VK_FORMAT_D32_SFLOAT_S8_UINT, 160 VK_FORMAT_D32_SFLOAT_S8_UINT,
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 660b68c1c..9241678e4 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -429,7 +429,7 @@
429 </item> 429 </item>
430 <item> 430 <item>
431 <property name="text"> 431 <property name="text">
432 <string>AMD's FidelityFX™️ Super Resolution [Vulkan Only]</string> 432 <string>AMD FidelityFX™️ Super Resolution [Vulkan Only]</string>
433 </property> 433 </property>
434 </item> 434 </item>
435 </widget> 435 </widget>
diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp
index d4e97fa16..e7e58f314 100644
--- a/src/yuzu/hotkeys.cpp
+++ b/src/yuzu/hotkeys.cpp
@@ -46,6 +46,8 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action
46 if (!hk.shortcut) 46 if (!hk.shortcut)
47 hk.shortcut = new QShortcut(hk.keyseq, widget, nullptr, nullptr, hk.context); 47 hk.shortcut = new QShortcut(hk.keyseq, widget, nullptr, nullptr, hk.context);
48 48
49 hk.shortcut->setAutoRepeat(false);
50
49 return hk.shortcut; 51 return hk.shortcut;
50} 52}
51 53
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index d057dc889..c4c76b094 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1031,7 +1031,7 @@ void GMainWindow::InitializeHotkeys() {
1031 &QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger); 1031 &QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger);
1032 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this), 1032 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this),
1033 &QShortcut::activated, this, [&] { 1033 &QShortcut::activated, this, [&] {
1034 if (emulation_running) { 1034 if (emulation_running && ui->action_Fullscreen->isChecked()) {
1035 ui->action_Fullscreen->setChecked(false); 1035 ui->action_Fullscreen->setChecked(false);
1036 ToggleFullscreen(); 1036 ToggleFullscreen();
1037 } 1037 }
@@ -3106,7 +3106,7 @@ void GMainWindow::UpdateFilterText() {
3106 filter_status_button->setText(tr("SCALEFORCE")); 3106 filter_status_button->setText(tr("SCALEFORCE"));
3107 break; 3107 break;
3108 case Settings::ScalingFilter::Fsr: 3108 case Settings::ScalingFilter::Fsr:
3109 filter_status_button->setText(tr("AMD'S FIDELITYFX SR")); 3109 filter_status_button->setText(tr("FSR"));
3110 break; 3110 break;
3111 default: 3111 default:
3112 filter_status_button->setText(tr("BILINEAR")); 3112 filter_status_button->setText(tr("BILINEAR"));
@@ -3117,15 +3117,15 @@ void GMainWindow::UpdateFilterText() {
3117void GMainWindow::UpdateAAText() { 3117void GMainWindow::UpdateAAText() {
3118 const auto aa_mode = Settings::values.anti_aliasing.GetValue(); 3118 const auto aa_mode = Settings::values.anti_aliasing.GetValue();
3119 switch (aa_mode) { 3119 switch (aa_mode) {
3120 case Settings::AntiAliasing::Fxaa:
3121 aa_status_button->setText(tr("FXAA"));
3122 break;
3123 case Settings::AntiAliasing::None: 3120 case Settings::AntiAliasing::None:
3124 aa_status_button->setText(tr("NO AA")); 3121 aa_status_button->setText(tr("NO AA"));
3125 break; 3122 break;
3126 default: 3123 case Settings::AntiAliasing::Fxaa:
3127 aa_status_button->setText(tr("FXAA")); 3124 aa_status_button->setText(tr("FXAA"));
3128 break; 3125 break;
3126 default:
3127 aa_status_button->setText(tr("NO AA"));
3128 break;
3129 } 3129 }
3130} 3130}
3131 3131
@@ -3300,9 +3300,9 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
3300 if (!errors.isEmpty()) { 3300 if (!errors.isEmpty()) {
3301 QMessageBox::warning( 3301 QMessageBox::warning(
3302 this, tr("Derivation Components Missing"), 3302 this, tr("Derivation Components Missing"),
3303 tr("Components are missing that may hinder key derivation from completing. " 3303 tr("Encryption keys are missing. "
3304 "<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu " 3304 "<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu "
3305 "quickstart guide</a> to get all your keys and " 3305 "quickstart guide</a> to get all your keys, firmware and "
3306 "games.<br><br><small>(%1)</small>") 3306 "games.<br><br><small>(%1)</small>")
3307 .arg(errors)); 3307 .arg(errors));
3308 } 3308 }