summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/jni/native.cpp4
-rw-r--r--src/common/settings.h2
-rw-r--r--src/core/core.cpp7
-rw-r--r--src/core/hle/service/am/am.cpp3
-rw-r--r--src/core/hle/service/am/applets/applet_mii_edit.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp41
-rw-r--r--src/core/hle/service/mii/mii_database_manager.cpp2
-rw-r--r--src/core/hle/service/mii/types/char_info.cpp2
-rw-r--r--src/core/hle/service/mii/types/core_data.cpp2
-rw-r--r--src/core/hle/service/nfc/common/device.cpp2
-rw-r--r--src/video_core/host_shaders/convert_msaa_to_non_msaa.comp7
-rw-r--r--src/video_core/host_shaders/convert_non_msaa_to_msaa.comp7
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp139
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h19
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp28
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp81
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h7
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp7
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h19
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp1
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h13
-rw-r--r--src/yuzu/main.cpp11
-rw-r--r--src/yuzu/main.h2
23 files changed, 350 insertions, 58 deletions
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 9fa082dd5..9cf71680c 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -141,10 +141,6 @@ public:
141 if (nsp->IsExtractedType()) { 141 if (nsp->IsExtractedType()) {
142 return InstallError; 142 return InstallError;
143 } 143 }
144 } else if (file_extension == "xci") {
145 jconst xci =
146 std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
147 nsp = xci->GetSecurePartitionNSP();
148 } else { 144 } else {
149 return ErrorFilenameExtension; 145 return ErrorFilenameExtension;
150 } 146 }
diff --git a/src/common/settings.h b/src/common/settings.h
index ae5e5d2b8..98ab0ec2e 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -351,6 +351,8 @@ struct Values {
351 linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug}; 351 linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug};
352 Setting<bool> enable_renderdoc_hotkey{linkage, false, "renderdoc_hotkey", 352 Setting<bool> enable_renderdoc_hotkey{linkage, false, "renderdoc_hotkey",
353 Category::RendererDebug}; 353 Category::RendererDebug};
354 // TODO: remove this once AMDVLK supports VK_EXT_depth_bias_control
355 bool renderer_amdvlk_depth_bias_workaround{};
354 356
355 // System 357 // System
356 SwitchableSetting<Language, true> language_index{linkage, 358 SwitchableSetting<Language, true> language_index{linkage,
diff --git a/src/core/core.cpp b/src/core/core.cpp
index e8300cd05..08cbb8978 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -381,6 +381,10 @@ struct System::Impl {
381 room_member->SendGameInfo(game_info); 381 room_member->SendGameInfo(game_info);
382 } 382 }
383 383
384 // Workarounds:
385 // Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK
386 Settings::values.renderer_amdvlk_depth_bias_workaround = program_id == 0x1006A800016E000ULL;
387
384 status = SystemResultStatus::Success; 388 status = SystemResultStatus::Success;
385 return status; 389 return status;
386 } 390 }
@@ -440,6 +444,9 @@ struct System::Impl {
440 room_member->SendGameInfo(game_info); 444 room_member->SendGameInfo(game_info);
441 } 445 }
442 446
447 // Workarounds
448 Settings::values.renderer_amdvlk_depth_bias_workaround = false;
449
443 LOG_DEBUG(Core, "Shutdown OK"); 450 LOG_DEBUG(Core, "Shutdown OK");
444 } 451 }
445 452
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index e9bd04842..a83622f7c 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -2094,9 +2094,6 @@ void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) {
2094 2094
2095void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { 2095void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
2096 auto message_queue = std::make_shared<AppletMessageQueue>(system); 2096 auto message_queue = std::make_shared<AppletMessageQueue>(system);
2097 // Needed on game boot
2098 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
2099
2100 auto server_manager = std::make_unique<ServerManager>(system); 2097 auto server_manager = std::make_unique<ServerManager>(system);
2101 2098
2102 server_manager->RegisterNamedService( 2099 server_manager->RegisterNamedService(
diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp
index ff77830d2..50adc7c02 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.cpp
+++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp
@@ -145,6 +145,8 @@ void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) {
145 .index{index}, 145 .index{index},
146 }; 146 };
147 147
148 LOG_INFO(Input, "called, result={}, index={}", result, index);
149
148 std::vector<u8> out_data(sizeof(MiiEditAppletOutput)); 150 std::vector<u8> out_data(sizeof(MiiEditAppletOutput));
149 std::memcpy(out_data.data(), &applet_output, sizeof(MiiEditAppletOutput)); 151 std::memcpy(out_data.data(), &applet_output, sizeof(MiiEditAppletOutput));
150 152
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 2492bbc16..c2054e8a0 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -329,6 +329,7 @@ public:
329 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, 329 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
330 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, 330 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
331 {15, nullptr, "QueryEntry"}, 331 {15, nullptr, "QueryEntry"},
332 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
332 }; 333 };
333 RegisterHandlers(functions); 334 RegisterHandlers(functions);
334 } 335 }
@@ -521,6 +522,46 @@ public:
521 rb.PushRaw(vfs_timestamp); 522 rb.PushRaw(vfs_timestamp);
522 } 523 }
523 524
525 void GetFileSystemAttribute(HLERequestContext& ctx) {
526 LOG_WARNING(Service_FS, "(STUBBED) called");
527
528 struct FileSystemAttribute {
529 u8 dir_entry_name_length_max_defined;
530 u8 file_entry_name_length_max_defined;
531 u8 dir_path_name_length_max_defined;
532 u8 file_path_name_length_max_defined;
533 INSERT_PADDING_BYTES_NOINIT(0x5);
534 u8 utf16_dir_entry_name_length_max_defined;
535 u8 utf16_file_entry_name_length_max_defined;
536 u8 utf16_dir_path_name_length_max_defined;
537 u8 utf16_file_path_name_length_max_defined;
538 INSERT_PADDING_BYTES_NOINIT(0x18);
539 s32 dir_entry_name_length_max;
540 s32 file_entry_name_length_max;
541 s32 dir_path_name_length_max;
542 s32 file_path_name_length_max;
543 INSERT_PADDING_WORDS_NOINIT(0x5);
544 s32 utf16_dir_entry_name_length_max;
545 s32 utf16_file_entry_name_length_max;
546 s32 utf16_dir_path_name_length_max;
547 s32 utf16_file_path_name_length_max;
548 INSERT_PADDING_WORDS_NOINIT(0x18);
549 INSERT_PADDING_WORDS_NOINIT(0x1);
550 };
551 static_assert(sizeof(FileSystemAttribute) == 0xc0,
552 "FileSystemAttribute has incorrect size");
553
554 FileSystemAttribute savedata_attribute{};
555 savedata_attribute.dir_entry_name_length_max_defined = true;
556 savedata_attribute.file_entry_name_length_max_defined = true;
557 savedata_attribute.dir_entry_name_length_max = 0x40;
558 savedata_attribute.file_entry_name_length_max = 0x40;
559
560 IPC::ResponseBuilder rb{ctx, 50};
561 rb.Push(ResultSuccess);
562 rb.PushRaw(savedata_attribute);
563 }
564
524private: 565private:
525 VfsDirectoryServiceWrapper backend; 566 VfsDirectoryServiceWrapper backend;
526 SizeGetter size; 567 SizeGetter size;
diff --git a/src/core/hle/service/mii/mii_database_manager.cpp b/src/core/hle/service/mii/mii_database_manager.cpp
index c39898594..0080b6705 100644
--- a/src/core/hle/service/mii/mii_database_manager.cpp
+++ b/src/core/hle/service/mii/mii_database_manager.cpp
@@ -168,7 +168,7 @@ Result DatabaseManager::FindIndex(s32& out_index, const Common::UUID& create_id,
168 return ResultSuccess; 168 return ResultSuccess;
169 } 169 }
170 170
171 for (std::size_t i = 0; i <= index; ++i) { 171 for (std::size_t i = 0; i < index; ++i) {
172 if (database.Get(i).IsSpecial()) { 172 if (database.Get(i).IsSpecial()) {
173 continue; 173 continue;
174 } 174 }
diff --git a/src/core/hle/service/mii/types/char_info.cpp b/src/core/hle/service/mii/types/char_info.cpp
index c82186c73..e90124af4 100644
--- a/src/core/hle/service/mii/types/char_info.cpp
+++ b/src/core/hle/service/mii/types/char_info.cpp
@@ -37,7 +37,7 @@ void CharInfo::SetFromStoreData(const StoreData& store_data) {
37 eyebrow_aspect = store_data.GetEyebrowAspect(); 37 eyebrow_aspect = store_data.GetEyebrowAspect();
38 eyebrow_rotate = store_data.GetEyebrowRotate(); 38 eyebrow_rotate = store_data.GetEyebrowRotate();
39 eyebrow_x = store_data.GetEyebrowX(); 39 eyebrow_x = store_data.GetEyebrowX();
40 eyebrow_y = store_data.GetEyebrowY(); 40 eyebrow_y = store_data.GetEyebrowY() + 3;
41 nose_type = store_data.GetNoseType(); 41 nose_type = store_data.GetNoseType();
42 nose_scale = store_data.GetNoseScale(); 42 nose_scale = store_data.GetNoseScale();
43 nose_y = store_data.GetNoseY(); 43 nose_y = store_data.GetNoseY();
diff --git a/src/core/hle/service/mii/types/core_data.cpp b/src/core/hle/service/mii/types/core_data.cpp
index 1068031e3..970c748ca 100644
--- a/src/core/hle/service/mii/types/core_data.cpp
+++ b/src/core/hle/service/mii/types/core_data.cpp
@@ -113,7 +113,7 @@ void CoreData::BuildRandom(Age age, Gender gender, Race race) {
113 .values[MiiUtil::GetRandomValue<std::size_t>(eyebrow_type_info.values_count)]); 113 .values[MiiUtil::GetRandomValue<std::size_t>(eyebrow_type_info.values_count)]);
114 114
115 const auto eyebrow_rotate_1{race == Race::Asian ? 6 : 0}; 115 const auto eyebrow_rotate_1{race == Race::Asian ? 6 : 0};
116 const auto eyebrow_y{race == Race::Asian ? 9 : 10}; 116 const auto eyebrow_y{race == Race::Asian ? 6 : 7};
117 const auto eyebrow_rotate_offset{32 - RawData::EyebrowRotateLookup[eyebrow_rotate_1] + 6}; 117 const auto eyebrow_rotate_offset{32 - RawData::EyebrowRotateLookup[eyebrow_rotate_1] + 6};
118 const auto eyebrow_rotate{ 118 const auto eyebrow_rotate{
119 32 - RawData::EyebrowRotateLookup[static_cast<std::size_t>(data.eyebrow_type.Value())]}; 119 32 - RawData::EyebrowRotateLookup[static_cast<std::size_t>(data.eyebrow_type.Value())]};
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 05951d8cb..68c407f81 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -1374,7 +1374,7 @@ NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) co
1374 1374
1375 // Convert from utf16 to utf8 1375 // Convert from utf16 to utf8
1376 const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data()); 1376 const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data());
1377 memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size() - 1); 1377 memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size());
1378 1378
1379 return amiibo_name; 1379 return amiibo_name;
1380} 1380}
diff --git a/src/video_core/host_shaders/convert_msaa_to_non_msaa.comp b/src/video_core/host_shaders/convert_msaa_to_non_msaa.comp
index fc3854d18..66f2ad483 100644
--- a/src/video_core/host_shaders/convert_msaa_to_non_msaa.comp
+++ b/src/video_core/host_shaders/convert_msaa_to_non_msaa.comp
@@ -15,11 +15,14 @@ void main() {
15 15
16 // TODO: Specialization constants for num_samples? 16 // TODO: Specialization constants for num_samples?
17 const int num_samples = imageSamples(msaa_in); 17 const int num_samples = imageSamples(msaa_in);
18 const ivec3 msaa_size = imageSize(msaa_in);
19 const ivec3 out_size = imageSize(output_img);
20 const ivec3 scale = out_size / msaa_size;
18 for (int curr_sample = 0; curr_sample < num_samples; ++curr_sample) { 21 for (int curr_sample = 0; curr_sample < num_samples; ++curr_sample) {
19 const vec4 pixel = imageLoad(msaa_in, coords, curr_sample); 22 const vec4 pixel = imageLoad(msaa_in, coords, curr_sample);
20 23
21 const int single_sample_x = 2 * coords.x + (curr_sample & 1); 24 const int single_sample_x = scale.x * coords.x + (curr_sample & 1);
22 const int single_sample_y = 2 * coords.y + ((curr_sample / 2) & 1); 25 const int single_sample_y = scale.y * coords.y + ((curr_sample / 2) & 1);
23 const ivec3 dest_coords = ivec3(single_sample_x, single_sample_y, coords.z); 26 const ivec3 dest_coords = ivec3(single_sample_x, single_sample_y, coords.z);
24 27
25 if (any(greaterThanEqual(dest_coords, imageSize(output_img)))) { 28 if (any(greaterThanEqual(dest_coords, imageSize(output_img)))) {
diff --git a/src/video_core/host_shaders/convert_non_msaa_to_msaa.comp b/src/video_core/host_shaders/convert_non_msaa_to_msaa.comp
index dedd962f1..c7ce38efa 100644
--- a/src/video_core/host_shaders/convert_non_msaa_to_msaa.comp
+++ b/src/video_core/host_shaders/convert_non_msaa_to_msaa.comp
@@ -15,9 +15,12 @@ void main() {
15 15
16 // TODO: Specialization constants for num_samples? 16 // TODO: Specialization constants for num_samples?
17 const int num_samples = imageSamples(output_msaa); 17 const int num_samples = imageSamples(output_msaa);
18 const ivec3 msaa_size = imageSize(output_msaa);
19 const ivec3 out_size = imageSize(img_in);
20 const ivec3 scale = out_size / msaa_size;
18 for (int curr_sample = 0; curr_sample < num_samples; ++curr_sample) { 21 for (int curr_sample = 0; curr_sample < num_samples; ++curr_sample) {
19 const int single_sample_x = 2 * coords.x + (curr_sample & 1); 22 const int single_sample_x = scale.x * coords.x + (curr_sample & 1);
20 const int single_sample_y = 2 * coords.y + ((curr_sample / 2) & 1); 23 const int single_sample_y = scale.y * coords.y + ((curr_sample / 2) & 1);
21 const ivec3 single_coords = ivec3(single_sample_x, single_sample_y, coords.z); 24 const ivec3 single_coords = ivec3(single_sample_x, single_sample_y, coords.z);
22 25
23 if (any(greaterThanEqual(single_coords, imageSize(img_in)))) { 26 if (any(greaterThanEqual(single_coords, imageSize(img_in)))) {
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 289d5b25c..617f92910 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -3,6 +3,7 @@
3 3
4#include <array> 4#include <array>
5#include <memory> 5#include <memory>
6#include <numeric>
6#include <optional> 7#include <optional>
7#include <utility> 8#include <utility>
8 9
@@ -11,7 +12,10 @@
11#include "common/assert.h" 12#include "common/assert.h"
12#include "common/common_types.h" 13#include "common/common_types.h"
13#include "common/div_ceil.h" 14#include "common/div_ceil.h"
15#include "common/vector_math.h"
14#include "video_core/host_shaders/astc_decoder_comp_spv.h" 16#include "video_core/host_shaders/astc_decoder_comp_spv.h"
17#include "video_core/host_shaders/convert_msaa_to_non_msaa_comp_spv.h"
18#include "video_core/host_shaders/convert_non_msaa_to_msaa_comp_spv.h"
15#include "video_core/host_shaders/queries_prefix_scan_sum_comp_spv.h" 19#include "video_core/host_shaders/queries_prefix_scan_sum_comp_spv.h"
16#include "video_core/host_shaders/queries_prefix_scan_sum_nosubgroups_comp_spv.h" 20#include "video_core/host_shaders/queries_prefix_scan_sum_nosubgroups_comp_spv.h"
17#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h" 21#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
@@ -131,6 +135,33 @@ constexpr DescriptorBankInfo ASTC_BANK_INFO{
131 .score = 2, 135 .score = 2,
132}; 136};
133 137
138constexpr std::array<VkDescriptorSetLayoutBinding, ASTC_NUM_BINDINGS> MSAA_DESCRIPTOR_SET_BINDINGS{{
139 {
140 .binding = 0,
141 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
142 .descriptorCount = 1,
143 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
144 .pImmutableSamplers = nullptr,
145 },
146 {
147 .binding = 1,
148 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
149 .descriptorCount = 1,
150 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
151 .pImmutableSamplers = nullptr,
152 },
153}};
154
155constexpr DescriptorBankInfo MSAA_BANK_INFO{
156 .uniform_buffers = 0,
157 .storage_buffers = 0,
158 .texture_buffers = 0,
159 .image_buffers = 0,
160 .textures = 0,
161 .images = 2,
162 .score = 2,
163};
164
134constexpr VkDescriptorUpdateTemplateEntry INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{ 165constexpr VkDescriptorUpdateTemplateEntry INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{
135 .dstBinding = 0, 166 .dstBinding = 0,
136 .dstArrayElement = 0, 167 .dstArrayElement = 0,
@@ -149,6 +180,15 @@ constexpr VkDescriptorUpdateTemplateEntry QUERIES_SCAN_DESCRIPTOR_UPDATE_TEMPLAT
149 .stride = sizeof(DescriptorUpdateEntry), 180 .stride = sizeof(DescriptorUpdateEntry),
150}; 181};
151 182
183constexpr VkDescriptorUpdateTemplateEntry MSAA_DESCRIPTOR_UPDATE_TEMPLATE{
184 .dstBinding = 0,
185 .dstArrayElement = 0,
186 .descriptorCount = 2,
187 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
188 .offset = 0,
189 .stride = sizeof(DescriptorUpdateEntry),
190};
191
152constexpr std::array<VkDescriptorUpdateTemplateEntry, ASTC_NUM_BINDINGS> 192constexpr std::array<VkDescriptorUpdateTemplateEntry, ASTC_NUM_BINDINGS>
153 ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY{{ 193 ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY{{
154 { 194 {
@@ -224,6 +264,9 @@ ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool,
224 }); 264 });
225 descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, bank_info); 265 descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, bank_info);
226 } 266 }
267 if (code.empty()) {
268 return;
269 }
227 module = device.GetLogical().CreateShaderModule({ 270 module = device.GetLogical().CreateShaderModule({
228 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 271 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
229 .pNext = nullptr, 272 .pNext = nullptr,
@@ -590,4 +633,100 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
590 scheduler.Finish(); 633 scheduler.Finish();
591} 634}
592 635
636MSAACopyPass::MSAACopyPass(const Device& device_, Scheduler& scheduler_,
637 DescriptorPool& descriptor_pool_,
638 StagingBufferPool& staging_buffer_pool_,
639 ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
640 : ComputePass(device_, descriptor_pool_, MSAA_DESCRIPTOR_SET_BINDINGS,
641 MSAA_DESCRIPTOR_UPDATE_TEMPLATE, MSAA_BANK_INFO, {},
642 CONVERT_NON_MSAA_TO_MSAA_COMP_SPV),
643 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
644 compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {
645 const auto make_msaa_pipeline = [this](size_t i, std::span<const u32> code) {
646 modules[i] = device.GetLogical().CreateShaderModule({
647 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
648 .pNext = nullptr,
649 .flags = 0,
650 .codeSize = static_cast<u32>(code.size_bytes()),
651 .pCode = code.data(),
652 });
653 pipelines[i] = device.GetLogical().CreateComputePipeline({
654 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
655 .pNext = nullptr,
656 .flags = 0,
657 .stage{
658 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
659 .pNext = nullptr,
660 .flags = 0,
661 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
662 .module = *modules[i],
663 .pName = "main",
664 .pSpecializationInfo = nullptr,
665 },
666 .layout = *layout,
667 .basePipelineHandle = nullptr,
668 .basePipelineIndex = 0,
669 });
670 };
671 make_msaa_pipeline(0, CONVERT_NON_MSAA_TO_MSAA_COMP_SPV);
672 make_msaa_pipeline(1, CONVERT_MSAA_TO_NON_MSAA_COMP_SPV);
673}
674
675MSAACopyPass::~MSAACopyPass() = default;
676
677void MSAACopyPass::CopyImage(Image& dst_image, Image& src_image,
678 std::span<const VideoCommon::ImageCopy> copies,
679 bool msaa_to_non_msaa) {
680 const VkPipeline msaa_pipeline = *pipelines[msaa_to_non_msaa ? 1 : 0];
681 scheduler.RequestOutsideRenderPassOperationContext();
682 for (const VideoCommon::ImageCopy& copy : copies) {
683 ASSERT(copy.src_subresource.base_layer == 0);
684 ASSERT(copy.src_subresource.num_layers == 1);
685 ASSERT(copy.dst_subresource.base_layer == 0);
686 ASSERT(copy.dst_subresource.num_layers == 1);
687
688 compute_pass_descriptor_queue.Acquire();
689 compute_pass_descriptor_queue.AddImage(
690 src_image.StorageImageView(copy.src_subresource.base_level));
691 compute_pass_descriptor_queue.AddImage(
692 dst_image.StorageImageView(copy.dst_subresource.base_level));
693 const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
694
695 const Common::Vec3<u32> num_dispatches = {
696 Common::DivCeil(copy.extent.width, 8U),
697 Common::DivCeil(copy.extent.height, 8U),
698 copy.extent.depth,
699 };
700
701 scheduler.Record([this, dst = dst_image.Handle(), msaa_pipeline, num_dispatches,
702 descriptor_data](vk::CommandBuffer cmdbuf) {
703 const VkDescriptorSet set = descriptor_allocator.Commit();
704 device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
705 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, msaa_pipeline);
706 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
707 cmdbuf.Dispatch(num_dispatches.x, num_dispatches.y, num_dispatches.z);
708 const VkImageMemoryBarrier write_barrier{
709 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
710 .pNext = nullptr,
711 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
712 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
713 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
714 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
715 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
716 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
717 .image = dst,
718 .subresourceRange{
719 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
720 .baseMipLevel = 0,
721 .levelCount = VK_REMAINING_MIP_LEVELS,
722 .baseArrayLayer = 0,
723 .layerCount = VK_REMAINING_ARRAY_LAYERS,
724 },
725 };
726 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
727 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier);
728 });
729 }
730}
731
593} // namespace Vulkan 732} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index 3ff935639..7b8f938c1 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -11,6 +11,7 @@
11#include "video_core/engines/maxwell_3d.h" 11#include "video_core/engines/maxwell_3d.h"
12#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 12#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
13#include "video_core/renderer_vulkan/vk_update_descriptor.h" 13#include "video_core/renderer_vulkan/vk_update_descriptor.h"
14#include "video_core/texture_cache/types.h"
14#include "video_core/vulkan_common/vulkan_memory_allocator.h" 15#include "video_core/vulkan_common/vulkan_memory_allocator.h"
15#include "video_core/vulkan_common/vulkan_wrapper.h" 16#include "video_core/vulkan_common/vulkan_wrapper.h"
16 17
@@ -130,4 +131,22 @@ private:
130 MemoryAllocator& memory_allocator; 131 MemoryAllocator& memory_allocator;
131}; 132};
132 133
134class MSAACopyPass final : public ComputePass {
135public:
136 explicit MSAACopyPass(const Device& device_, Scheduler& scheduler_,
137 DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_,
138 ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
139 ~MSAACopyPass();
140
141 void CopyImage(Image& dst_image, Image& src_image,
142 std::span<const VideoCommon::ImageCopy> copies, bool msaa_to_non_msaa);
143
144private:
145 Scheduler& scheduler;
146 StagingBufferPool& staging_buffer_pool;
147 ComputePassDescriptorQueue& compute_pass_descriptor_queue;
148 std::array<vk::ShaderModule, 2> modules;
149 std::array<vk::Pipeline, 2> pipelines;
150};
151
133} // namespace Vulkan 152} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index c7ce7c312..1628d76d6 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -1014,15 +1014,37 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
1014 regs.zeta.format == Tegra::DepthFormat::X8Z24_UNORM || 1014 regs.zeta.format == Tegra::DepthFormat::X8Z24_UNORM ||
1015 regs.zeta.format == Tegra::DepthFormat::S8Z24_UNORM || 1015 regs.zeta.format == Tegra::DepthFormat::S8Z24_UNORM ||
1016 regs.zeta.format == Tegra::DepthFormat::V8Z24_UNORM; 1016 regs.zeta.format == Tegra::DepthFormat::V8Z24_UNORM;
1017 if (is_d24 && !device.SupportsD24DepthBuffer()) { 1017 bool force_unorm = ([&] {
1018 if (!is_d24 || device.SupportsD24DepthBuffer()) {
1019 return false;
1020 }
1021 if (device.IsExtDepthBiasControlSupported()) {
1022 return true;
1023 }
1024 if (!Settings::values.renderer_amdvlk_depth_bias_workaround) {
1025 return false;
1026 }
1018 // the base formulas can be obtained from here: 1027 // the base formulas can be obtained from here:
1019 // https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias 1028 // https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias
1020 const double rescale_factor = 1029 const double rescale_factor =
1021 static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127)); 1030 static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127));
1022 units = static_cast<float>(static_cast<double>(units) * rescale_factor); 1031 units = static_cast<float>(static_cast<double>(units) * rescale_factor);
1023 } 1032 return false;
1033 })();
1024 scheduler.Record([constant = units, clamp = regs.depth_bias_clamp, 1034 scheduler.Record([constant = units, clamp = regs.depth_bias_clamp,
1025 factor = regs.slope_scale_depth_bias](vk::CommandBuffer cmdbuf) { 1035 factor = regs.slope_scale_depth_bias, force_unorm,
1036 precise = device.HasExactDepthBiasControl()](vk::CommandBuffer cmdbuf) {
1037 if (force_unorm) {
1038 VkDepthBiasRepresentationInfoEXT info{
1039 .sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT,
1040 .pNext = nullptr,
1041 .depthBiasRepresentation =
1042 VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT,
1043 .depthBiasExact = precise ? VK_TRUE : VK_FALSE,
1044 };
1045 cmdbuf.SetDepthBias(constant, clamp, factor, &info);
1046 return;
1047 }
1026 cmdbuf.SetDepthBias(constant, clamp, factor); 1048 cmdbuf.SetDepthBias(constant, clamp, factor);
1027 }); 1049 });
1028} 1050}
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 1f9e7acaa..71fdec809 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -176,6 +176,36 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
176 return allocator.CreateImage(image_ci); 176 return allocator.CreateImage(image_ci);
177} 177}
178 178
179[[nodiscard]] vk::ImageView MakeStorageView(const vk::Device& device, u32 level, VkImage image,
180 VkFormat format) {
181 static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
182 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
183 .pNext = nullptr,
184 .usage = VK_IMAGE_USAGE_STORAGE_BIT,
185 };
186 return device.CreateImageView(VkImageViewCreateInfo{
187 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
188 .pNext = &storage_image_view_usage_create_info,
189 .flags = 0,
190 .image = image,
191 .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
192 .format = format,
193 .components{
194 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
195 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
196 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
197 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
198 },
199 .subresourceRange{
200 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
201 .baseMipLevel = level,
202 .levelCount = 1,
203 .baseArrayLayer = 0,
204 .layerCount = VK_REMAINING_ARRAY_LAYERS,
205 },
206 });
207}
208
179[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { 209[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) {
180 switch (VideoCore::Surface::GetFormatType(format)) { 210 switch (VideoCore::Surface::GetFormatType(format)) {
181 case VideoCore::Surface::SurfaceType::ColorTexture: 211 case VideoCore::Surface::SurfaceType::ColorTexture:
@@ -817,6 +847,10 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
817 astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, 847 astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
818 compute_pass_descriptor_queue, memory_allocator); 848 compute_pass_descriptor_queue, memory_allocator);
819 } 849 }
850 if (device.IsStorageImageMultisampleSupported()) {
851 msaa_copy_pass = std::make_unique<MSAACopyPass>(
852 device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue);
853 }
820 if (!device.IsKhrImageFormatListSupported()) { 854 if (!device.IsKhrImageFormatListSupported()) {
821 return; 855 return;
822 } 856 }
@@ -1285,7 +1319,11 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
1285 1319
1286void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, 1320void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
1287 std::span<const VideoCommon::ImageCopy> copies) { 1321 std::span<const VideoCommon::ImageCopy> copies) {
1288 UNIMPLEMENTED_MSG("Copying images with different samples is not implemented in Vulkan."); 1322 const bool msaa_to_non_msaa = src.info.num_samples > 1 && dst.info.num_samples == 1;
1323 if (msaa_copy_pass) {
1324 return msaa_copy_pass->CopyImage(dst, src, copies, msaa_to_non_msaa);
1325 }
1326 UNIMPLEMENTED_MSG("Copying images with different samples is not supported.");
1289} 1327}
1290 1328
1291u64 TextureCacheRuntime::GetDeviceLocalMemory() const { 1329u64 TextureCacheRuntime::GetDeviceLocalMemory() const {
@@ -1333,39 +1371,15 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
1333 if (runtime->device.HasDebuggingToolAttached()) { 1371 if (runtime->device.HasDebuggingToolAttached()) {
1334 original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); 1372 original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
1335 } 1373 }
1336 static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
1337 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
1338 .pNext = nullptr,
1339 .usage = VK_IMAGE_USAGE_STORAGE_BIT,
1340 };
1341 current_image = *original_image; 1374 current_image = *original_image;
1375 storage_image_views.resize(info.resources.levels);
1342 if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported() && 1376 if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported() &&
1343 Settings::values.astc_recompression.GetValue() == 1377 Settings::values.astc_recompression.GetValue() ==
1344 Settings::AstcRecompression::Uncompressed) { 1378 Settings::AstcRecompression::Uncompressed) {
1345 const auto& device = runtime->device.GetLogical(); 1379 const auto& device = runtime->device.GetLogical();
1346 storage_image_views.reserve(info.resources.levels);
1347 for (s32 level = 0; level < info.resources.levels; ++level) { 1380 for (s32 level = 0; level < info.resources.levels; ++level) {
1348 storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{ 1381 storage_image_views[level] =
1349 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1382 MakeStorageView(device, level, *original_image, VK_FORMAT_A8B8G8R8_UNORM_PACK32);
1350 .pNext = &storage_image_view_usage_create_info,
1351 .flags = 0,
1352 .image = *original_image,
1353 .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
1354 .format = VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1355 .components{
1356 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
1357 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
1358 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
1359 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
1360 },
1361 .subresourceRange{
1362 .aspectMask = aspect_mask,
1363 .baseMipLevel = static_cast<u32>(level),
1364 .levelCount = 1,
1365 .baseArrayLayer = 0,
1366 .layerCount = VK_REMAINING_ARRAY_LAYERS,
1367 },
1368 }));
1369 } 1383 }
1370 } 1384 }
1371} 1385}
@@ -1496,6 +1510,17 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm
1496 DownloadMemory(buffers, offsets, copies); 1510 DownloadMemory(buffers, offsets, copies);
1497} 1511}
1498 1512
1513VkImageView Image::StorageImageView(s32 level) noexcept {
1514 auto& view = storage_image_views[level];
1515 if (!view) {
1516 const auto format_info =
1517 MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format);
1518 view =
1519 MakeStorageView(runtime->device.GetLogical(), level, current_image, format_info.format);
1520 }
1521 return *view;
1522}
1523
1499bool Image::IsRescaled() const noexcept { 1524bool Image::IsRescaled() const noexcept {
1500 return True(flags & ImageFlagBits::Rescaled); 1525 return True(flags & ImageFlagBits::Rescaled);
1501} 1526}
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 565ce19a9..d6c5a15cc 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -117,6 +117,7 @@ public:
117 BlitImageHelper& blit_image_helper; 117 BlitImageHelper& blit_image_helper;
118 RenderPassCache& render_pass_cache; 118 RenderPassCache& render_pass_cache;
119 std::optional<ASTCDecoderPass> astc_decoder_pass; 119 std::optional<ASTCDecoderPass> astc_decoder_pass;
120 std::unique_ptr<MSAACopyPass> msaa_copy_pass;
120 const Settings::ResolutionScalingInfo& resolution; 121 const Settings::ResolutionScalingInfo& resolution;
121 std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats; 122 std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;
122 123
@@ -161,15 +162,13 @@ public:
161 return aspect_mask; 162 return aspect_mask;
162 } 163 }
163 164
164 [[nodiscard]] VkImageView StorageImageView(s32 level) const noexcept {
165 return *storage_image_views[level];
166 }
167
168 /// Returns true when the image is already initialized and mark it as initialized 165 /// Returns true when the image is already initialized and mark it as initialized
169 [[nodiscard]] bool ExchangeInitialization() noexcept { 166 [[nodiscard]] bool ExchangeInitialization() noexcept {
170 return std::exchange(initialized, true); 167 return std::exchange(initialized, true);
171 } 168 }
172 169
170 VkImageView StorageImageView(s32 level) noexcept;
171
173 bool IsRescaled() const noexcept; 172 bool IsRescaled() const noexcept;
174 173
175 bool ScaleUp(bool ignore = false); 174 bool ScaleUp(bool ignore = false);
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 18185610f..3960b135a 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -1059,6 +1059,13 @@ void Device::RemoveUnsuitableExtensions() {
1059 RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color, 1059 RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
1060 VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); 1060 VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
1061 1061
1062 // VK_EXT_depth_bias_control
1063 extensions.depth_bias_control =
1064 features.depth_bias_control.depthBiasControl &&
1065 features.depth_bias_control.leastRepresentableValueForceUnormRepresentation;
1066 RemoveExtensionFeatureIfUnsuitable(extensions.depth_bias_control, features.depth_bias_control,
1067 VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME);
1068
1062 // VK_EXT_depth_clip_control 1069 // VK_EXT_depth_clip_control
1063 extensions.depth_clip_control = features.depth_clip_control.depthClipControl; 1070 extensions.depth_clip_control = features.depth_clip_control.depthClipControl;
1064 RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control, 1071 RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control,
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 94f41266d..9be612392 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -41,6 +41,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
41// Define all features which may be used by the implementation and require an extension here. 41// Define all features which may be used by the implementation and require an extension here.
42#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \ 42#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \
43 FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \ 43 FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \
44 FEATURE(EXT, DepthBiasControl, DEPTH_BIAS_CONTROL, depth_bias_control) \
44 FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \ 45 FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
45 FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \ 46 FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \
46 FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \ 47 FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
@@ -96,6 +97,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
96#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \ 97#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \
97 EXTENSION_NAME(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME) \ 98 EXTENSION_NAME(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME) \
98 EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \ 99 EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \
100 EXTENSION_NAME(VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME) \
99 EXTENSION_NAME(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME) \ 101 EXTENSION_NAME(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME) \
100 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \ 102 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \
101 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \ 103 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \
@@ -147,6 +149,9 @@ VK_DEFINE_HANDLE(VmaAllocator)
147// Define features where the absence of the feature may result in a degraded experience. 149// Define features where the absence of the feature may result in a degraded experience.
148#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \ 150#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \
149 FEATURE_NAME(custom_border_color, customBorderColors) \ 151 FEATURE_NAME(custom_border_color, customBorderColors) \
152 FEATURE_NAME(depth_bias_control, depthBiasControl) \
153 FEATURE_NAME(depth_bias_control, leastRepresentableValueForceUnormRepresentation) \
154 FEATURE_NAME(depth_bias_control, depthBiasExact) \
150 FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \ 155 FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \
151 FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \ 156 FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \
152 FEATURE_NAME(index_type_uint8, indexTypeUint8) \ 157 FEATURE_NAME(index_type_uint8, indexTypeUint8) \
@@ -324,6 +329,11 @@ public:
324 return features.shader_float16_int8.shaderInt8; 329 return features.shader_float16_int8.shaderInt8;
325 } 330 }
326 331
332 /// Returns true if the device supports binding multisample images as storage images.
333 bool IsStorageImageMultisampleSupported() const {
334 return features.features.shaderStorageImageMultisample;
335 }
336
327 /// Returns true if the device warp size can potentially be bigger than guest's warp size. 337 /// Returns true if the device warp size can potentially be bigger than guest's warp size.
328 bool IsWarpSizePotentiallyBiggerThanGuest() const { 338 bool IsWarpSizePotentiallyBiggerThanGuest() const {
329 return is_warp_potentially_bigger; 339 return is_warp_potentially_bigger;
@@ -459,6 +469,11 @@ public:
459 return extensions.depth_clip_control; 469 return extensions.depth_clip_control;
460 } 470 }
461 471
472 /// Returns true if the device supports VK_EXT_depth_bias_control.
473 bool IsExtDepthBiasControlSupported() const {
474 return extensions.depth_bias_control;
475 }
476
462 /// Returns true if the device supports VK_EXT_shader_viewport_index_layer. 477 /// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
463 bool IsExtShaderViewportIndexLayerSupported() const { 478 bool IsExtShaderViewportIndexLayerSupported() const {
464 return extensions.shader_viewport_index_layer; 479 return extensions.shader_viewport_index_layer;
@@ -619,6 +634,10 @@ public:
619 return features.robustness2.nullDescriptor; 634 return features.robustness2.nullDescriptor;
620 } 635 }
621 636
637 bool HasExactDepthBiasControl() const {
638 return features.depth_bias_control.depthBiasExact;
639 }
640
622 u32 GetMaxVertexInputAttributes() const { 641 u32 GetMaxVertexInputAttributes() const {
623 return properties.properties.limits.maxVertexInputAttributes; 642 return properties.properties.limits.maxVertexInputAttributes;
624 } 643 }
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 5afba365c..2f3254a97 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -113,6 +113,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
113 X(vkCmdPushDescriptorSetWithTemplateKHR); 113 X(vkCmdPushDescriptorSetWithTemplateKHR);
114 X(vkCmdSetBlendConstants); 114 X(vkCmdSetBlendConstants);
115 X(vkCmdSetDepthBias); 115 X(vkCmdSetDepthBias);
116 X(vkCmdSetDepthBias2EXT);
116 X(vkCmdSetDepthBounds); 117 X(vkCmdSetDepthBounds);
117 X(vkCmdSetEvent); 118 X(vkCmdSetEvent);
118 X(vkCmdSetScissor); 119 X(vkCmdSetScissor);
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index 0d4bbe7f7..1e3c0fa64 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -226,6 +226,7 @@ struct DeviceDispatch : InstanceDispatch {
226 PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants{}; 226 PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants{};
227 PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT{}; 227 PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT{};
228 PFN_vkCmdSetDepthBias vkCmdSetDepthBias{}; 228 PFN_vkCmdSetDepthBias vkCmdSetDepthBias{};
229 PFN_vkCmdSetDepthBias2EXT vkCmdSetDepthBias2EXT{};
229 PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds{}; 230 PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds{};
230 PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT{}; 231 PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT{};
231 PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT{}; 232 PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT{};
@@ -1333,6 +1334,18 @@ public:
1333 dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor); 1334 dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor);
1334 } 1335 }
1335 1336
1337 void SetDepthBias(float constant_factor, float clamp, float slope_factor,
1338 VkDepthBiasRepresentationInfoEXT* extra) const noexcept {
1339 VkDepthBiasInfoEXT info{
1340 .sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_INFO_EXT,
1341 .pNext = extra,
1342 .depthBiasConstantFactor = constant_factor,
1343 .depthBiasClamp = clamp,
1344 .depthBiasSlopeFactor = slope_factor,
1345 };
1346 dld->vkCmdSetDepthBias2EXT(handle, &info);
1347 }
1348
1336 void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept { 1349 void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept {
1337 dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds); 1350 dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds);
1338 } 1351 }
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b1b6b9354..adb7b332f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -3113,10 +3113,9 @@ void GMainWindow::OnMenuInstallToNAND() {
3113 QFuture<InstallResult> future; 3113 QFuture<InstallResult> future;
3114 InstallResult result; 3114 InstallResult result;
3115 3115
3116 if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || 3116 if (file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
3117 file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
3118 3117
3119 future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); }); 3118 future = QtConcurrent::run([this, &file] { return InstallNSP(file); });
3120 3119
3121 while (!future.isFinished()) { 3120 while (!future.isFinished()) {
3122 QCoreApplication::processEvents(); 3121 QCoreApplication::processEvents();
@@ -3175,7 +3174,7 @@ void GMainWindow::OnMenuInstallToNAND() {
3175 ui->action_Install_File_NAND->setEnabled(true); 3174 ui->action_Install_File_NAND->setEnabled(true);
3176} 3175}
3177 3176
3178InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { 3177InstallResult GMainWindow::InstallNSP(const QString& filename) {
3179 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, 3178 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
3180 const FileSys::VirtualFile& dest, std::size_t block_size) { 3179 const FileSys::VirtualFile& dest, std::size_t block_size) {
3181 if (src == nullptr || dest == nullptr) { 3180 if (src == nullptr || dest == nullptr) {
@@ -3209,9 +3208,7 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
3209 return InstallResult::Failure; 3208 return InstallResult::Failure;
3210 } 3209 }
3211 } else { 3210 } else {
3212 const auto xci = std::make_shared<FileSys::XCI>( 3211 return InstallResult::Failure;
3213 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
3214 nsp = xci->GetSecurePartitionNSP();
3215 } 3212 }
3216 3213
3217 if (nsp->GetStatus() != Loader::ResultStatus::Success) { 3214 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 53bedfab3..ba318eb11 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -387,7 +387,7 @@ private:
387 void RemoveCacheStorage(u64 program_id); 387 void RemoveCacheStorage(u64 program_id);
388 bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, 388 bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id,
389 u64* selected_title_id, u8* selected_content_record_type); 389 u64* selected_title_id, u8* selected_content_record_type);
390 InstallResult InstallNSPXCI(const QString& filename); 390 InstallResult InstallNSP(const QString& filename);
391 InstallResult InstallNCA(const QString& filename); 391 InstallResult InstallNCA(const QString& filename);
392 void MigrateConfigFiles(); 392 void MigrateConfigFiles();
393 void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, 393 void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {},