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/video_core/gpu.h1
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp78
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h23
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h1
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h1
-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.h3
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h2
-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
19 files changed, 127 insertions, 49 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/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/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 5cfb6bb8a..3dbdcc2c4 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -148,6 +148,8 @@ GLenum AttachmentType(PixelFormat format) {
148 switch (const SurfaceType type = VideoCore::Surface::GetFormatType(format); type) { 148 switch (const SurfaceType type = VideoCore::Surface::GetFormatType(format); type) {
149 case SurfaceType::Depth: 149 case SurfaceType::Depth:
150 return GL_DEPTH_ATTACHMENT; 150 return GL_DEPTH_ATTACHMENT;
151 case SurfaceType::Stencil:
152 return GL_STENCIL_ATTACHMENT;
151 case SurfaceType::DepthStencil: 153 case SurfaceType::DepthStencil:
152 return GL_DEPTH_STENCIL_ATTACHMENT; 154 return GL_DEPTH_STENCIL_ATTACHMENT;
153 default: 155 default:
@@ -395,6 +397,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
395 UNREACHABLE_MSG("Invalid image format={}", format); 397 UNREACHABLE_MSG("Invalid image format={}", format);
396 return GL_R32UI; 398 return GL_R32UI;
397} 399}
400
401[[nodiscard]] u32 NextPow2(u32 value) {
402 return 1U << (32U - std::countl_zero(value - 1U));
403}
398} // Anonymous namespace 404} // Anonymous namespace
399 405
400ImageBufferMap::~ImageBufferMap() { 406ImageBufferMap::~ImageBufferMap() {
@@ -521,6 +527,12 @@ void TextureCacheRuntime::CopyImage(Image& dst_image, Image& src_image,
521 } 527 }
522} 528}
523 529
530void TextureCacheRuntime::ConvertImage(Image& dst, Image& src,
531 std::span<const VideoCommon::ImageCopy> copies) {
532 LOG_DEBUG(Render_OpenGL, "Converting {} to {}", src.info.format, dst.info.format);
533 format_conversion_pass.ConvertImage(dst, src, copies);
534}
535
524bool TextureCacheRuntime::CanImageBeCopied(const Image& dst, const Image& src) { 536bool TextureCacheRuntime::CanImageBeCopied(const Image& dst, const Image& src) {
525 if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) { 537 if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) {
526 return false; 538 return false;
@@ -537,7 +549,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src,
537 ASSERT(src.info.type == ImageType::e3D); 549 ASSERT(src.info.type == ImageType::e3D);
538 util_shaders.CopyBC4(dst, src, copies); 550 util_shaders.CopyBC4(dst, src, copies);
539 } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { 551 } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) {
540 bgr_copy_pass.CopyBGR(dst, src, copies); 552 format_conversion_pass.ConvertImage(dst, src, copies);
541 } else { 553 } else {
542 UNREACHABLE(); 554 UNREACHABLE();
543 } 555 }
@@ -904,6 +916,8 @@ void Image::Scale(bool up_scale) {
904 return GL_COLOR_ATTACHMENT0; 916 return GL_COLOR_ATTACHMENT0;
905 case SurfaceType::Depth: 917 case SurfaceType::Depth:
906 return GL_DEPTH_ATTACHMENT; 918 return GL_DEPTH_ATTACHMENT;
919 case SurfaceType::Stencil:
920 return GL_STENCIL_ATTACHMENT;
907 case SurfaceType::DepthStencil: 921 case SurfaceType::DepthStencil:
908 return GL_DEPTH_STENCIL_ATTACHMENT; 922 return GL_DEPTH_STENCIL_ATTACHMENT;
909 default: 923 default:
@@ -917,8 +931,10 @@ void Image::Scale(bool up_scale) {
917 return GL_COLOR_BUFFER_BIT; 931 return GL_COLOR_BUFFER_BIT;
918 case SurfaceType::Depth: 932 case SurfaceType::Depth:
919 return GL_DEPTH_BUFFER_BIT; 933 return GL_DEPTH_BUFFER_BIT;
934 case SurfaceType::Stencil:
935 return GL_STENCIL_BUFFER_BIT;
920 case SurfaceType::DepthStencil: 936 case SurfaceType::DepthStencil:
921 return GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; 937 return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
922 default: 938 default:
923 UNREACHABLE(); 939 UNREACHABLE();
924 return GL_COLOR_BUFFER_BIT; 940 return GL_COLOR_BUFFER_BIT;
@@ -930,8 +946,10 @@ void Image::Scale(bool up_scale) {
930 return 0; 946 return 0;
931 case SurfaceType::Depth: 947 case SurfaceType::Depth:
932 return 1; 948 return 1;
933 case SurfaceType::DepthStencil: 949 case SurfaceType::Stencil:
934 return 2; 950 return 2;
951 case SurfaceType::DepthStencil:
952 return 3;
935 default: 953 default:
936 UNREACHABLE(); 954 UNREACHABLE();
937 return 0; 955 return 0;
@@ -1261,10 +1279,20 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1261 } 1279 }
1262 1280
1263 if (const ImageView* const image_view = depth_buffer; image_view) { 1281 if (const ImageView* const image_view = depth_buffer; image_view) {
1264 if (GetFormatType(image_view->format) == SurfaceType::DepthStencil) { 1282 switch (GetFormatType(image_view->format)) {
1283 case SurfaceType::Depth:
1284 buffer_bits |= GL_DEPTH_BUFFER_BIT;
1285 break;
1286 case SurfaceType::Stencil:
1287 buffer_bits |= GL_STENCIL_BUFFER_BIT;
1288 break;
1289 case SurfaceType::DepthStencil:
1265 buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; 1290 buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
1266 } else { 1291 break;
1292 default:
1293 UNREACHABLE();
1267 buffer_bits |= GL_DEPTH_BUFFER_BIT; 1294 buffer_bits |= GL_DEPTH_BUFFER_BIT;
1295 break;
1268 } 1296 }
1269 const GLenum attachment = AttachmentType(image_view->format); 1297 const GLenum attachment = AttachmentType(image_view->format);
1270 AttachTexture(handle, attachment, image_view); 1298 AttachTexture(handle, attachment, image_view);
@@ -1293,35 +1321,37 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1293 1321
1294Framebuffer::~Framebuffer() = default; 1322Framebuffer::~Framebuffer() = default;
1295 1323
1296void BGRCopyPass::CopyBGR(Image& dst_image, Image& src_image, 1324void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,
1297 std::span<const VideoCommon::ImageCopy> copies) { 1325 std::span<const VideoCommon::ImageCopy> copies) {
1298 static constexpr VideoCommon::Offset3D zero_offset{0, 0, 0}; 1326 const GLenum dst_target = ImageTarget(dst_image.info);
1327 const GLenum src_target = ImageTarget(src_image.info);
1299 const u32 img_bpp = BytesPerBlock(src_image.info.format); 1328 const u32 img_bpp = BytesPerBlock(src_image.info.format);
1300 for (const ImageCopy& copy : copies) { 1329 for (const ImageCopy& copy : copies) {
1301 ASSERT(copy.src_offset == zero_offset); 1330 const auto src_origin = MakeCopyOrigin(copy.src_offset, copy.src_subresource, src_target);
1302 ASSERT(copy.dst_offset == zero_offset); 1331 const auto dst_origin = MakeCopyOrigin(copy.dst_offset, copy.dst_subresource, dst_target);
1303 const u32 num_src_layers = static_cast<u32>(copy.src_subresource.num_layers); 1332 const auto region = MakeCopyRegion(copy.extent, copy.dst_subresource, dst_target);
1304 const u32 copy_size = copy.extent.width * copy.extent.height * num_src_layers * img_bpp; 1333 const u32 copy_size = region.width * region.height * region.depth * img_bpp;
1305 if (bgr_pbo_size < copy_size) { 1334 if (pbo_size < copy_size) {
1306 bgr_pbo.Create(); 1335 intermediate_pbo.Create();
1307 bgr_pbo_size = copy_size; 1336 pbo_size = NextPow2(copy_size);
1308 glNamedBufferData(bgr_pbo.handle, bgr_pbo_size, nullptr, GL_STREAM_COPY); 1337 glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY);
1309 } 1338 }
1310 // Copy from source to PBO 1339 // Copy from source to PBO
1311 glPixelStorei(GL_PACK_ALIGNMENT, 1); 1340 glPixelStorei(GL_PACK_ALIGNMENT, 1);
1312 glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width); 1341 glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width);
1313 glBindBuffer(GL_PIXEL_PACK_BUFFER, bgr_pbo.handle); 1342 glBindBuffer(GL_PIXEL_PACK_BUFFER, intermediate_pbo.handle);
1314 glGetTextureSubImage(src_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height, 1343 glGetTextureSubImage(src_image.Handle(), src_origin.level, src_origin.x, src_origin.y,
1315 num_src_layers, src_image.GlFormat(), src_image.GlType(), 1344 src_origin.z, region.width, region.height, region.depth,
1316 static_cast<GLsizei>(bgr_pbo_size), nullptr); 1345 src_image.GlFormat(), src_image.GlType(),
1346 static_cast<GLsizei>(pbo_size), nullptr);
1317 1347
1318 // Copy from PBO to destination in desired GL format 1348 // Copy from PBO to destination in desired GL format
1319 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 1349 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1320 glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width); 1350 glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width);
1321 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bgr_pbo.handle); 1351 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, intermediate_pbo.handle);
1322 glTextureSubImage3D(dst_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height, 1352 glTextureSubImage3D(dst_image.Handle(), dst_origin.level, dst_origin.x, dst_origin.y,
1323 copy.dst_subresource.num_layers, dst_image.GlFormat(), 1353 dst_origin.z, region.width, region.height, region.depth,
1324 dst_image.GlType(), nullptr); 1354 dst_image.GlFormat(), dst_image.GlType(), nullptr);
1325 } 1355 }
1326} 1356}
1327 1357
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 30037a6a2..c0534b1f1 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 {
@@ -86,6 +86,8 @@ public:
86 86
87 void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); 87 void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
88 88
89 void ConvertImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
90
89 void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) { 91 void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) {
90 UNIMPLEMENTED(); 92 UNIMPLEMENTED();
91 } 93 }
@@ -144,7 +146,7 @@ private:
144 const Device& device; 146 const Device& device;
145 StateTracker& state_tracker; 147 StateTracker& state_tracker;
146 UtilShaders util_shaders; 148 UtilShaders util_shaders;
147 BGRCopyPass bgr_copy_pass; 149 FormatConversionPass format_conversion_pass;
148 150
149 std::array<std::unordered_map<GLenum, FormatProperties>, 3> format_properties; 151 std::array<std::unordered_map<GLenum, FormatProperties>, 3> format_properties;
150 bool has_broken_texture_view_formats = false; 152 bool has_broken_texture_view_formats = false;
@@ -162,8 +164,8 @@ private:
162 164
163 std::array<GLuint, Shader::NUM_TEXTURE_TYPES> null_image_views{}; 165 std::array<GLuint, Shader::NUM_TEXTURE_TYPES> null_image_views{};
164 166
165 std::array<OGLFramebuffer, 3> rescale_draw_fbos; 167 std::array<OGLFramebuffer, 4> rescale_draw_fbos;
166 std::array<OGLFramebuffer, 3> rescale_read_fbos; 168 std::array<OGLFramebuffer, 4> rescale_read_fbos;
167 const Settings::ResolutionScalingInfo& resolution; 169 const Settings::ResolutionScalingInfo& resolution;
168}; 170};
169 171
@@ -337,6 +339,7 @@ struct TextureCacheParams {
337 static constexpr bool FRAMEBUFFER_BLITS = true; 339 static constexpr bool FRAMEBUFFER_BLITS = true;
338 static constexpr bool HAS_EMULATED_COPIES = true; 340 static constexpr bool HAS_EMULATED_COPIES = true;
339 static constexpr bool HAS_DEVICE_MEMORY_INFO = true; 341 static constexpr bool HAS_DEVICE_MEMORY_INFO = true;
342 static constexpr bool HAS_PIXEL_FORMAT_CONVERSIONS = true;
340 343
341 using Runtime = OpenGL::TextureCacheRuntime; 344 using Runtime = OpenGL::TextureCacheRuntime;
342 using Image = OpenGL::Image; 345 using Image = OpenGL::Image;
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/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..9bc846b94 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -102,6 +102,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
102 usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 102 usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
103 break; 103 break;
104 case VideoCore::Surface::SurfaceType::Depth: 104 case VideoCore::Surface::SurfaceType::Depth:
105 case VideoCore::Surface::SurfaceType::Stencil:
105 case VideoCore::Surface::SurfaceType::DepthStencil: 106 case VideoCore::Surface::SurfaceType::DepthStencil:
106 usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; 107 usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
107 break; 108 break;
@@ -173,6 +174,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
173 return VK_IMAGE_ASPECT_COLOR_BIT; 174 return VK_IMAGE_ASPECT_COLOR_BIT;
174 case VideoCore::Surface::SurfaceType::Depth: 175 case VideoCore::Surface::SurfaceType::Depth:
175 return VK_IMAGE_ASPECT_DEPTH_BIT; 176 return VK_IMAGE_ASPECT_DEPTH_BIT;
177 case VideoCore::Surface::SurfaceType::Stencil:
178 return VK_IMAGE_ASPECT_STENCIL_BIT;
176 case VideoCore::Surface::SurfaceType::DepthStencil: 179 case VideoCore::Surface::SurfaceType::DepthStencil:
177 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; 180 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
178 default: 181 default:
@@ -195,6 +198,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
195 case PixelFormat::D16_UNORM: 198 case PixelFormat::D16_UNORM:
196 case PixelFormat::D32_FLOAT: 199 case PixelFormat::D32_FLOAT:
197 return VK_IMAGE_ASPECT_DEPTH_BIT; 200 return VK_IMAGE_ASPECT_DEPTH_BIT;
201 case PixelFormat::S8_UINT:
202 return VK_IMAGE_ASPECT_STENCIL_BIT;
198 default: 203 default:
199 return VK_IMAGE_ASPECT_COLOR_BIT; 204 return VK_IMAGE_ASPECT_COLOR_BIT;
200 } 205 }
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index ff28b4e96..f5f8f9a74 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -316,6 +316,7 @@ struct TextureCacheParams {
316 static constexpr bool FRAMEBUFFER_BLITS = false; 316 static constexpr bool FRAMEBUFFER_BLITS = false;
317 static constexpr bool HAS_EMULATED_COPIES = false; 317 static constexpr bool HAS_EMULATED_COPIES = false;
318 static constexpr bool HAS_DEVICE_MEMORY_INFO = true; 318 static constexpr bool HAS_DEVICE_MEMORY_INFO = true;
319 static constexpr bool HAS_PIXEL_FORMAT_CONVERSIONS = false;
319 320
320 using Runtime = Vulkan::TextureCacheRuntime; 321 using Runtime = Vulkan::TextureCacheRuntime;
321 using Image = Vulkan::Image; 322 using Image = Vulkan::Image;
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..241f71a91 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1759,6 +1759,9 @@ void TextureCache<P>::CopyImage(ImageId dst_id, ImageId src_id, std::vector<Imag
1759 } 1759 }
1760 UNIMPLEMENTED_IF(dst.info.type != ImageType::e2D); 1760 UNIMPLEMENTED_IF(dst.info.type != ImageType::e2D);
1761 UNIMPLEMENTED_IF(src.info.type != ImageType::e2D); 1761 UNIMPLEMENTED_IF(src.info.type != ImageType::e2D);
1762 if constexpr (HAS_PIXEL_FORMAT_CONVERSIONS) {
1763 return runtime.ConvertImage(dst, src, copies);
1764 }
1762 for (const ImageCopy& copy : copies) { 1765 for (const ImageCopy& copy : copies) {
1763 UNIMPLEMENTED_IF(copy.dst_subresource.num_layers != 1); 1766 UNIMPLEMENTED_IF(copy.dst_subresource.num_layers != 1);
1764 UNIMPLEMENTED_IF(copy.src_subresource.num_layers != 1); 1767 UNIMPLEMENTED_IF(copy.src_subresource.num_layers != 1);
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index 643ad811c..a9504c0e8 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -59,6 +59,8 @@ class TextureCache {
59 static constexpr bool HAS_EMULATED_COPIES = P::HAS_EMULATED_COPIES; 59 static constexpr bool HAS_EMULATED_COPIES = P::HAS_EMULATED_COPIES;
60 /// True when the API can provide info about the memory of the device. 60 /// True when the API can provide info about the memory of the device.
61 static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO; 61 static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
62 /// True when the API provides utilities for pixel format conversions.
63 static constexpr bool HAS_PIXEL_FORMAT_CONVERSIONS = P::HAS_PIXEL_FORMAT_CONVERSIONS;
62 64
63 static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB; 65 static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
64 static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB; 66 static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
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 }