summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
28 files changed, 762 insertions, 75 deletions
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 @@
#include <bit>
#include <climits>
#include <cstddef>
+#include <type_traits>
#include "common/common_types.h"
@@ -44,4 +45,10 @@ template <typename T>
return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL));
}
+template <typename T>
+requires std::is_integral_v<T>
+[[nodiscard]] T NextPow2(T value) {
+ return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
+}
+
} // 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 {
namespace {
-constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1};
+constexpr ResultCode ResultProcessNotFound{ErrorModule::PM, 1};
+[[maybe_unused]] constexpr ResultCode ResultAlreadyStarted{ErrorModule::PM, 2};
+[[maybe_unused]] constexpr ResultCode ResultNotTerminated{ErrorModule::PM, 3};
+[[maybe_unused]] constexpr ResultCode ResultDebugHookInUse{ErrorModule::PM, 4};
+[[maybe_unused]] constexpr ResultCode ResultApplicationRunning{ErrorModule::PM, 5};
+[[maybe_unused]] constexpr ResultCode ResultInvalidSize{ErrorModule::PM, 6};
constexpr u64 NO_PROCESS_FOUND_PID{0};
@@ -95,18 +100,18 @@ public:
private:
void GetProcessId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto title_id = rp.PopRaw<u64>();
+ const auto program_id = rp.PopRaw<u64>();
- LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id);
+ LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
const auto process =
- SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) {
- return proc->GetProgramID() == title_id;
+ SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) {
+ return proc->GetProgramID() == program_id;
});
if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_PROCESS_NOT_FOUND);
+ rb.Push(ResultProcessNotFound);
return;
}
@@ -128,13 +133,16 @@ public:
explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_)
: ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
static const FunctionInfo functions[] = {
- {0, &Info::GetTitleId, "GetTitleId"},
+ {0, &Info::GetProgramId, "GetProgramId"},
+ {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"},
+ {65001, nullptr, "AtmosphereHasLaunchedProgram"},
+ {65002, nullptr, "AtmosphereGetProcessInfo"},
};
RegisterHandlers(functions);
}
private:
- void GetTitleId(Kernel::HLERequestContext& ctx) {
+ void GetProgramId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
@@ -146,7 +154,7 @@ private:
if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_PROCESS_NOT_FOUND);
+ rb.Push(ResultProcessNotFound);
return;
}
@@ -155,6 +163,27 @@ private:
rb.Push((*process)->GetProgramID());
}
+ void AtmosphereGetProcessId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto program_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
+
+ const auto process = SearchProcessList(process_list, [program_id](const auto& proc) {
+ return proc->GetProgramID() == program_id;
+ });
+
+ if (!process.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultProcessNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push((*process)->GetProcessID());
+ }
+
const std::vector<Kernel::KProcess*>& process_list;
};
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 {
S8_UINT_Z24_UNORM = 0x14,
D24X8_UNORM = 0x15,
D24S8_UNORM = 0x16,
+ S8_UINT = 0x17,
D24C8_UNORM = 0x18,
D32_FLOAT_S8X24_UINT = 0x19,
};
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
astc_decoder.comp
block_linear_unswizzle_2d.comp
block_linear_unswizzle_3d.comp
+ convert_abgr8_to_d24s8.frag
+ convert_b10g11r11_to_d24s8.frag
+ convert_d24s8_to_abgr8.frag
+ convert_d24s8_to_b10g11r11.frag
+ convert_d24s8_to_r16g16.frag
convert_depth_to_float.frag
convert_float_to_depth.frag
+ convert_r16g16_to_d24s8.frag
full_screen_triangle.vert
fxaa.frag
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+#extension GL_ARB_shader_stencil_export : require
+
+layout(binding = 0) uniform sampler2D color_texture;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ uvec4 color = uvec4(texelFetch(color_texture, coord, 0).rgba * (exp2(8) - 1.0f));
+ uint depth_unorm = (color.r << 16) | (color.g << 8) | color.b;
+
+ gl_FragDepth = float(depth_unorm) / (exp2(24.0) - 1.0f);
+ gl_FragStencilRefARB = int(color.a);
+}
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+#extension GL_ARB_shader_stencil_export : require
+
+layout(binding = 0) uniform sampler2D color_texture;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ vec4 color = texelFetch(color_texture, coord, 0).rgba;
+ uint depth_stencil_unorm = (uint(color.b * (exp2(10) - 1.0f)) << 22)
+ | (uint(color.g * (exp2(11) - 1.0f)) << 11)
+ | (uint(color.r * (exp2(11) - 1.0f)));
+
+ gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
+ gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
+}
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+
+layout(binding = 0) uniform sampler2D depth_tex;
+layout(binding = 1) uniform isampler2D stencil_tex;
+
+layout(location = 0) out vec4 color;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
+ uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
+
+ color.r = float(depth >> 16) / (exp2(8) - 1.0);
+ color.g = float((depth >> 8) & 0x00FF) / (exp2(8) - 1.0);
+ color.b = float(depth & 0x00FF) / (exp2(8) - 1.0);
+ color.a = float(stencil) / (exp2(8) - 1.0);
+}
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+
+layout(binding = 0) uniform sampler2D depth_tex;
+layout(binding = 1) uniform isampler2D stencil_tex;
+
+layout(location = 0) out vec4 color;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
+ uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
+
+ color.b = float(depth >> 22) / (exp2(10) - 1.0);
+ color.g = float((depth >> 11) & 0x00FF) / (exp2(11) - 1.0);
+ color.r = float(depth & 0x00FF) / (exp2(11) - 1.0);
+ color.a = 1.0f;
+}
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+
+layout(binding = 0) uniform sampler2D depth_tex;
+layout(binding = 1) uniform isampler2D stencil_tex;
+
+layout(location = 0) out vec4 color;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
+ uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
+
+ color.r = float(depth >> 16) / (exp2(16) - 1.0);
+ color.g = float((depth >> 16) & 0x00FF) / (exp2(16) - 1.0);
+ color.b = 0.0f;
+ color.a = 1.0f;
+}
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+#extension GL_ARB_shader_stencil_export : require
+
+layout(binding = 0) uniform sampler2D color_texture;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ vec4 color = texelFetch(color_texture, coord, 0).rgba;
+ uint depth_stencil_unorm = (uint(color.r * (exp2(16) - 1.0f)) << 16)
+ | (uint(color.g * (exp2(16) - 1.0f)) << 16);
+
+ gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
+ gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
+}
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 @@
#include <glad/glad.h>
+#include "common/bit_util.h"
#include "common/literals.h"
#include "common/settings.h"
#include "video_core/renderer_opengl/gl_device.h"
@@ -148,6 +149,8 @@ GLenum AttachmentType(PixelFormat format) {
switch (const SurfaceType type = VideoCore::Surface::GetFormatType(format); type) {
case SurfaceType::Depth:
return GL_DEPTH_ATTACHMENT;
+ case SurfaceType::Stencil:
+ return GL_STENCIL_ATTACHMENT;
case SurfaceType::DepthStencil:
return GL_DEPTH_STENCIL_ATTACHMENT;
default:
@@ -317,13 +320,12 @@ void AttachTexture(GLuint fbo, GLenum attachment, const ImageView* image_view) {
}
}
-OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_format) {
+OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_format,
+ GLsizei gl_num_levels) {
const GLenum target = ImageTarget(info);
const GLsizei width = info.size.width;
const GLsizei height = info.size.height;
const GLsizei depth = info.size.depth;
- const int max_host_mip_levels = std::bit_width(info.size.width);
- const GLsizei num_levels = std::min(info.resources.levels, max_host_mip_levels);
const GLsizei num_layers = info.resources.layers;
const GLsizei num_samples = info.num_samples;
@@ -335,10 +337,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
}
switch (target) {
case GL_TEXTURE_1D_ARRAY:
- glTextureStorage2D(handle, num_levels, gl_internal_format, width, num_layers);
+ glTextureStorage2D(handle, gl_num_levels, gl_internal_format, width, num_layers);
break;
case GL_TEXTURE_2D_ARRAY:
- glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, num_layers);
+ glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, num_layers);
break;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: {
// TODO: Where should 'fixedsamplelocations' come from?
@@ -348,10 +350,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
break;
}
case GL_TEXTURE_RECTANGLE:
- glTextureStorage2D(handle, num_levels, gl_internal_format, width, height);
+ glTextureStorage2D(handle, gl_num_levels, gl_internal_format, width, height);
break;
case GL_TEXTURE_3D:
- glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, depth);
+ glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, depth);
break;
case GL_TEXTURE_BUFFER:
UNREACHABLE();
@@ -396,6 +398,7 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
UNREACHABLE_MSG("Invalid image format={}", format);
return GL_R32UI;
}
+
} // Anonymous namespace
ImageBufferMap::~ImageBufferMap() {
@@ -522,6 +525,12 @@ void TextureCacheRuntime::CopyImage(Image& dst_image, Image& src_image,
}
}
+void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
+ std::span<const VideoCommon::ImageCopy> copies) {
+ LOG_DEBUG(Render_OpenGL, "Converting {} to {}", src.info.format, dst.info.format);
+ format_conversion_pass.ConvertImage(dst, src, copies);
+}
+
bool TextureCacheRuntime::CanImageBeCopied(const Image& dst, const Image& src) {
if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) {
return false;
@@ -538,7 +547,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src,
ASSERT(src.info.type == ImageType::e3D);
util_shaders.CopyBC4(dst, src, copies);
} else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) {
- bgr_copy_pass.CopyBGR(dst, src, copies);
+ format_conversion_pass.ConvertImage(dst, src, copies);
} else {
UNREACHABLE();
}
@@ -686,7 +695,9 @@ Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_,
gl_format = tuple.format;
gl_type = tuple.type;
}
- texture = MakeImage(info, gl_internal_format);
+ const int max_host_mip_levels = std::bit_width(info.size.width);
+ gl_num_levels = std::min(info.resources.levels, max_host_mip_levels);
+ texture = MakeImage(info, gl_internal_format, gl_num_levels);
current_texture = texture.handle;
if (runtime->device.HasDebuggingToolAttached()) {
const std::string name = VideoCommon::Name(*this);
@@ -714,6 +725,9 @@ void Image::UploadMemory(const ImageBufferMap& map,
u32 current_image_height = std::numeric_limits<u32>::max();
for (const VideoCommon::BufferImageCopy& copy : copies) {
+ if (copy.image_subresource.base_level >= gl_num_levels) {
+ continue;
+ }
if (current_row_length != copy.buffer_row_length) {
current_row_length = copy.buffer_row_length;
glPixelStorei(GL_UNPACK_ROW_LENGTH, current_row_length);
@@ -743,6 +757,9 @@ void Image::DownloadMemory(ImageBufferMap& map,
u32 current_image_height = std::numeric_limits<u32>::max();
for (const VideoCommon::BufferImageCopy& copy : copies) {
+ if (copy.image_subresource.base_level >= gl_num_levels) {
+ continue;
+ }
if (current_row_length != copy.buffer_row_length) {
current_row_length = copy.buffer_row_length;
glPixelStorei(GL_PACK_ROW_LENGTH, current_row_length);
@@ -782,7 +799,7 @@ GLuint Image::StorageHandle() noexcept {
}
store_view.Create();
glTextureView(store_view.handle, ImageTarget(info), current_texture, GL_RGBA8, 0,
- info.resources.levels, 0, info.resources.layers);
+ gl_num_levels, 0, info.resources.layers);
return store_view.handle;
default:
return current_texture;
@@ -897,6 +914,8 @@ void Image::Scale(bool up_scale) {
return GL_COLOR_ATTACHMENT0;
case SurfaceType::Depth:
return GL_DEPTH_ATTACHMENT;
+ case SurfaceType::Stencil:
+ return GL_STENCIL_ATTACHMENT;
case SurfaceType::DepthStencil:
return GL_DEPTH_STENCIL_ATTACHMENT;
default:
@@ -910,8 +929,10 @@ void Image::Scale(bool up_scale) {
return GL_COLOR_BUFFER_BIT;
case SurfaceType::Depth:
return GL_DEPTH_BUFFER_BIT;
+ case SurfaceType::Stencil:
+ return GL_STENCIL_BUFFER_BIT;
case SurfaceType::DepthStencil:
- return GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
+ return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
default:
UNREACHABLE();
return GL_COLOR_BUFFER_BIT;
@@ -923,8 +944,10 @@ void Image::Scale(bool up_scale) {
return 0;
case SurfaceType::Depth:
return 1;
- case SurfaceType::DepthStencil:
+ case SurfaceType::Stencil:
return 2;
+ case SurfaceType::DepthStencil:
+ return 3;
default:
UNREACHABLE();
return 0;
@@ -946,7 +969,7 @@ void Image::Scale(bool up_scale) {
auto dst_info = info;
dst_info.size.width = scaled_width;
dst_info.size.height = scaled_height;
- upscaled_backup = MakeImage(dst_info, gl_internal_format);
+ upscaled_backup = MakeImage(dst_info, gl_internal_format, gl_num_levels);
}
const u32 src_width = up_scale ? original_width : scaled_width;
const u32 src_height = up_scale ? original_height : scaled_height;
@@ -1254,10 +1277,20 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
}
if (const ImageView* const image_view = depth_buffer; image_view) {
- if (GetFormatType(image_view->format) == SurfaceType::DepthStencil) {
+ switch (GetFormatType(image_view->format)) {
+ case SurfaceType::Depth:
+ buffer_bits |= GL_DEPTH_BUFFER_BIT;
+ break;
+ case SurfaceType::Stencil:
+ buffer_bits |= GL_STENCIL_BUFFER_BIT;
+ break;
+ case SurfaceType::DepthStencil:
buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
- } else {
+ break;
+ default:
+ UNREACHABLE();
buffer_bits |= GL_DEPTH_BUFFER_BIT;
+ break;
}
const GLenum attachment = AttachmentType(image_view->format);
AttachTexture(handle, attachment, image_view);
@@ -1286,35 +1319,37 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
Framebuffer::~Framebuffer() = default;
-void BGRCopyPass::CopyBGR(Image& dst_image, Image& src_image,
- std::span<const VideoCommon::ImageCopy> copies) {
- static constexpr VideoCommon::Offset3D zero_offset{0, 0, 0};
+void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,
+ std::span<const VideoCommon::ImageCopy> copies) {
+ const GLenum dst_target = ImageTarget(dst_image.info);
+ const GLenum src_target = ImageTarget(src_image.info);
const u32 img_bpp = BytesPerBlock(src_image.info.format);
for (const ImageCopy& copy : copies) {
- ASSERT(copy.src_offset == zero_offset);
- ASSERT(copy.dst_offset == zero_offset);
- const u32 num_src_layers = static_cast<u32>(copy.src_subresource.num_layers);
- const u32 copy_size = copy.extent.width * copy.extent.height * num_src_layers * img_bpp;
- if (bgr_pbo_size < copy_size) {
- bgr_pbo.Create();
- bgr_pbo_size = copy_size;
- glNamedBufferData(bgr_pbo.handle, bgr_pbo_size, nullptr, GL_STREAM_COPY);
+ const auto src_origin = MakeCopyOrigin(copy.src_offset, copy.src_subresource, src_target);
+ const auto dst_origin = MakeCopyOrigin(copy.dst_offset, copy.dst_subresource, dst_target);
+ const auto region = MakeCopyRegion(copy.extent, copy.dst_subresource, dst_target);
+ const u32 copy_size = region.width * region.height * region.depth * img_bpp;
+ if (pbo_size < copy_size) {
+ intermediate_pbo.Create();
+ pbo_size = Common::NextPow2(copy_size);
+ glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY);
}
// Copy from source to PBO
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width);
- glBindBuffer(GL_PIXEL_PACK_BUFFER, bgr_pbo.handle);
- glGetTextureSubImage(src_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height,
- num_src_layers, src_image.GlFormat(), src_image.GlType(),
- static_cast<GLsizei>(bgr_pbo_size), nullptr);
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, intermediate_pbo.handle);
+ glGetTextureSubImage(src_image.Handle(), src_origin.level, src_origin.x, src_origin.y,
+ src_origin.z, region.width, region.height, region.depth,
+ src_image.GlFormat(), src_image.GlType(),
+ static_cast<GLsizei>(pbo_size), nullptr);
// Copy from PBO to destination in desired GL format
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bgr_pbo.handle);
- glTextureSubImage3D(dst_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height,
- copy.dst_subresource.num_layers, dst_image.GlFormat(),
- dst_image.GlType(), nullptr);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, intermediate_pbo.handle);
+ glTextureSubImage3D(dst_image.Handle(), dst_origin.level, dst_origin.x, dst_origin.y,
+ dst_origin.z, region.width, region.height, region.depth,
+ dst_image.GlFormat(), dst_image.GlType(), nullptr);
}
}
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 {
bool is_compressed;
};
-class BGRCopyPass {
+class FormatConversionPass {
public:
- BGRCopyPass() = default;
- ~BGRCopyPass() = default;
+ FormatConversionPass() = default;
+ ~FormatConversionPass() = default;
- void CopyBGR(Image& dst_image, Image& src_image,
- std::span<const VideoCommon::ImageCopy> copies);
+ void ConvertImage(Image& dst_image, Image& src_image,
+ std::span<const VideoCommon::ImageCopy> copies);
private:
- OGLBuffer bgr_pbo;
- size_t bgr_pbo_size{};
+ OGLBuffer intermediate_pbo;
+ size_t pbo_size{};
};
class TextureCacheRuntime {
@@ -84,8 +84,14 @@ public:
u64 GetDeviceLocalMemory() const;
+ bool ShouldReinterpret([[maybe_unused]] Image& dst, [[maybe_unused]] Image& src) {
+ return true;
+ }
+
void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
+ void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
+
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) {
UNIMPLEMENTED();
}
@@ -144,7 +150,7 @@ private:
const Device& device;
StateTracker& state_tracker;
UtilShaders util_shaders;
- BGRCopyPass bgr_copy_pass;
+ FormatConversionPass format_conversion_pass;
std::array<std::unordered_map<GLenum, FormatProperties>, 3> format_properties;
bool has_broken_texture_view_formats = false;
@@ -162,8 +168,8 @@ private:
std::array<GLuint, Shader::NUM_TEXTURE_TYPES> null_image_views{};
- std::array<OGLFramebuffer, 3> rescale_draw_fbos;
- std::array<OGLFramebuffer, 3> rescale_read_fbos;
+ std::array<OGLFramebuffer, 4> rescale_draw_fbos;
+ std::array<OGLFramebuffer, 4> rescale_read_fbos;
const Settings::ResolutionScalingInfo& resolution;
};
@@ -219,6 +225,7 @@ private:
GLenum gl_internal_format = GL_NONE;
GLenum gl_format = GL_NONE;
GLenum gl_type = GL_NONE;
+ GLsizei gl_num_levels{};
TextureCacheRuntime* runtime{};
GLuint current_texture{};
};
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
{GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM
+ {GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE}, // S8_UINT
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM
{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 @@
#include <algorithm>
+#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
+#include "video_core/host_shaders/convert_b10g11r11_to_d24s8_frag_spv.h"
+#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
+#include "video_core/host_shaders/convert_d24s8_to_b10g11r11_frag_spv.h"
+#include "video_core/host_shaders/convert_d24s8_to_r16g16_frag_spv.h"
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
+#include "video_core/host_shaders/convert_r16g16_to_d24s8_frag_spv.h"
#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
#include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h"
#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
@@ -354,6 +360,12 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)),
convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
+ convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
+ convert_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)),
+ convert_r16g16_to_d24s8_frag(BuildShader(device, CONVERT_R16G16_TO_D24S8_FRAG_SPV)),
+ convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
+ convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)),
+ convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)),
linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {
if (device.IsExtShaderStencilExportSupported()) {
@@ -448,6 +460,59 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
}
+void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
+ const ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
+ convert_abgr8_to_d24s8_frag, true);
+ Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
+ down_shift);
+}
+
+void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
+ const ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineDepthTargetEx(convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
+ convert_b10g11r11_to_d24s8_frag, true);
+ Convert(*convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
+ down_shift);
+}
+
+void BlitImageHelper::ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer,
+ const ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineDepthTargetEx(convert_r16g16_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
+ convert_r16g16_to_d24s8_frag, true);
+ Convert(*convert_r16g16_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
+ down_shift);
+}
+
+void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale, u32 down_shift) {
+ ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
+ convert_d24s8_to_abgr8_frag, false);
+ ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view, up_scale,
+ down_shift);
+}
+
+void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineColorTargetEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(),
+ convert_d24s8_to_b10g11r11_frag, false);
+ ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view,
+ up_scale, down_shift);
+}
+
+void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineColorTargetEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(),
+ convert_d24s8_to_r16g16_frag, false);
+ ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view,
+ up_scale, down_shift);
+}
+
void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale, u32 down_shift) {
const VkPipelineLayout layout = *one_texture_pipeline_layout;
@@ -495,6 +560,54 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb
scheduler.InvalidateState();
}
+void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale, u32 down_shift) {
+ const VkPipelineLayout layout = *two_textures_pipeline_layout;
+ const VkImageView src_depth_view = src_image_view.DepthView();
+ const VkImageView src_stencil_view = src_image_view.StencilView();
+ const VkSampler sampler = *nearest_sampler;
+ const VkExtent2D extent{
+ .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U),
+ .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U),
+ };
+ scheduler.RequestRenderpass(dst_framebuffer);
+ scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, up_scale,
+ down_shift, this](vk::CommandBuffer cmdbuf) {
+ const VkOffset2D offset{
+ .x = 0,
+ .y = 0,
+ };
+ const VkViewport viewport{
+ .x = 0.0f,
+ .y = 0.0f,
+ .width = static_cast<float>(extent.width),
+ .height = static_cast<float>(extent.height),
+ .minDepth = 0.0f,
+ .maxDepth = 0.0f,
+ };
+ const VkRect2D scissor{
+ .offset = offset,
+ .extent = extent,
+ };
+ const PushConstants push_constants{
+ .tex_scale = {viewport.width, viewport.height},
+ .tex_offset = {0.0f, 0.0f},
+ };
+ const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
+ UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
+ src_stencil_view);
+ // TODO: Barriers
+ cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
+ nullptr);
+ cmdbuf.SetViewport(0, viewport);
+ cmdbuf.SetScissor(0, scissor);
+ cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
+ cmdbuf.Draw(3, 1, 0, 0);
+ });
+ scheduler.InvalidateState();
+}
+
VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) {
const auto it = std::ranges::find(blit_color_keys, key);
if (it != blit_color_keys.end()) {
@@ -636,4 +749,62 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
});
}
+void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture) {
+ if (pipeline) {
+ return;
+ }
+ const std::array stages = MakeStages(*full_screen_vert, *module);
+ pipeline = device.GetLogical().CreateGraphicsPipeline({
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .stageCount = static_cast<u32>(stages.size()),
+ .pStages = stages.data(),
+ .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .pTessellationState = nullptr,
+ .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .pDepthStencilState = nullptr,
+ .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
+ .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
+ .renderPass = renderpass,
+ .subpass = 0,
+ .basePipelineHandle = VK_NULL_HANDLE,
+ .basePipelineIndex = 0,
+ });
+}
+
+void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture) {
+ if (pipeline) {
+ return;
+ }
+ const std::array stages = MakeStages(*full_screen_vert, *module);
+ pipeline = device.GetLogical().CreateGraphicsPipeline({
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .stageCount = static_cast<u32>(stages.size()),
+ .pStages = stages.data(),
+ .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .pTessellationState = nullptr,
+ .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+ .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
+ .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
+ .renderPass = renderpass,
+ .subpass = 0,
+ .basePipelineHandle = VK_NULL_HANDLE,
+ .basePipelineIndex = 0,
+ });
+}
+
} // 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:
void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
u32 up_scale, u32 down_shift);
+ void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
+ void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
+ const ImageView& src_image_view, u32 up_scale, u32 down_shift);
+
+ void ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
+ void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
+ void ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
+ void ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
private:
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale, u32 down_shift);
+ void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale, u32 down_shift);
+
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key);
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
@@ -68,6 +89,12 @@ private:
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
+ void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture);
+
+ void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture);
+
const Device& device;
VKScheduler& scheduler;
StateTracker& state_tracker;
@@ -83,6 +110,12 @@ private:
vk::ShaderModule blit_depth_stencil_frag;
vk::ShaderModule convert_depth_to_float_frag;
vk::ShaderModule convert_float_to_depth_frag;
+ vk::ShaderModule convert_abgr8_to_d24s8_frag;
+ vk::ShaderModule convert_b10g11r11_to_d24s8_frag;
+ vk::ShaderModule convert_r16g16_to_d24s8_frag;
+ vk::ShaderModule convert_d24s8_to_abgr8_frag;
+ vk::ShaderModule convert_d24s8_to_b10g11r11_frag;
+ vk::ShaderModule convert_d24s8_to_r16g16_frag;
vk::Sampler linear_sampler;
vk::Sampler nearest_sampler;
@@ -94,6 +127,12 @@ private:
vk::Pipeline convert_r32_to_d32_pipeline;
vk::Pipeline convert_d16_to_r16_pipeline;
vk::Pipeline convert_r16_to_d16_pipeline;
+ vk::Pipeline convert_abgr8_to_d24s8_pipeline;
+ vk::Pipeline convert_b10g11r11_to_d24s8_pipeline;
+ vk::Pipeline convert_r16g16_to_d24s8_pipeline;
+ vk::Pipeline convert_d24s8_to_abgr8_pipeline;
+ vk::Pipeline convert_d24s8_to_b10g11r11_pipeline;
+ vk::Pipeline convert_d24s8_to_r16g16_pipeline;
};
} // 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 {
{VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT
{VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM
+ // Stencil formats
+ {VK_FORMAT_S8_UINT, Attachable}, // S8_UINT
+
// DepthStencil formats
{VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // D24_UNORM_S8_UINT
{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 @@
#include <vector>
#include "common/bit_cast.h"
+#include "common/bit_util.h"
#include "common/settings.h"
#include "video_core/engines/fermi_2d.h"
@@ -102,6 +103,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case VideoCore::Surface::SurfaceType::Depth:
+ case VideoCore::Surface::SurfaceType::Stencil:
case VideoCore::Surface::SurfaceType::DepthStencil:
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
@@ -173,6 +175,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
return VK_IMAGE_ASPECT_COLOR_BIT;
case VideoCore::Surface::SurfaceType::Depth:
return VK_IMAGE_ASPECT_DEPTH_BIT;
+ case VideoCore::Surface::SurfaceType::Stencil:
+ return VK_IMAGE_ASPECT_STENCIL_BIT;
case VideoCore::Surface::SurfaceType::DepthStencil:
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
default:
@@ -195,6 +199,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
case PixelFormat::D16_UNORM:
case PixelFormat::D32_FLOAT:
return VK_IMAGE_ASPECT_DEPTH_BIT;
+ case PixelFormat::S8_UINT:
+ return VK_IMAGE_ASPECT_STENCIL_BIT;
default:
return VK_IMAGE_ASPECT_COLOR_BIT;
}
@@ -308,6 +314,19 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
};
}
+[[nodiscard]] VkBufferImageCopy MakeBufferImageCopy(const VideoCommon::ImageCopy& copy, bool is_src,
+ VkImageAspectFlags aspect_mask) noexcept {
+ return VkBufferImageCopy{
+ .bufferOffset = 0,
+ .bufferRowLength = 0,
+ .bufferImageHeight = 0,
+ .imageSubresource = MakeImageSubresourceLayers(
+ is_src ? copy.src_subresource : copy.dst_subresource, aspect_mask),
+ .imageOffset = MakeOffset3D(is_src ? copy.src_offset : copy.dst_offset),
+ .imageExtent = MakeExtent3D(copy.extent),
+ };
+}
+
[[maybe_unused]] [[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies(
std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) {
std::vector<VkBufferCopy> result(copies.size());
@@ -754,6 +773,163 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
return staging_buffer_pool.Request(size, MemoryUsage::Download);
}
+bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
+ if (VideoCore::Surface::GetFormatType(dst.info.format) ==
+ VideoCore::Surface::SurfaceType::DepthStencil) {
+ return !device.IsExtShaderStencilExportSupported();
+ }
+ return false;
+}
+
+VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
+ const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL);
+ if (buffer_commits[level]) {
+ return *buffers[level];
+ }
+ const auto new_size = Common::NextPow2(needed_size);
+ VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
+ VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
+ VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+ buffers[level] = device.GetLogical().CreateBuffer({
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .size = new_size,
+ .usage = flags,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .queueFamilyIndexCount = 0,
+ .pQueueFamilyIndices = nullptr,
+ });
+ buffer_commits[level] = std::make_unique<MemoryCommit>(
+ memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal));
+ return *buffers[level];
+}
+
+void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
+ std::span<const VideoCommon::ImageCopy> copies) {
+ std::vector<VkBufferImageCopy> vk_in_copies(copies.size());
+ std::vector<VkBufferImageCopy> vk_out_copies(copies.size());
+ const VkImageAspectFlags src_aspect_mask = src.AspectMask();
+ const VkImageAspectFlags dst_aspect_mask = dst.AspectMask();
+
+ std::ranges::transform(copies, vk_in_copies.begin(), [src_aspect_mask](const auto& copy) {
+ return MakeBufferImageCopy(copy, true, src_aspect_mask);
+ });
+ std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) {
+ return MakeBufferImageCopy(copy, false, dst_aspect_mask);
+ });
+ const u32 img_bpp = BytesPerBlock(src.info.format);
+ size_t total_size = 0;
+ for (const auto& copy : copies) {
+ total_size += copy.extent.width * copy.extent.height * copy.extent.depth * img_bpp;
+ }
+ const VkBuffer copy_buffer = GetTemporaryBuffer(total_size);
+ const VkImage dst_image = dst.Handle();
+ const VkImage src_image = src.Handle();
+ scheduler.RequestOutsideRenderPassOperationContext();
+ scheduler.Record([dst_image, src_image, copy_buffer, src_aspect_mask, dst_aspect_mask,
+ vk_in_copies, vk_out_copies](vk::CommandBuffer cmdbuf) {
+ RangedBarrierRange dst_range;
+ RangedBarrierRange src_range;
+ for (const VkBufferImageCopy& copy : vk_in_copies) {
+ src_range.AddLayers(copy.imageSubresource);
+ }
+ for (const VkBufferImageCopy& copy : vk_out_copies) {
+ dst_range.AddLayers(copy.imageSubresource);
+ }
+ static constexpr VkMemoryBarrier READ_BARRIER{
+ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
+ };
+ static constexpr VkMemoryBarrier WRITE_BARRIER{
+ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
+ };
+ const std::array pre_barriers{
+ VkImageMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = src_image,
+ .subresourceRange = src_range.SubresourceRange(src_aspect_mask),
+ },
+ };
+ const std::array middle_in_barrier{
+ VkImageMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = 0,
+ .dstAccessMask = 0,
+ .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = src_image,
+ .subresourceRange = src_range.SubresourceRange(src_aspect_mask),
+ },
+ };
+ const std::array middle_out_barrier{
+ VkImageMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = dst_image,
+ .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
+ },
+ };
+ const std::array post_barriers{
+ VkImageMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = dst_image,
+ .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
+ },
+ };
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0, {}, {}, pre_barriers);
+
+ cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer,
+ vk_in_copies);
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ 0, WRITE_BARRIER, nullptr, middle_in_barrier);
+
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0, READ_BARRIER, {}, middle_out_barrier);
+ cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies);
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ 0, {}, {}, post_barriers);
+ });
+}
+
void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
@@ -881,6 +1057,22 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift);
}
break;
+ case PixelFormat::A8B8G8R8_UNORM:
+ case PixelFormat::B8G8R8A8_UNORM:
+ if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
+ return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift);
+ }
+ break;
+ case PixelFormat::B10G11R11_FLOAT:
+ if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
+ return blit_image_helper.ConvertD24S8ToB10G11R11(dst, src_view, up_scale, down_shift);
+ }
+ break;
+ case PixelFormat::R16G16_UNORM:
+ if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
+ return blit_image_helper.ConvertD24S8ToR16G16(dst, src_view, up_scale, down_shift);
+ }
+ break;
case PixelFormat::R32_FLOAT:
if (src_view.format == PixelFormat::D32_FLOAT) {
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
return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift);
}
break;
+ case PixelFormat::S8_UINT_D24_UNORM:
+ if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
+ src_view.format == PixelFormat::B8G8R8A8_UNORM) {
+ return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift);
+ }
+ if (src_view.format == PixelFormat::B10G11R11_FLOAT) {
+ return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift);
+ }
+ if (src_view.format == PixelFormat::R16G16_UNORM) {
+ return blit_image_helper.ConvertR16G16ToD24S8(dst, src_view, up_scale, down_shift);
+ }
+ break;
case PixelFormat::D32_FLOAT:
if (src_view.format == PixelFormat::R32_FLOAT) {
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:
void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
+ bool ShouldReinterpret(Image& dst, Image& src);
+
+ void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
+
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled);
bool CanAccelerateImageUpload(Image&) const noexcept {
@@ -82,6 +86,8 @@ public:
return true;
}
+ [[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size);
+
const Device& device;
VKScheduler& scheduler;
MemoryAllocator& memory_allocator;
@@ -90,6 +96,10 @@ public:
ASTCDecoderPass& astc_decoder_pass;
RenderPassCache& render_pass_cache;
const Settings::ResolutionScalingInfo& resolution;
+
+ constexpr static size_t indexing_slots = 8 * sizeof(size_t);
+ std::array<vk::Buffer, indexing_slots> buffers{};
+ std::array<std::unique_ptr<MemoryCommit>, indexing_slots> buffer_commits{};
};
class 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) {
return PixelFormat::D32_FLOAT;
case Tegra::DepthFormat::D16_UNORM:
return PixelFormat::D16_UNORM;
+ case Tegra::DepthFormat::S8_UINT:
+ return PixelFormat::S8_UINT;
case Tegra::DepthFormat::D32_FLOAT_S8X24_UINT:
return PixelFormat::D32_FLOAT_S8_UINT;
default:
@@ -214,6 +216,11 @@ SurfaceType GetFormatType(PixelFormat pixel_format) {
}
if (static_cast<std::size_t>(pixel_format) <
+ static_cast<std::size_t>(PixelFormat::MaxStencilFormat)) {
+ return SurfaceType::Stencil;
+ }
+
+ if (static_cast<std::size_t>(pixel_format) <
static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
return SurfaceType::DepthStencil;
}
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 {
MaxDepthFormat,
+ // Stencil formats
+ S8_UINT = MaxDepthFormat,
+ MaxStencilFormat,
+
// DepthStencil formats
- D24_UNORM_S8_UINT = MaxDepthFormat,
+ D24_UNORM_S8_UINT = MaxStencilFormat,
S8_UINT_D24_UNORM,
D32_FLOAT_S8_UINT,
@@ -125,8 +129,9 @@ constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max
enum class SurfaceType {
ColorTexture = 0,
Depth = 1,
- DepthStencil = 2,
- Invalid = 3,
+ Stencil = 2,
+ DepthStencil = 3,
+ Invalid = 4,
};
enum class SurfaceTarget {
@@ -229,6 +234,7 @@ constexpr std::array<u32, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
1, // E5B9G9R9_FLOAT
1, // D32_FLOAT
1, // D16_UNORM
+ 1, // S8_UINT
1, // D24_UNORM_S8_UINT
1, // S8_UINT_D24_UNORM
1, // D32_FLOAT_S8_UINT
@@ -328,6 +334,7 @@ constexpr std::array<u32, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
1, // E5B9G9R9_FLOAT
1, // D32_FLOAT
1, // D16_UNORM
+ 1, // S8_UINT
1, // D24_UNORM_S8_UINT
1, // S8_UINT_D24_UNORM
1, // D32_FLOAT_S8_UINT
@@ -427,6 +434,7 @@ constexpr std::array<u32, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
32, // E5B9G9R9_FLOAT
32, // D32_FLOAT
16, // D16_UNORM
+ 8, // S8_UINT
32, // D24_UNORM_S8_UINT
32, // S8_UINT_D24_UNORM
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
return "D32_FLOAT";
case PixelFormat::D16_UNORM:
return "D16_UNORM";
+ case PixelFormat::S8_UINT:
+ return "S8_UINT";
case PixelFormat::D24_UNORM_S8_UINT:
return "D24_UNORM_S8_UINT";
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,
const BlitImages images = GetBlitImages(dst, src);
const ImageId dst_id = images.dst_id;
const ImageId src_id = images.src_id;
+
PrepareImage(src_id, false, false);
PrepareImage(dst_id, true, false);
@@ -758,7 +759,8 @@ ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
return ImageId{};
}
}
- const bool broken_views = runtime.HasBrokenTextureViewFormats();
+ const bool broken_views =
+ runtime.HasBrokenTextureViewFormats() || True(options & RelaxedOptions::ForceBrokenViews);
const bool native_bgr = runtime.HasNativeBgr();
ImageId image_id;
const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) {
@@ -1094,12 +1096,13 @@ typename TextureCache<P>::BlitImages TextureCache<P>::GetBlitImages(
if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) {
continue;
}
- if (!dst_id) {
- dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{});
- }
- if (!src_id) {
- src_id = InsertImage(src_info, src_addr, RelaxedOptions{});
+ RelaxedOptions find_options{};
+ if (src_info.num_samples > 1) {
+ // it's a resolve, we must enforce the same format.
+ find_options = RelaxedOptions::ForceBrokenViews;
}
+ src_id = FindOrInsertImage(src_info, src_addr, find_options);
+ dst_id = FindOrInsertImage(dst_info, dst_addr, find_options);
} while (has_deleted_images);
return BlitImages{
.dst_id = dst_id,
@@ -1759,6 +1762,9 @@ void TextureCache<P>::CopyImage(ImageId dst_id, ImageId src_id, std::vector<Imag
}
UNIMPLEMENTED_IF(dst.info.type != ImageType::e2D);
UNIMPLEMENTED_IF(src.info.type != ImageType::e2D);
+ if (runtime.ShouldReinterpret(dst, src)) {
+ return runtime.ReinterpretImage(dst, src, copies);
+ }
for (const ImageCopy& copy : copies) {
UNIMPLEMENTED_IF(copy.dst_subresource.num_layers != 1);
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 {
Size = 1 << 0,
Format = 1 << 1,
Samples = 1 << 2,
+ ForceBrokenViews = 1 << 3,
};
DECLARE_ENUM_FLAG_OPERATORS(RelaxedOptions)
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
void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst,
const ImageBase* src) {
- if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
- src_info.format = src->info.format;
+ bool is_resolve = false;
+ const auto original_src_format = src_info.format;
+ const auto original_dst_format = dst_info.format;
+ if (src) {
+ if (GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
+ src_info.format = src->info.format;
+ }
+ is_resolve = src->info.num_samples > 1;
+ src_info.num_samples = src->info.num_samples;
+ src_info.size = src->info.size;
}
if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
dst_info.format = dst->info.format;
}
if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
- dst_info.format = src->info.format;
+ if (dst) {
+ if (GetFormatType(dst->info.format) == SurfaceType::ColorTexture) {
+ src_info.format = original_src_format;
+ }
+ } else {
+ dst_info.format = src->info.format;
+ }
}
if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
- src_info.format = dst->info.format;
+ if (src) {
+ if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) {
+ dst_info.format = original_dst_format;
+ }
+ } else {
+ src_info.format = dst->info.format;
+ }
}
+ ASSERT(!is_resolve || dst_info.format == src_info.format);
}
u32 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 @@
namespace Vulkan {
namespace {
namespace Alternatives {
+constexpr std::array STENCIL8_UINT{
+ VK_FORMAT_D16_UNORM_S8_UINT,
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_D32_SFLOAT_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+};
+
constexpr std::array DEPTH24_UNORM_STENCIL8_UINT{
VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_D16_UNORM_S8_UINT,
@@ -74,6 +81,8 @@ void SetNext(void**& next, T& data) {
constexpr const VkFormat* GetFormatAlternatives(VkFormat format) {
switch (format) {
+ case VK_FORMAT_S8_UINT:
+ return Alternatives::STENCIL8_UINT.data();
case VK_FORMAT_D24_UNORM_S8_UINT:
return Alternatives::DEPTH24_UNORM_STENCIL8_UINT.data();
case VK_FORMAT_D16_UNORM_S8_UINT:
@@ -145,6 +154,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
VK_FORMAT_R4G4B4A4_UNORM_PACK16,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_D16_UNORM,
+ VK_FORMAT_S8_UINT,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D24_UNORM_S8_UINT,
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 @@
</item>
<item>
<property name="text">
- <string>AMD's FidelityFX™️ Super Resolution [Vulkan Only]</string>
+ <string>AMD FidelityFX™️ Super Resolution [Vulkan Only]</string>
</property>
</item>
</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
if (!hk.shortcut)
hk.shortcut = new QShortcut(hk.keyseq, widget, nullptr, nullptr, hk.context);
+ hk.shortcut->setAutoRepeat(false);
+
return hk.shortcut;
}
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() {
&QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger);
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this),
&QShortcut::activated, this, [&] {
- if (emulation_running) {
+ if (emulation_running && ui->action_Fullscreen->isChecked()) {
ui->action_Fullscreen->setChecked(false);
ToggleFullscreen();
}
@@ -3106,7 +3106,7 @@ void GMainWindow::UpdateFilterText() {
filter_status_button->setText(tr("SCALEFORCE"));
break;
case Settings::ScalingFilter::Fsr:
- filter_status_button->setText(tr("AMD'S FIDELITYFX SR"));
+ filter_status_button->setText(tr("FSR"));
break;
default:
filter_status_button->setText(tr("BILINEAR"));
@@ -3117,15 +3117,15 @@ void GMainWindow::UpdateFilterText() {
void GMainWindow::UpdateAAText() {
const auto aa_mode = Settings::values.anti_aliasing.GetValue();
switch (aa_mode) {
- case Settings::AntiAliasing::Fxaa:
- aa_status_button->setText(tr("FXAA"));
- break;
case Settings::AntiAliasing::None:
aa_status_button->setText(tr("NO AA"));
break;
- default:
+ case Settings::AntiAliasing::Fxaa:
aa_status_button->setText(tr("FXAA"));
break;
+ default:
+ aa_status_button->setText(tr("NO AA"));
+ break;
}
}
@@ -3300,9 +3300,9 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
if (!errors.isEmpty()) {
QMessageBox::warning(
this, tr("Derivation Components Missing"),
- tr("Components are missing that may hinder key derivation from completing. "
+ tr("Encryption keys are missing. "
"<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu "
- "quickstart guide</a> to get all your keys and "
+ "quickstart guide</a> to get all your keys, firmware and "
"games.<br><br><small>(%1)</small>")
.arg(errors));
}