summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt14
-rw-r--r--src/core/hle/service/am/applets/applet_mii_edit.cpp50
-rw-r--r--src/core/hle/service/am/applets/applet_mii_edit.h7
-rw-r--r--src/core/hle/service/mii/mii.cpp114
-rw-r--r--src/core/hle/service/mii/mii.h18
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp6
-rw-r--r--src/core/hle/service/mii/types/char_info.cpp2
-rw-r--r--src/core/hle/service/mii/types/core_data.cpp3
-rw-r--r--src/core/hle/service/mii/types/raw_data.cpp12
-rw-r--r--src/video_core/engines/maxwell_dma.cpp5
-rw-r--r--src/video_core/engines/maxwell_dma.h55
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp10
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp8
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h8
15 files changed, 208 insertions, 106 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 74941f934..6fa847631 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -50,6 +50,7 @@ import org.yuzu.yuzu_emu.model.TaskViewModel
50import org.yuzu.yuzu_emu.utils.* 50import org.yuzu.yuzu_emu.utils.*
51import java.io.BufferedInputStream 51import java.io.BufferedInputStream
52import java.io.BufferedOutputStream 52import java.io.BufferedOutputStream
53import java.io.FileInputStream
53import java.io.FileOutputStream 54import java.io.FileOutputStream
54import java.util.zip.ZipEntry 55import java.util.zip.ZipEntry
55import java.util.zip.ZipInputStream 56import java.util.zip.ZipInputStream
@@ -639,7 +640,15 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
639 file.path.length 640 file.path.length
640 ) 641 )
641 stream.putNextEntry(ZipEntry(newPath)) 642 stream.putNextEntry(ZipEntry(newPath))
642 stream.write(file.readBytes()) 643
644 val buffer = ByteArray(8096)
645 var read: Int
646 FileInputStream(file).use { fis ->
647 while (fis.read(buffer).also { read = it } != -1) {
648 stream.write(buffer, 0, read)
649 }
650 }
651
643 stream.closeEntry() 652 stream.closeEntry()
644 } 653 }
645 } 654 }
@@ -664,7 +673,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
664 checkStream.use { stream -> 673 checkStream.use { stream ->
665 var ze: ZipEntry? = null 674 var ze: ZipEntry? = null
666 while (stream.nextEntry?.also { ze = it } != null) { 675 while (stream.nextEntry?.also { ze = it } != null) {
667 if (ze!!.name.trim() == "/config/config.ini") { 676 val itemName = ze!!.name.trim()
677 if (itemName == "/config/config.ini" || itemName == "config/config.ini") {
668 isYuzuBackup = true 678 isYuzuBackup = true
669 return@use 679 return@use
670 } 680 }
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 350a90818..ff77830d2 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.cpp
+++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp
@@ -7,7 +7,9 @@
7#include "core/frontend/applets/mii_edit.h" 7#include "core/frontend/applets/mii_edit.h"
8#include "core/hle/service/am/am.h" 8#include "core/hle/service/am/am.h"
9#include "core/hle/service/am/applets/applet_mii_edit.h" 9#include "core/hle/service/am/applets/applet_mii_edit.h"
10#include "core/hle/service/mii/mii.h"
10#include "core/hle/service/mii/mii_manager.h" 11#include "core/hle/service/mii/mii_manager.h"
12#include "core/hle/service/sm/sm.h"
11 13
12namespace Service::AM::Applets { 14namespace Service::AM::Applets {
13 15
@@ -56,6 +58,12 @@ void MiiEdit::Initialize() {
56 sizeof(MiiEditAppletInputV4)); 58 sizeof(MiiEditAppletInputV4));
57 break; 59 break;
58 } 60 }
61
62 manager = system.ServiceManager().GetService<Mii::MiiDBModule>("mii:e")->GetMiiManager();
63 if (manager == nullptr) {
64 manager = std::make_shared<Mii::MiiManager>();
65 }
66 manager->Initialize(metadata);
59} 67}
60 68
61bool MiiEdit::TransactionComplete() const { 69bool MiiEdit::TransactionComplete() const {
@@ -78,22 +86,46 @@ void MiiEdit::Execute() {
78 // This is a default stub for each of the MiiEdit applet modes. 86 // This is a default stub for each of the MiiEdit applet modes.
79 switch (applet_input_common.applet_mode) { 87 switch (applet_input_common.applet_mode) {
80 case MiiEditAppletMode::ShowMiiEdit: 88 case MiiEditAppletMode::ShowMiiEdit:
81 case MiiEditAppletMode::AppendMii:
82 case MiiEditAppletMode::AppendMiiImage: 89 case MiiEditAppletMode::AppendMiiImage:
83 case MiiEditAppletMode::UpdateMiiImage: 90 case MiiEditAppletMode::UpdateMiiImage:
84 MiiEditOutput(MiiEditResult::Success, 0); 91 MiiEditOutput(MiiEditResult::Success, 0);
85 break; 92 break;
86 case MiiEditAppletMode::CreateMii: 93 case MiiEditAppletMode::AppendMii: {
87 case MiiEditAppletMode::EditMii: {
88 Mii::CharInfo char_info{};
89 Mii::StoreData store_data{}; 94 Mii::StoreData store_data{};
90 store_data.BuildBase(Mii::Gender::Male); 95 store_data.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All);
91 char_info.SetFromStoreData(store_data); 96 store_data.SetNickname({u'y', u'u', u'z', u'u'});
97 store_data.SetChecksum();
98 const auto result = manager->AddOrReplace(metadata, store_data);
99
100 if (result.IsError()) {
101 MiiEditOutput(MiiEditResult::Cancel, 0);
102 break;
103 }
104
105 s32 index = manager->FindIndex(store_data.GetCreateId(), false);
106
107 if (index == -1) {
108 MiiEditOutput(MiiEditResult::Cancel, 0);
109 break;
110 }
111
112 MiiEditOutput(MiiEditResult::Success, index);
113 break;
114 }
115 case MiiEditAppletMode::CreateMii: {
116 Mii::CharInfo char_info{};
117 manager->BuildRandom(char_info, Mii::Age::All, Mii::Gender::All, Mii::Race::All);
118
119 const MiiEditCharInfo edit_char_info{
120 .mii_info{char_info},
121 };
92 122
123 MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info);
124 break;
125 }
126 case MiiEditAppletMode::EditMii: {
93 const MiiEditCharInfo edit_char_info{ 127 const MiiEditCharInfo edit_char_info{
94 .mii_info{applet_input_common.applet_mode == MiiEditAppletMode::EditMii 128 .mii_info{applet_input_v4.char_info.mii_info},
95 ? applet_input_v4.char_info.mii_info
96 : char_info},
97 }; 129 };
98 130
99 MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info); 131 MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info);
diff --git a/src/core/hle/service/am/applets/applet_mii_edit.h b/src/core/hle/service/am/applets/applet_mii_edit.h
index 3f46fae1b..7ff34af49 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.h
+++ b/src/core/hle/service/am/applets/applet_mii_edit.h
@@ -11,6 +11,11 @@ namespace Core {
11class System; 11class System;
12} // namespace Core 12} // namespace Core
13 13
14namespace Service::Mii {
15struct DatabaseSessionMetadata;
16class MiiManager;
17} // namespace Service::Mii
18
14namespace Service::AM::Applets { 19namespace Service::AM::Applets {
15 20
16class MiiEdit final : public Applet { 21class MiiEdit final : public Applet {
@@ -40,6 +45,8 @@ private:
40 MiiEditAppletInputV4 applet_input_v4{}; 45 MiiEditAppletInputV4 applet_input_v4{};
41 46
42 bool is_complete{false}; 47 bool is_complete{false};
48 std::shared_ptr<Mii::MiiManager> manager = nullptr;
49 Mii::DatabaseSessionMetadata metadata{};
43}; 50};
44 51
45} // namespace Service::AM::Applets 52} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 8de806cfb..c28eed926 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -18,8 +18,10 @@ namespace Service::Mii {
18 18
19class IDatabaseService final : public ServiceFramework<IDatabaseService> { 19class IDatabaseService final : public ServiceFramework<IDatabaseService> {
20public: 20public:
21 explicit IDatabaseService(Core::System& system_, bool is_system_) 21 explicit IDatabaseService(Core::System& system_, std::shared_ptr<MiiManager> mii_manager,
22 : ServiceFramework{system_, "IDatabaseService"}, is_system{is_system_} { 22 bool is_system_)
23 : ServiceFramework{system_, "IDatabaseService"}, manager{mii_manager}, is_system{
24 is_system_} {
23 // clang-format off 25 // clang-format off
24 static const FunctionInfo functions[] = { 26 static const FunctionInfo functions[] = {
25 {0, &IDatabaseService::IsUpdated, "IsUpdated"}, 27 {0, &IDatabaseService::IsUpdated, "IsUpdated"},
@@ -54,7 +56,7 @@ public:
54 56
55 RegisterHandlers(functions); 57 RegisterHandlers(functions);
56 58
57 manager.Initialize(metadata); 59 manager->Initialize(metadata);
58 } 60 }
59 61
60private: 62private:
@@ -64,7 +66,7 @@ private:
64 66
65 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); 67 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
66 68
67 const bool is_updated = manager.IsUpdated(metadata, source_flag); 69 const bool is_updated = manager->IsUpdated(metadata, source_flag);
68 70
69 IPC::ResponseBuilder rb{ctx, 3}; 71 IPC::ResponseBuilder rb{ctx, 3};
70 rb.Push(ResultSuccess); 72 rb.Push(ResultSuccess);
@@ -74,7 +76,7 @@ private:
74 void IsFullDatabase(HLERequestContext& ctx) { 76 void IsFullDatabase(HLERequestContext& ctx) {
75 LOG_DEBUG(Service_Mii, "called"); 77 LOG_DEBUG(Service_Mii, "called");
76 78
77 const bool is_full_database = manager.IsFullDatabase(); 79 const bool is_full_database = manager->IsFullDatabase();
78 80
79 IPC::ResponseBuilder rb{ctx, 3}; 81 IPC::ResponseBuilder rb{ctx, 3};
80 rb.Push(ResultSuccess); 82 rb.Push(ResultSuccess);
@@ -85,7 +87,7 @@ private:
85 IPC::RequestParser rp{ctx}; 87 IPC::RequestParser rp{ctx};
86 const auto source_flag{rp.PopRaw<SourceFlag>()}; 88 const auto source_flag{rp.PopRaw<SourceFlag>()};
87 89
88 const u32 mii_count = manager.GetCount(metadata, source_flag); 90 const u32 mii_count = manager->GetCount(metadata, source_flag);
89 91
90 LOG_DEBUG(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, mii_count); 92 LOG_DEBUG(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, mii_count);
91 93
@@ -101,7 +103,7 @@ private:
101 103
102 u32 mii_count{}; 104 u32 mii_count{};
103 std::vector<CharInfoElement> char_info_elements(output_size); 105 std::vector<CharInfoElement> char_info_elements(output_size);
104 const auto result = manager.Get(metadata, char_info_elements, mii_count, source_flag); 106 const auto result = manager->Get(metadata, char_info_elements, mii_count, source_flag);
105 107
106 if (mii_count != 0) { 108 if (mii_count != 0) {
107 ctx.WriteBuffer(char_info_elements); 109 ctx.WriteBuffer(char_info_elements);
@@ -122,7 +124,7 @@ private:
122 124
123 u32 mii_count{}; 125 u32 mii_count{};
124 std::vector<CharInfo> char_info(output_size); 126 std::vector<CharInfo> char_info(output_size);
125 const auto result = manager.Get(metadata, char_info, mii_count, source_flag); 127 const auto result = manager->Get(metadata, char_info, mii_count, source_flag);
126 128
127 if (mii_count != 0) { 129 if (mii_count != 0) {
128 ctx.WriteBuffer(char_info); 130 ctx.WriteBuffer(char_info);
@@ -144,7 +146,7 @@ private:
144 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); 146 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
145 147
146 CharInfo new_char_info{}; 148 CharInfo new_char_info{};
147 const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag); 149 const auto result = manager->UpdateLatest(metadata, new_char_info, char_info, source_flag);
148 if (result.IsFailure()) { 150 if (result.IsFailure()) {
149 IPC::ResponseBuilder rb{ctx, 2}; 151 IPC::ResponseBuilder rb{ctx, 2};
150 rb.Push(result); 152 rb.Push(result);
@@ -183,7 +185,7 @@ private:
183 } 185 }
184 186
185 CharInfo char_info{}; 187 CharInfo char_info{};
186 manager.BuildRandom(char_info, age, gender, race); 188 manager->BuildRandom(char_info, age, gender, race);
187 189
188 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 190 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
189 rb.Push(ResultSuccess); 191 rb.Push(ResultSuccess);
@@ -203,7 +205,7 @@ private:
203 } 205 }
204 206
205 CharInfo char_info{}; 207 CharInfo char_info{};
206 manager.BuildDefault(char_info, index); 208 manager->BuildDefault(char_info, index);
207 209
208 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 210 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
209 rb.Push(ResultSuccess); 211 rb.Push(ResultSuccess);
@@ -217,7 +219,7 @@ private:
217 219
218 u32 mii_count{}; 220 u32 mii_count{};
219 std::vector<StoreDataElement> store_data_elements(output_size); 221 std::vector<StoreDataElement> store_data_elements(output_size);
220 const auto result = manager.Get(metadata, store_data_elements, mii_count, source_flag); 222 const auto result = manager->Get(metadata, store_data_elements, mii_count, source_flag);
221 223
222 if (mii_count != 0) { 224 if (mii_count != 0) {
223 ctx.WriteBuffer(store_data_elements); 225 ctx.WriteBuffer(store_data_elements);
@@ -238,7 +240,7 @@ private:
238 240
239 u32 mii_count{}; 241 u32 mii_count{};
240 std::vector<StoreData> store_data(output_size); 242 std::vector<StoreData> store_data(output_size);
241 const auto result = manager.Get(metadata, store_data, mii_count, source_flag); 243 const auto result = manager->Get(metadata, store_data, mii_count, source_flag);
242 244
243 if (mii_count != 0) { 245 if (mii_count != 0) {
244 ctx.WriteBuffer(store_data); 246 ctx.WriteBuffer(store_data);
@@ -266,7 +268,7 @@ private:
266 268
267 StoreData new_store_data{}; 269 StoreData new_store_data{};
268 if (result.IsSuccess()) { 270 if (result.IsSuccess()) {
269 result = manager.UpdateLatest(metadata, new_store_data, store_data, source_flag); 271 result = manager->UpdateLatest(metadata, new_store_data, store_data, source_flag);
270 } 272 }
271 273
272 if (result.IsFailure()) { 274 if (result.IsFailure()) {
@@ -288,7 +290,7 @@ private:
288 LOG_INFO(Service_Mii, "called with create_id={}, is_special={}", 290 LOG_INFO(Service_Mii, "called with create_id={}, is_special={}",
289 create_id.FormattedString(), is_special); 291 create_id.FormattedString(), is_special);
290 292
291 const s32 index = manager.FindIndex(create_id, is_special); 293 const s32 index = manager->FindIndex(create_id, is_special);
292 294
293 IPC::ResponseBuilder rb{ctx, 3}; 295 IPC::ResponseBuilder rb{ctx, 3};
294 rb.Push(ResultSuccess); 296 rb.Push(ResultSuccess);
@@ -309,14 +311,14 @@ private:
309 } 311 }
310 312
311 if (result.IsSuccess()) { 313 if (result.IsSuccess()) {
312 const u32 count = manager.GetCount(metadata, SourceFlag::Database); 314 const u32 count = manager->GetCount(metadata, SourceFlag::Database);
313 if (new_index < 0 || new_index >= static_cast<s32>(count)) { 315 if (new_index < 0 || new_index >= static_cast<s32>(count)) {
314 result = ResultInvalidArgument; 316 result = ResultInvalidArgument;
315 } 317 }
316 } 318 }
317 319
318 if (result.IsSuccess()) { 320 if (result.IsSuccess()) {
319 result = manager.Move(metadata, new_index, create_id); 321 result = manager->Move(metadata, new_index, create_id);
320 } 322 }
321 323
322 IPC::ResponseBuilder rb{ctx, 2}; 324 IPC::ResponseBuilder rb{ctx, 2};
@@ -336,7 +338,7 @@ private:
336 } 338 }
337 339
338 if (result.IsSuccess()) { 340 if (result.IsSuccess()) {
339 result = manager.AddOrReplace(metadata, store_data); 341 result = manager->AddOrReplace(metadata, store_data);
340 } 342 }
341 343
342 IPC::ResponseBuilder rb{ctx, 2}; 344 IPC::ResponseBuilder rb{ctx, 2};
@@ -356,7 +358,7 @@ private:
356 } 358 }
357 359
358 if (result.IsSuccess()) { 360 if (result.IsSuccess()) {
359 result = manager.Delete(metadata, create_id); 361 result = manager->Delete(metadata, create_id);
360 } 362 }
361 363
362 IPC::ResponseBuilder rb{ctx, 2}; 364 IPC::ResponseBuilder rb{ctx, 2};
@@ -376,7 +378,7 @@ private:
376 } 378 }
377 379
378 if (result.IsSuccess()) { 380 if (result.IsSuccess()) {
379 result = manager.DestroyFile(metadata); 381 result = manager->DestroyFile(metadata);
380 } 382 }
381 383
382 IPC::ResponseBuilder rb{ctx, 2}; 384 IPC::ResponseBuilder rb{ctx, 2};
@@ -396,7 +398,7 @@ private:
396 } 398 }
397 399
398 if (result.IsSuccess()) { 400 if (result.IsSuccess()) {
399 result = manager.DeleteFile(); 401 result = manager->DeleteFile();
400 } 402 }
401 403
402 IPC::ResponseBuilder rb{ctx, 2}; 404 IPC::ResponseBuilder rb{ctx, 2};
@@ -416,7 +418,7 @@ private:
416 } 418 }
417 419
418 if (result.IsSuccess()) { 420 if (result.IsSuccess()) {
419 result = manager.Format(metadata); 421 result = manager->Format(metadata);
420 } 422 }
421 423
422 IPC::ResponseBuilder rb{ctx, 2}; 424 IPC::ResponseBuilder rb{ctx, 2};
@@ -434,7 +436,7 @@ private:
434 } 436 }
435 437
436 if (result.IsSuccess()) { 438 if (result.IsSuccess()) {
437 is_broken_with_clear_flag = manager.IsBrokenWithClearFlag(metadata); 439 is_broken_with_clear_flag = manager->IsBrokenWithClearFlag(metadata);
438 } 440 }
439 441
440 IPC::ResponseBuilder rb{ctx, 3}; 442 IPC::ResponseBuilder rb{ctx, 3};
@@ -449,7 +451,7 @@ private:
449 LOG_DEBUG(Service_Mii, "called"); 451 LOG_DEBUG(Service_Mii, "called");
450 452
451 s32 index{}; 453 s32 index{};
452 const auto result = manager.GetIndex(metadata, info, index); 454 const auto result = manager->GetIndex(metadata, info, index);
453 455
454 IPC::ResponseBuilder rb{ctx, 3}; 456 IPC::ResponseBuilder rb{ctx, 3};
455 rb.Push(result); 457 rb.Push(result);
@@ -462,7 +464,7 @@ private:
462 464
463 LOG_INFO(Service_Mii, "called, interface_version={:08X}", interface_version); 465 LOG_INFO(Service_Mii, "called, interface_version={:08X}", interface_version);
464 466
465 manager.SetInterfaceVersion(metadata, interface_version); 467 manager->SetInterfaceVersion(metadata, interface_version);
466 468
467 IPC::ResponseBuilder rb{ctx, 2}; 469 IPC::ResponseBuilder rb{ctx, 2};
468 rb.Push(ResultSuccess); 470 rb.Push(ResultSuccess);
@@ -475,7 +477,7 @@ private:
475 LOG_INFO(Service_Mii, "called"); 477 LOG_INFO(Service_Mii, "called");
476 478
477 CharInfo char_info{}; 479 CharInfo char_info{};
478 const auto result = manager.ConvertV3ToCharInfo(char_info, mii_v3); 480 const auto result = manager->ConvertV3ToCharInfo(char_info, mii_v3);
479 481
480 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 482 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
481 rb.Push(result); 483 rb.Push(result);
@@ -489,7 +491,7 @@ private:
489 LOG_INFO(Service_Mii, "called"); 491 LOG_INFO(Service_Mii, "called");
490 492
491 CharInfo char_info{}; 493 CharInfo char_info{};
492 const auto result = manager.ConvertCoreDataToCharInfo(char_info, core_data); 494 const auto result = manager->ConvertCoreDataToCharInfo(char_info, core_data);
493 495
494 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 496 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
495 rb.Push(result); 497 rb.Push(result);
@@ -503,7 +505,7 @@ private:
503 LOG_INFO(Service_Mii, "called"); 505 LOG_INFO(Service_Mii, "called");
504 506
505 CoreData core_data{}; 507 CoreData core_data{};
506 const auto result = manager.ConvertCharInfoToCoreData(core_data, char_info); 508 const auto result = manager->ConvertCharInfoToCoreData(core_data, char_info);
507 509
508 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CoreData) / sizeof(u32)}; 510 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CoreData) / sizeof(u32)};
509 rb.Push(result); 511 rb.Push(result);
@@ -516,41 +518,46 @@ private:
516 518
517 LOG_INFO(Service_Mii, "called"); 519 LOG_INFO(Service_Mii, "called");
518 520
519 const auto result = manager.Append(metadata, char_info); 521 const auto result = manager->Append(metadata, char_info);
520 522
521 IPC::ResponseBuilder rb{ctx, 2}; 523 IPC::ResponseBuilder rb{ctx, 2};
522 rb.Push(result); 524 rb.Push(result);
523 } 525 }
524 526
525 MiiManager manager{}; 527 std::shared_ptr<MiiManager> manager = nullptr;
526 DatabaseSessionMetadata metadata{}; 528 DatabaseSessionMetadata metadata{};
527 bool is_system{}; 529 bool is_system{};
528}; 530};
529 531
530class MiiDBModule final : public ServiceFramework<MiiDBModule> { 532MiiDBModule::MiiDBModule(Core::System& system_, const char* name_,
531public: 533 std::shared_ptr<MiiManager> mii_manager, bool is_system_)
532 explicit MiiDBModule(Core::System& system_, const char* name_, bool is_system_) 534 : ServiceFramework{system_, name_}, manager{mii_manager}, is_system{is_system_} {
533 : ServiceFramework{system_, name_}, is_system{is_system_} { 535 // clang-format off
534 // clang-format off 536 static const FunctionInfo functions[] = {
535 static const FunctionInfo functions[] = { 537 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
536 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, 538 };
537 }; 539 // clang-format on
538 // clang-format on
539 540
540 RegisterHandlers(functions); 541 RegisterHandlers(functions);
542
543 if (manager == nullptr) {
544 manager = std::make_shared<MiiManager>();
541 } 545 }
546}
542 547
543private: 548MiiDBModule::~MiiDBModule() = default;
544 void GetDatabaseService(HLERequestContext& ctx) {
545 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
546 rb.Push(ResultSuccess);
547 rb.PushIpcInterface<IDatabaseService>(system, is_system);
548 549
549 LOG_DEBUG(Service_Mii, "called"); 550void MiiDBModule::GetDatabaseService(HLERequestContext& ctx) {
550 } 551 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
552 rb.Push(ResultSuccess);
553 rb.PushIpcInterface<IDatabaseService>(system, manager, is_system);
551 554
552 bool is_system{}; 555 LOG_DEBUG(Service_Mii, "called");
553}; 556}
557
558std::shared_ptr<MiiManager> MiiDBModule::GetMiiManager() {
559 return manager;
560}
554 561
555class MiiImg final : public ServiceFramework<MiiImg> { 562class MiiImg final : public ServiceFramework<MiiImg> {
556public: 563public:
@@ -596,11 +603,12 @@ private:
596 603
597void LoopProcess(Core::System& system) { 604void LoopProcess(Core::System& system) {
598 auto server_manager = std::make_unique<ServerManager>(system); 605 auto server_manager = std::make_unique<ServerManager>(system);
606 std::shared_ptr<MiiManager> manager = nullptr;
599 607
600 server_manager->RegisterNamedService("mii:e", 608 server_manager->RegisterNamedService(
601 std::make_shared<MiiDBModule>(system, "mii:e", true)); 609 "mii:e", std::make_shared<MiiDBModule>(system, "mii:e", manager, true));
602 server_manager->RegisterNamedService("mii:u", 610 server_manager->RegisterNamedService(
603 std::make_shared<MiiDBModule>(system, "mii:u", false)); 611 "mii:u", std::make_shared<MiiDBModule>(system, "mii:u", manager, false));
604 server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system)); 612 server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system));
605 ServerManager::RunServer(std::move(server_manager)); 613 ServerManager::RunServer(std::move(server_manager));
606} 614}
diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h
index ed4e3f62b..9aa4426f6 100644
--- a/src/core/hle/service/mii/mii.h
+++ b/src/core/hle/service/mii/mii.h
@@ -3,11 +3,29 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/service.h"
7
6namespace Core { 8namespace Core {
7class System; 9class System;
8} 10}
9 11
10namespace Service::Mii { 12namespace Service::Mii {
13class MiiManager;
14
15class MiiDBModule final : public ServiceFramework<MiiDBModule> {
16public:
17 explicit MiiDBModule(Core::System& system_, const char* name_,
18 std::shared_ptr<MiiManager> mii_manager, bool is_system_);
19 ~MiiDBModule() override;
20
21 std::shared_ptr<MiiManager> GetMiiManager();
22
23private:
24 void GetDatabaseService(HLERequestContext& ctx);
25
26 std::shared_ptr<MiiManager> manager = nullptr;
27 bool is_system{};
28};
11 29
12void LoopProcess(Core::System& system); 30void LoopProcess(Core::System& system);
13 31
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp
index a5a2a9232..dcfd6b2e2 100644
--- a/src/core/hle/service/mii/mii_manager.cpp
+++ b/src/core/hle/service/mii/mii_manager.cpp
@@ -130,11 +130,11 @@ Result MiiManager::GetIndex(const DatabaseSessionMetadata& metadata, const CharI
130 } 130 }
131 131
132 s32 index{}; 132 s32 index{};
133 Result result = {}; 133 const bool is_special = metadata.magic == MiiMagic;
134 // FindIndex(index); 134 const auto result = database_manager.FindIndex(index, char_info.GetCreateId(), is_special);
135 135
136 if (result.IsError()) { 136 if (result.IsError()) {
137 return ResultNotFound; 137 index = -1;
138 } 138 }
139 139
140 if (index == -1) { 140 if (index == -1) {
diff --git a/src/core/hle/service/mii/types/char_info.cpp b/src/core/hle/service/mii/types/char_info.cpp
index e90124af4..c82186c73 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() + 3; 40 eyebrow_y = store_data.GetEyebrowY();
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 465c6293a..1068031e3 100644
--- a/src/core/hle/service/mii/types/core_data.cpp
+++ b/src/core/hle/service/mii/types/core_data.cpp
@@ -171,7 +171,7 @@ void CoreData::BuildRandom(Age age, Gender gender, Race race) {
171 u8 glasses_type{}; 171 u8 glasses_type{};
172 while (glasses_type_start < glasses_type_info.values[glasses_type]) { 172 while (glasses_type_start < glasses_type_info.values[glasses_type]) {
173 if (++glasses_type >= glasses_type_info.values_count) { 173 if (++glasses_type >= glasses_type_info.values_count) {
174 ASSERT(false); 174 glasses_type = 0;
175 break; 175 break;
176 } 176 }
177 } 177 }
@@ -179,6 +179,7 @@ void CoreData::BuildRandom(Age age, Gender gender, Race race) {
179 SetGlassType(static_cast<GlassType>(glasses_type)); 179 SetGlassType(static_cast<GlassType>(glasses_type));
180 SetGlassColor(RawData::GetGlassColorFromVer3(0)); 180 SetGlassColor(RawData::GetGlassColorFromVer3(0));
181 SetGlassScale(4); 181 SetGlassScale(4);
182 SetGlassY(static_cast<u8>(axis_y + 10));
182 183
183 SetMoleType(MoleType::None); 184 SetMoleType(MoleType::None);
184 SetMoleScale(4); 185 SetMoleScale(4);
diff --git a/src/core/hle/service/mii/types/raw_data.cpp b/src/core/hle/service/mii/types/raw_data.cpp
index 5143abcc8..0e1a07fd7 100644
--- a/src/core/hle/service/mii/types/raw_data.cpp
+++ b/src/core/hle/service/mii/types/raw_data.cpp
@@ -1716,18 +1716,18 @@ const std::array<RandomMiiData4, 18> RandomMiiMouthType{
1716const std::array<RandomMiiData2, 3> RandomMiiGlassType{ 1716const std::array<RandomMiiData2, 3> RandomMiiGlassType{
1717 RandomMiiData2{ 1717 RandomMiiData2{
1718 .arg_1 = 0, 1718 .arg_1 = 0,
1719 .values_count = 9, 1719 .values_count = 4,
1720 .values = {90, 94, 96, 100, 0, 0, 0, 0, 0}, 1720 .values = {90, 94, 96, 100},
1721 }, 1721 },
1722 RandomMiiData2{ 1722 RandomMiiData2{
1723 .arg_1 = 1, 1723 .arg_1 = 1,
1724 .values_count = 9, 1724 .values_count = 8,
1725 .values = {83, 86, 90, 93, 94, 96, 98, 100, 0}, 1725 .values = {83, 86, 90, 93, 94, 96, 98, 100},
1726 }, 1726 },
1727 RandomMiiData2{ 1727 RandomMiiData2{
1728 .arg_1 = 2, 1728 .arg_1 = 2,
1729 .values_count = 9, 1729 .values_count = 8,
1730 .values = {78, 83, 0, 93, 0, 0, 98, 100, 0}, 1730 .values = {78, 83, 0, 93, 0, 0, 98, 100},
1731 }, 1731 },
1732}; 1732};
1733 1733
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index da8eab7ee..279f0daa1 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -109,10 +109,11 @@ void MaxwellDMA::Launch() {
109 const bool is_const_a_dst = regs.remap_const.dst_x == RemapConst::Swizzle::CONST_A; 109 const bool is_const_a_dst = regs.remap_const.dst_x == RemapConst::Swizzle::CONST_A;
110 if (regs.launch_dma.remap_enable != 0 && is_const_a_dst) { 110 if (regs.launch_dma.remap_enable != 0 && is_const_a_dst) {
111 ASSERT(regs.remap_const.component_size_minus_one == 3); 111 ASSERT(regs.remap_const.component_size_minus_one == 3);
112 accelerate.BufferClear(regs.offset_out, regs.line_length_in, regs.remap_consta_value); 112 accelerate.BufferClear(regs.offset_out, regs.line_length_in,
113 regs.remap_const.remap_consta_value);
113 read_buffer.resize_destructive(regs.line_length_in * sizeof(u32)); 114 read_buffer.resize_destructive(regs.line_length_in * sizeof(u32));
114 std::span<u32> span(reinterpret_cast<u32*>(read_buffer.data()), regs.line_length_in); 115 std::span<u32> span(reinterpret_cast<u32*>(read_buffer.data()), regs.line_length_in);
115 std::ranges::fill(span, regs.remap_consta_value); 116 std::ranges::fill(span, regs.remap_const.remap_consta_value);
116 memory_manager.WriteBlockUnsafe(regs.offset_out, 117 memory_manager.WriteBlockUnsafe(regs.offset_out,
117 reinterpret_cast<u8*>(read_buffer.data()), 118 reinterpret_cast<u8*>(read_buffer.data()),
118 regs.line_length_in * sizeof(u32)); 119 regs.line_length_in * sizeof(u32));
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index 69e26cb32..1a43e24b6 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -214,14 +214,15 @@ public:
214 NO_WRITE = 6, 214 NO_WRITE = 6,
215 }; 215 };
216 216
217 PackedGPUVAddr address; 217 u32 remap_consta_value;
218 u32 remap_constb_value;
218 219
219 union { 220 union {
221 BitField<0, 12, u32> dst_components_raw;
220 BitField<0, 3, Swizzle> dst_x; 222 BitField<0, 3, Swizzle> dst_x;
221 BitField<4, 3, Swizzle> dst_y; 223 BitField<4, 3, Swizzle> dst_y;
222 BitField<8, 3, Swizzle> dst_z; 224 BitField<8, 3, Swizzle> dst_z;
223 BitField<12, 3, Swizzle> dst_w; 225 BitField<12, 3, Swizzle> dst_w;
224 BitField<0, 12, u32> dst_components_raw;
225 BitField<16, 2, u32> component_size_minus_one; 226 BitField<16, 2, u32> component_size_minus_one;
226 BitField<20, 2, u32> num_src_components_minus_one; 227 BitField<20, 2, u32> num_src_components_minus_one;
227 BitField<24, 2, u32> num_dst_components_minus_one; 228 BitField<24, 2, u32> num_dst_components_minus_one;
@@ -274,55 +275,57 @@ private:
274 struct Regs { 275 struct Regs {
275 union { 276 union {
276 struct { 277 struct {
277 u32 reserved[0x40]; 278 INSERT_PADDING_BYTES_NOINIT(0x100);
278 u32 nop; 279 u32 nop;
279 u32 reserved01[0xf]; 280 INSERT_PADDING_BYTES_NOINIT(0x3C);
280 u32 pm_trigger; 281 u32 pm_trigger;
281 u32 reserved02[0x3f]; 282 INSERT_PADDING_BYTES_NOINIT(0xFC);
282 Semaphore semaphore; 283 Semaphore semaphore;
283 u32 reserved03[0x2]; 284 INSERT_PADDING_BYTES_NOINIT(0x8);
284 RenderEnable render_enable; 285 RenderEnable render_enable;
285 PhysMode src_phys_mode; 286 PhysMode src_phys_mode;
286 PhysMode dst_phys_mode; 287 PhysMode dst_phys_mode;
287 u32 reserved04[0x26]; 288 INSERT_PADDING_BYTES_NOINIT(0x98);
288 LaunchDMA launch_dma; 289 LaunchDMA launch_dma;
289 u32 reserved05[0x3f]; 290 INSERT_PADDING_BYTES_NOINIT(0xFC);
290 PackedGPUVAddr offset_in; 291 PackedGPUVAddr offset_in;
291 PackedGPUVAddr offset_out; 292 PackedGPUVAddr offset_out;
292 s32 pitch_in; 293 s32 pitch_in;
293 s32 pitch_out; 294 s32 pitch_out;
294 u32 line_length_in; 295 u32 line_length_in;
295 u32 line_count; 296 u32 line_count;
296 u32 reserved06[0xb6]; 297 INSERT_PADDING_BYTES_NOINIT(0x2E0);
297 u32 remap_consta_value;
298 u32 remap_constb_value;
299 RemapConst remap_const; 298 RemapConst remap_const;
300 DMA::Parameters dst_params; 299 DMA::Parameters dst_params;
301 u32 reserved07[0x1]; 300 INSERT_PADDING_BYTES_NOINIT(0x4);
302 DMA::Parameters src_params; 301 DMA::Parameters src_params;
303 u32 reserved08[0x275]; 302 INSERT_PADDING_BYTES_NOINIT(0x9D4);
304 u32 pm_trigger_end; 303 u32 pm_trigger_end;
305 u32 reserved09[0x3ba]; 304 INSERT_PADDING_BYTES_NOINIT(0xEE8);
306 }; 305 };
307 std::array<u32, NUM_REGS> reg_array; 306 std::array<u32, NUM_REGS> reg_array;
308 }; 307 };
309 } regs{}; 308 } regs{};
309 static_assert(sizeof(Regs) == NUM_REGS * 4);
310 310
311#define ASSERT_REG_POSITION(field_name, position) \ 311#define ASSERT_REG_POSITION(field_name, position) \
312 static_assert(offsetof(MaxwellDMA::Regs, field_name) == position * 4, \ 312 static_assert(offsetof(MaxwellDMA::Regs, field_name) == position, \
313 "Field " #field_name " has invalid position") 313 "Field " #field_name " has invalid position")
314 314
315 ASSERT_REG_POSITION(launch_dma, 0xC0); 315 ASSERT_REG_POSITION(semaphore, 0x240);
316 ASSERT_REG_POSITION(offset_in, 0x100); 316 ASSERT_REG_POSITION(render_enable, 0x254);
317 ASSERT_REG_POSITION(offset_out, 0x102); 317 ASSERT_REG_POSITION(src_phys_mode, 0x260);
318 ASSERT_REG_POSITION(pitch_in, 0x104); 318 ASSERT_REG_POSITION(launch_dma, 0x300);
319 ASSERT_REG_POSITION(pitch_out, 0x105); 319 ASSERT_REG_POSITION(offset_in, 0x400);
320 ASSERT_REG_POSITION(line_length_in, 0x106); 320 ASSERT_REG_POSITION(offset_out, 0x408);
321 ASSERT_REG_POSITION(line_count, 0x107); 321 ASSERT_REG_POSITION(pitch_in, 0x410);
322 ASSERT_REG_POSITION(remap_const, 0x1C0); 322 ASSERT_REG_POSITION(pitch_out, 0x414);
323 ASSERT_REG_POSITION(dst_params, 0x1C3); 323 ASSERT_REG_POSITION(line_length_in, 0x418);
324 ASSERT_REG_POSITION(src_params, 0x1CA); 324 ASSERT_REG_POSITION(line_count, 0x41C);
325 325 ASSERT_REG_POSITION(remap_const, 0x700);
326 ASSERT_REG_POSITION(dst_params, 0x70C);
327 ASSERT_REG_POSITION(src_params, 0x728);
328 ASSERT_REG_POSITION(pm_trigger_end, 0x1114);
326#undef ASSERT_REG_POSITION 329#undef ASSERT_REG_POSITION
327}; 330};
328 331
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 35bf80ea3..208e88533 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -185,7 +185,7 @@ struct FormatTuple {
185 {VK_FORMAT_BC2_SRGB_BLOCK}, // BC2_SRGB 185 {VK_FORMAT_BC2_SRGB_BLOCK}, // BC2_SRGB
186 {VK_FORMAT_BC3_SRGB_BLOCK}, // BC3_SRGB 186 {VK_FORMAT_BC3_SRGB_BLOCK}, // BC3_SRGB
187 {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7_SRGB 187 {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7_SRGB
188 {VK_FORMAT_R4G4B4A4_UNORM_PACK16}, // A4B4G4R4_UNORM 188 {VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT}, // A4B4G4R4_UNORM
189 {VK_FORMAT_R4G4_UNORM_PACK8}, // G4R4_UNORM 189 {VK_FORMAT_R4G4_UNORM_PACK8}, // G4R4_UNORM
190 {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB 190 {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB
191 {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB 191 {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index b3e17c332..285a50ea4 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -600,7 +600,7 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
600} 600}
601 601
602void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4>& swizzle, 602void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4>& swizzle,
603 bool emulate_bgr565) { 603 bool emulate_bgr565, bool emulate_a4b4g4r4) {
604 switch (format) { 604 switch (format) {
605 case PixelFormat::A1B5G5R5_UNORM: 605 case PixelFormat::A1B5G5R5_UNORM:
606 std::ranges::transform(swizzle, swizzle.begin(), SwapBlueRed); 606 std::ranges::transform(swizzle, swizzle.begin(), SwapBlueRed);
@@ -616,6 +616,11 @@ void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4
616 case PixelFormat::G4R4_UNORM: 616 case PixelFormat::G4R4_UNORM:
617 std::ranges::transform(swizzle, swizzle.begin(), SwapGreenRed); 617 std::ranges::transform(swizzle, swizzle.begin(), SwapGreenRed);
618 break; 618 break;
619 case PixelFormat::A4B4G4R4_UNORM:
620 if (emulate_a4b4g4r4) {
621 std::ranges::reverse(swizzle);
622 }
623 break;
619 default: 624 default:
620 break; 625 break;
621 } 626 }
@@ -1649,7 +1654,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1649 }; 1654 };
1650 if (!info.IsRenderTarget()) { 1655 if (!info.IsRenderTarget()) {
1651 swizzle = info.Swizzle(); 1656 swizzle = info.Swizzle();
1652 TryTransformSwizzleIfNeeded(format, swizzle, device->MustEmulateBGR565()); 1657 TryTransformSwizzleIfNeeded(format, swizzle, device->MustEmulateBGR565(),
1658 !device->IsExt4444FormatsSupported());
1653 if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { 1659 if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
1654 std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); 1660 std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed);
1655 } 1661 }
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 617417040..a88ff5ca5 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -76,6 +76,11 @@ constexpr std::array VK_FORMAT_R32G32B32_SFLOAT{
76 VK_FORMAT_UNDEFINED, 76 VK_FORMAT_UNDEFINED,
77}; 77};
78 78
79constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{
80 VK_FORMAT_R4G4B4A4_UNORM_PACK16,
81 VK_FORMAT_UNDEFINED,
82};
83
79} // namespace Alternatives 84} // namespace Alternatives
80 85
81enum class NvidiaArchitecture { 86enum class NvidiaArchitecture {
@@ -110,6 +115,8 @@ constexpr const VkFormat* GetFormatAlternatives(VkFormat format) {
110 return Alternatives::R8G8B8_SSCALED.data(); 115 return Alternatives::R8G8B8_SSCALED.data();
111 case VK_FORMAT_R32G32B32_SFLOAT: 116 case VK_FORMAT_R32G32B32_SFLOAT:
112 return Alternatives::VK_FORMAT_R32G32B32_SFLOAT.data(); 117 return Alternatives::VK_FORMAT_R32G32B32_SFLOAT.data();
118 case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT:
119 return Alternatives::VK_FORMAT_A4B4G4R4_UNORM_PACK16.data();
113 default: 120 default:
114 return nullptr; 121 return nullptr;
115 } 122 }
@@ -238,6 +245,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
238 VK_FORMAT_R32_SINT, 245 VK_FORMAT_R32_SINT,
239 VK_FORMAT_R32_UINT, 246 VK_FORMAT_R32_UINT,
240 VK_FORMAT_R4G4B4A4_UNORM_PACK16, 247 VK_FORMAT_R4G4B4A4_UNORM_PACK16,
248 VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT,
241 VK_FORMAT_R4G4_UNORM_PACK8, 249 VK_FORMAT_R4G4_UNORM_PACK8,
242 VK_FORMAT_R5G5B5A1_UNORM_PACK16, 250 VK_FORMAT_R5G5B5A1_UNORM_PACK16,
243 VK_FORMAT_R5G6B5_UNORM_PACK16, 251 VK_FORMAT_R5G6B5_UNORM_PACK16,
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 488fdd313..6c7fa34e5 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -45,6 +45,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
45 FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \ 45 FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \
46 FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \ 46 FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
47 FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \ 47 FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \
48 FEATURE(EXT, 4444Formats, 4444_FORMATS, format_a4b4g4r4) \
48 FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \ 49 FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \
49 FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \ 50 FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \
50 FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART, \ 51 FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART, \
@@ -97,6 +98,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
97 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \ 98 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \
98 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \ 99 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \
99 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME) \ 100 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME) \
101 EXTENSION_NAME(VK_EXT_4444_FORMATS_EXTENSION_NAME) \
100 EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME) \ 102 EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME) \
101 EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \ 103 EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \
102 EXTENSION_NAME(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME) \ 104 EXTENSION_NAME(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME) \
@@ -144,6 +146,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
144#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \ 146#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \
145 FEATURE_NAME(custom_border_color, customBorderColors) \ 147 FEATURE_NAME(custom_border_color, customBorderColors) \
146 FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \ 148 FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \
149 FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \
147 FEATURE_NAME(index_type_uint8, indexTypeUint8) \ 150 FEATURE_NAME(index_type_uint8, indexTypeUint8) \
148 FEATURE_NAME(primitive_topology_list_restart, primitiveTopologyListRestart) \ 151 FEATURE_NAME(primitive_topology_list_restart, primitiveTopologyListRestart) \
149 FEATURE_NAME(provoking_vertex, provokingVertexLast) \ 152 FEATURE_NAME(provoking_vertex, provokingVertexLast) \
@@ -488,6 +491,11 @@ public:
488 return extensions.extended_dynamic_state3; 491 return extensions.extended_dynamic_state3;
489 } 492 }
490 493
494 /// Returns true if the device supports VK_EXT_4444_formats.
495 bool IsExt4444FormatsSupported() const {
496 return features.format_a4b4g4r4.formatA4B4G4R4;
497 }
498
491 /// Returns true if the device supports VK_EXT_extended_dynamic_state3. 499 /// Returns true if the device supports VK_EXT_extended_dynamic_state3.
492 bool IsExtExtendedDynamicState3BlendingSupported() const { 500 bool IsExtExtendedDynamicState3BlendingSupported() const {
493 return dynamic_state3_blending; 501 return dynamic_state3_blending;