diff options
91 files changed, 2263 insertions, 239 deletions
diff --git a/.github/ISSUE_TEMPLATE/blank_issue_template.yml b/.github/ISSUE_TEMPLATE/blank_issue_template.yml new file mode 100644 index 000000000..49b7f3822 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/blank_issue_template.yml | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | name: New Issue (Developers Only) | ||
| 2 | description: A blank issue template for developers only. If you are not a developer, do not use this issue template. Your issue WILL BE CLOSED if you do not use the appropriate issue template. | ||
| 3 | body: | ||
| 4 | - type: markdown | ||
| 5 | attributes: | ||
| 6 | value: | | ||
| 7 | **If you are not a developer, do not use this issue template. Your issue WILL BE CLOSED if you do not use the appropriate issue template.** | ||
| 8 | - type: textarea | ||
| 9 | attributes: | ||
| 10 | label: "Issue" | ||
diff --git a/.github/ISSUE_TEMPLATE/bug-report-feature-request.md b/.github/ISSUE_TEMPLATE/bug-report-feature-request.md deleted file mode 100644 index 808613237..000000000 --- a/.github/ISSUE_TEMPLATE/bug-report-feature-request.md +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | --- | ||
| 2 | name: Bug Report / Feature Request | ||
| 3 | about: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with yuzu or you are requesting a feature you believe would make yuzu better. | ||
| 4 | title: '' | ||
| 5 | labels: '' | ||
| 6 | assignees: '' | ||
| 7 | |||
| 8 | --- | ||
| 9 | |||
| 10 | <!--- | ||
| 11 | Please keep in mind yuzu is EXPERIMENTAL SOFTWARE. | ||
| 12 | |||
| 13 | Please read the FAQ: | ||
| 14 | https://yuzu-emu.org/wiki/faq/ | ||
| 15 | |||
| 16 | THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO: | ||
| 17 | https://community.citra-emu.org/ | ||
| 18 | |||
| 19 | If the FAQ does not answer your question, please go to: | ||
| 20 | https://community.citra-emu.org/ | ||
| 21 | |||
| 22 | When submitting an issue, please check the following: | ||
| 23 | |||
| 24 | - You have read the above. | ||
| 25 | - You have provided the version (commit hash) of yuzu you are using. | ||
| 26 | - You have provided sufficient detail for the issue to be reproduced. | ||
| 27 | - You have provided system specs (if relevant). | ||
| 28 | - Please also provide: | ||
| 29 | - For any issues, a log file | ||
| 30 | - For crashes, a backtrace. | ||
| 31 | - For graphical issues, comparison screenshots with real hardware. | ||
| 32 | - For emulation inaccuracies, a test-case (if able). | ||
| 33 | |||
| 34 | --> | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | |||
| 39 | |||
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..1405ccce8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | name: Bug Report | ||
| 2 | description: File a bug report | ||
| 3 | body: | ||
| 4 | - type: markdown | ||
| 5 | attributes: | ||
| 6 | value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with yuzu. | ||
| 7 | - type: checkboxes | ||
| 8 | attributes: | ||
| 9 | label: Is there an existing issue for this? | ||
| 10 | description: Please search to see if an issue already exists for the bug you encountered. | ||
| 11 | options: | ||
| 12 | - label: I have searched the existing issues | ||
| 13 | required: true | ||
| 14 | - type: input | ||
| 15 | attributes: | ||
| 16 | label: Affected Build(s) | ||
| 17 | description: List the affected build(s) that this issue applies to. | ||
| 18 | placeholder: Mainline 1234 / Early Access 1234 | ||
| 19 | validations: | ||
| 20 | required: true | ||
| 21 | - type: textarea | ||
| 22 | id: issue-desc | ||
| 23 | attributes: | ||
| 24 | label: Description of Issue | ||
| 25 | description: A brief description of the issue encountered along with any images and/or videos. | ||
| 26 | validations: | ||
| 27 | required: true | ||
| 28 | - type: textarea | ||
| 29 | id: expected-behavior | ||
| 30 | attributes: | ||
| 31 | label: Expected Behavior | ||
| 32 | description: A brief description of how it is expected to work along with any images and/or videos. | ||
| 33 | validations: | ||
| 34 | required: true | ||
| 35 | - type: textarea | ||
| 36 | id: reproduction-steps | ||
| 37 | attributes: | ||
| 38 | label: Reproduction Steps | ||
| 39 | description: A brief explanation of how to reproduce this issue. If possible, provide a save file to aid in reproducing the issue. | ||
| 40 | validations: | ||
| 41 | required: true | ||
| 42 | - type: textarea | ||
| 43 | id: log | ||
| 44 | attributes: | ||
| 45 | label: Log File | ||
| 46 | description: A log file will help our developers to better diagnose and fix the issue. | ||
| 47 | validations: | ||
| 48 | required: true | ||
| 49 | - type: textarea | ||
| 50 | id: system-config | ||
| 51 | attributes: | ||
| 52 | label: System Configuration | ||
| 53 | placeholder: | | ||
| 54 | CPU: Intel i5-10400 / AMD Ryzen 5 3600 | ||
| 55 | GPU/Driver: NVIDIA GeForce GTX 1060 (Driver 512.95) | ||
| 56 | RAM: 16GB DDR4-3200 | ||
| 57 | OS: Windows 11 22H2 (Build 22621.819) | ||
| 58 | value: | | ||
| 59 | CPU: | ||
| 60 | GPU/Driver: | ||
| 61 | RAM: | ||
| 62 | OS: | ||
| 63 | validations: | ||
| 64 | required: true | ||
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..766da2c87 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | name: Feature Request | ||
| 2 | description: File a feature request | ||
| 3 | labels: "request" | ||
| 4 | body: | ||
| 5 | - type: markdown | ||
| 6 | attributes: | ||
| 7 | value: Tech support does not belong here. You should only file an issue here if you are requesting a feature you believe would make yuzu better. | ||
| 8 | - type: checkboxes | ||
| 9 | attributes: | ||
| 10 | label: Is there an existing issue for this? | ||
| 11 | description: Please search to see if an issue already exists for the feature you are requesting. | ||
| 12 | options: | ||
| 13 | - label: I have searched the existing issues | ||
| 14 | required: true | ||
| 15 | - type: textarea | ||
| 16 | id: what-feature | ||
| 17 | attributes: | ||
| 18 | label: What feature are you suggesting? | ||
| 19 | description: A brief description of the requested feature. | ||
| 20 | validations: | ||
| 21 | required: true | ||
| 22 | - type: textarea | ||
| 23 | id: why-feature | ||
| 24 | attributes: | ||
| 25 | label: Why would this feature be useful? | ||
| 26 | description: A brief description of why this feature would make yuzu better. | ||
| 27 | validations: | ||
| 28 | required: true | ||
diff --git a/.reuse/dep5 b/.reuse/dep5 index 9a90f9eb6..3810f2c41 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 | |||
| @@ -132,10 +132,6 @@ Files: vcpkg.json | |||
| 132 | Copyright: 2022 yuzu Emulator Project | 132 | Copyright: 2022 yuzu Emulator Project |
| 133 | License: GPL-3.0-or-later | 133 | License: GPL-3.0-or-later |
| 134 | 134 | ||
| 135 | Files: .github/ISSUE_TEMPLATE/config.yml | 135 | Files: .github/ISSUE_TEMPLATE/* |
| 136 | Copyright: 2020 tgsm <doodrabbit@hotmail.com> | 136 | Copyright: 2022 yuzu Emulator Project |
| 137 | License: GPL-2.0-or-later | ||
| 138 | |||
| 139 | Files: .github/ISSUE_TEMPLATE/bug-report-feature-request.md | ||
| 140 | Copyright: 2016 MerryMage | ||
| 141 | License: GPL-2.0-or-later | 137 | License: GPL-2.0-or-later |
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject 424fdb5c5026ec5bdd7553271190397f63fb503 | Subproject 07c614f91b0af5335e1f9c0653c2d75e7b5f53b | ||
diff --git a/externals/microprofile/microprofileui.h b/externals/microprofile/microprofileui.h index 1357a08fd..ca9fe7063 100644 --- a/externals/microprofile/microprofileui.h +++ b/externals/microprofile/microprofileui.h | |||
| @@ -845,8 +845,6 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int | |||
| 845 | MicroProfile& S = *MicroProfileGet(); | 845 | MicroProfile& S = *MicroProfileGet(); |
| 846 | MP_DEBUG_DUMP_RANGE(); | 846 | MP_DEBUG_DUMP_RANGE(); |
| 847 | int nY = nBaseY - UI.nOffsetY; | 847 | int nY = nBaseY - UI.nOffsetY; |
| 848 | int64_t nNumBoxes = 0; | ||
| 849 | int64_t nNumLines = 0; | ||
| 850 | 848 | ||
| 851 | uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY; | 849 | uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY; |
| 852 | MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; | 850 | MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; |
| @@ -1149,7 +1147,6 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int | |||
| 1149 | } | 1147 | } |
| 1150 | } | 1148 | } |
| 1151 | #endif | 1149 | #endif |
| 1152 | ++nNumBoxes; | ||
| 1153 | } | 1150 | } |
| 1154 | else | 1151 | else |
| 1155 | { | 1152 | { |
| @@ -1165,7 +1162,6 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int | |||
| 1165 | } | 1162 | } |
| 1166 | nLinesDrawn[nStackPos] = nLineX; | 1163 | nLinesDrawn[nStackPos] = nLineX; |
| 1167 | MicroProfileDrawLineVertical(nLineX, fYStart + 0.5f, fYEnd + 0.5f, nColor|UI.nOpacityForeground); | 1164 | MicroProfileDrawLineVertical(nLineX, fYStart + 0.5f, fYEnd + 0.5f, nColor|UI.nOpacityForeground); |
| 1168 | ++nNumLines; | ||
| 1169 | } | 1165 | } |
| 1170 | } | 1166 | } |
| 1171 | nStackPos--; | 1167 | nStackPos--; |
diff --git a/src/audio_core/renderer/performance/performance_manager.cpp b/src/audio_core/renderer/performance/performance_manager.cpp index fd5873e1e..8aa0f5ed0 100644 --- a/src/audio_core/renderer/performance/performance_manager.cpp +++ b/src/audio_core/renderer/performance/performance_manager.cpp | |||
| @@ -26,6 +26,7 @@ void PerformanceManager::CreateImpl(const size_t version) { | |||
| 26 | impl = std::make_unique< | 26 | impl = std::make_unique< |
| 27 | PerformanceManagerImpl<PerformanceVersion::Version1, PerformanceFrameHeaderVersion1, | 27 | PerformanceManagerImpl<PerformanceVersion::Version1, PerformanceFrameHeaderVersion1, |
| 28 | PerformanceEntryVersion1, PerformanceDetailVersion1>>(); | 28 | PerformanceEntryVersion1, PerformanceDetailVersion1>>(); |
| 29 | break; | ||
| 29 | } | 30 | } |
| 30 | } | 31 | } |
| 31 | 32 | ||
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index c0555f840..b7c15c191 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -34,6 +34,8 @@ add_library(common STATIC | |||
| 34 | bit_util.h | 34 | bit_util.h |
| 35 | cityhash.cpp | 35 | cityhash.cpp |
| 36 | cityhash.h | 36 | cityhash.h |
| 37 | cache_management.cpp | ||
| 38 | cache_management.h | ||
| 37 | common_funcs.h | 39 | common_funcs.h |
| 38 | common_types.h | 40 | common_types.h |
| 39 | concepts.h | 41 | concepts.h |
diff --git a/src/common/atomic_helpers.h b/src/common/atomic_helpers.h index bef5015c1..aef3b66a4 100644 --- a/src/common/atomic_helpers.h +++ b/src/common/atomic_helpers.h | |||
| @@ -156,6 +156,7 @@ AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN { | |||
| 156 | break; | 156 | break; |
| 157 | default: | 157 | default: |
| 158 | assert(false); | 158 | assert(false); |
| 159 | break; | ||
| 159 | } | 160 | } |
| 160 | } | 161 | } |
| 161 | 162 | ||
diff --git a/src/common/cache_management.cpp b/src/common/cache_management.cpp new file mode 100644 index 000000000..57810b76a --- /dev/null +++ b/src/common/cache_management.cpp | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <cstring> | ||
| 5 | |||
| 6 | #include "alignment.h" | ||
| 7 | #include "cache_management.h" | ||
| 8 | #include "common_types.h" | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | #if defined(ARCHITECTURE_x86_64) | ||
| 13 | |||
| 14 | // Most cache operations are no-ops on x86 | ||
| 15 | |||
| 16 | void DataCacheLineCleanByVAToPoU(void* start, size_t size) {} | ||
| 17 | void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size) {} | ||
| 18 | void DataCacheLineCleanByVAToPoC(void* start, size_t size) {} | ||
| 19 | void DataCacheZeroByVA(void* start, size_t size) { | ||
| 20 | std::memset(start, 0, size); | ||
| 21 | } | ||
| 22 | |||
| 23 | #elif defined(ARCHITECTURE_arm64) | ||
| 24 | |||
| 25 | // BS/DminLine is log2(cache size in words), we want size in bytes | ||
| 26 | #define EXTRACT_DMINLINE(ctr_el0) (1 << ((((ctr_el0) >> 16) & 0xf) + 2)) | ||
| 27 | #define EXTRACT_BS(dczid_el0) (1 << (((dczid_el0)&0xf) + 2)) | ||
| 28 | |||
| 29 | #define DEFINE_DC_OP(op_name, function_name) \ | ||
| 30 | void function_name(void* start, size_t size) { \ | ||
| 31 | size_t ctr_el0; \ | ||
| 32 | asm volatile("mrs %[ctr_el0], ctr_el0\n\t" : [ctr_el0] "=r"(ctr_el0)); \ | ||
| 33 | size_t cacheline_size = EXTRACT_DMINLINE(ctr_el0); \ | ||
| 34 | uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \ | ||
| 35 | uintptr_t va_end = va_start + size; \ | ||
| 36 | for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \ | ||
| 37 | asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \ | ||
| 38 | } \ | ||
| 39 | } | ||
| 40 | |||
| 41 | #define DEFINE_DC_OP_DCZID(op_name, function_name) \ | ||
| 42 | void function_name(void* start, size_t size) { \ | ||
| 43 | size_t dczid_el0; \ | ||
| 44 | asm volatile("mrs %[dczid_el0], dczid_el0\n\t" : [dczid_el0] "=r"(dczid_el0)); \ | ||
| 45 | size_t cacheline_size = EXTRACT_BS(dczid_el0); \ | ||
| 46 | uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \ | ||
| 47 | uintptr_t va_end = va_start + size; \ | ||
| 48 | for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \ | ||
| 49 | asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \ | ||
| 50 | } \ | ||
| 51 | } | ||
| 52 | |||
| 53 | DEFINE_DC_OP(cvau, DataCacheLineCleanByVAToPoU); | ||
| 54 | DEFINE_DC_OP(civac, DataCacheLineCleanAndInvalidateByVAToPoC); | ||
| 55 | DEFINE_DC_OP(cvac, DataCacheLineCleanByVAToPoC); | ||
| 56 | DEFINE_DC_OP_DCZID(zva, DataCacheZeroByVA); | ||
| 57 | |||
| 58 | #endif | ||
| 59 | |||
| 60 | } // namespace Common | ||
diff --git a/src/common/cache_management.h b/src/common/cache_management.h new file mode 100644 index 000000000..e467b87e4 --- /dev/null +++ b/src/common/cache_management.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "stdlib.h" | ||
| 7 | |||
| 8 | namespace Common { | ||
| 9 | |||
| 10 | // Data cache instructions enabled at EL0 by SCTLR_EL1.UCI. | ||
| 11 | // VA = virtual address | ||
| 12 | // PoC = point of coherency | ||
| 13 | // PoU = point of unification | ||
| 14 | |||
| 15 | // dc cvau | ||
| 16 | void DataCacheLineCleanByVAToPoU(void* start, size_t size); | ||
| 17 | |||
| 18 | // dc civac | ||
| 19 | void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size); | ||
| 20 | |||
| 21 | // dc cvac | ||
| 22 | void DataCacheLineCleanByVAToPoC(void* start, size_t size); | ||
| 23 | |||
| 24 | // dc zva | ||
| 25 | void DataCacheZeroByVA(void* start, size_t size); | ||
| 26 | |||
| 27 | } // namespace Common | ||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 705667080..5629980d9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -120,6 +120,8 @@ add_library(core STATIC | |||
| 120 | file_sys/vfs_vector.h | 120 | file_sys/vfs_vector.h |
| 121 | file_sys/xts_archive.cpp | 121 | file_sys/xts_archive.cpp |
| 122 | file_sys/xts_archive.h | 122 | file_sys/xts_archive.h |
| 123 | frontend/applets/cabinet.cpp | ||
| 124 | frontend/applets/cabinet.h | ||
| 123 | frontend/applets/controller.cpp | 125 | frontend/applets/controller.cpp |
| 124 | frontend/applets/controller.h | 126 | frontend/applets/controller.h |
| 125 | frontend/applets/error.cpp | 127 | frontend/applets/error.cpp |
| @@ -312,6 +314,8 @@ add_library(core STATIC | |||
| 312 | hle/service/am/applet_ae.h | 314 | hle/service/am/applet_ae.h |
| 313 | hle/service/am/applet_oe.cpp | 315 | hle/service/am/applet_oe.cpp |
| 314 | hle/service/am/applet_oe.h | 316 | hle/service/am/applet_oe.h |
| 317 | hle/service/am/applets/applet_cabinet.cpp | ||
| 318 | hle/service/am/applets/applet_cabinet.h | ||
| 315 | hle/service/am/applets/applet_controller.cpp | 319 | hle/service/am/applets/applet_controller.cpp |
| 316 | hle/service/am/applets/applet_controller.h | 320 | hle/service/am/applets/applet_controller.h |
| 317 | hle/service/am/applets/applet_error.cpp | 321 | hle/service/am/applets/applet_error.cpp |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index afb7fb3a0..cb53d64ba 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -348,7 +348,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* | |||
| 348 | if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { | 348 | if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { |
| 349 | config.unsafe_optimizations = true; | 349 | config.unsafe_optimizations = true; |
| 350 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; | 350 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; |
| 351 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; | ||
| 352 | config.fastmem_address_space_bits = 64; | 351 | config.fastmem_address_space_bits = 64; |
| 353 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; | 352 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; |
| 354 | } | 353 | } |
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 339f971e6..1a8e02e6a 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp | |||
| @@ -27,12 +27,21 @@ static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) { | |||
| 27 | const u8* buffer_start = reinterpret_cast<const u8*>(&buffer); | 27 | const u8* buffer_start = reinterpret_cast<const u8*>(&buffer); |
| 28 | std::span<const u8> received_data{buffer_start, buffer_start + bytes_read}; | 28 | std::span<const u8> received_data{buffer_start, buffer_start + bytes_read}; |
| 29 | c(received_data); | 29 | c(received_data); |
| 30 | AsyncReceiveInto(r, buffer, c); | ||
| 30 | } | 31 | } |
| 31 | |||
| 32 | AsyncReceiveInto(r, buffer, c); | ||
| 33 | }); | 32 | }); |
| 34 | } | 33 | } |
| 35 | 34 | ||
| 35 | template <typename Callback> | ||
| 36 | static void AsyncAccept(boost::asio::ip::tcp::acceptor& acceptor, Callback&& c) { | ||
| 37 | acceptor.async_accept([&, c](const boost::system::error_code& error, auto&& peer_socket) { | ||
| 38 | if (!error.failed()) { | ||
| 39 | c(peer_socket); | ||
| 40 | AsyncAccept(acceptor, c); | ||
| 41 | } | ||
| 42 | }); | ||
| 43 | } | ||
| 44 | |||
| 36 | template <typename Readable, typename Buffer> | 45 | template <typename Readable, typename Buffer> |
| 37 | static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) { | 46 | static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) { |
| 38 | static_assert(std::is_trivial_v<Buffer>); | 47 | static_assert(std::is_trivial_v<Buffer>); |
| @@ -59,9 +68,7 @@ namespace Core { | |||
| 59 | 68 | ||
| 60 | class DebuggerImpl : public DebuggerBackend { | 69 | class DebuggerImpl : public DebuggerBackend { |
| 61 | public: | 70 | public: |
| 62 | explicit DebuggerImpl(Core::System& system_, u16 port) | 71 | explicit DebuggerImpl(Core::System& system_, u16 port) : system{system_} { |
| 63 | : system{system_}, signal_pipe{io_context}, client_socket{io_context} { | ||
| 64 | frontend = std::make_unique<GDBStub>(*this, system); | ||
| 65 | InitializeServer(port); | 72 | InitializeServer(port); |
| 66 | } | 73 | } |
| 67 | 74 | ||
| @@ -70,39 +77,42 @@ public: | |||
| 70 | } | 77 | } |
| 71 | 78 | ||
| 72 | bool SignalDebugger(SignalInfo signal_info) { | 79 | bool SignalDebugger(SignalInfo signal_info) { |
| 73 | { | 80 | std::scoped_lock lk{connection_lock}; |
| 74 | std::scoped_lock lk{connection_lock}; | ||
| 75 | 81 | ||
| 76 | if (stopped) { | 82 | if (stopped || !state) { |
| 77 | // Do not notify the debugger about another event. | 83 | // Do not notify the debugger about another event. |
| 78 | // It should be ignored. | 84 | // It should be ignored. |
| 79 | return false; | 85 | return false; |
| 80 | } | ||
| 81 | |||
| 82 | // Set up the state. | ||
| 83 | stopped = true; | ||
| 84 | info = signal_info; | ||
| 85 | } | 86 | } |
| 86 | 87 | ||
| 88 | // Set up the state. | ||
| 89 | stopped = true; | ||
| 90 | state->info = signal_info; | ||
| 91 | |||
| 87 | // Write a single byte into the pipe to wake up the debug interface. | 92 | // Write a single byte into the pipe to wake up the debug interface. |
| 88 | boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); | 93 | boost::asio::write(state->signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); |
| 94 | |||
| 89 | return true; | 95 | return true; |
| 90 | } | 96 | } |
| 91 | 97 | ||
| 98 | // These functions are callbacks from the frontend, and the lock will be held. | ||
| 99 | // There is no need to relock it. | ||
| 100 | |||
| 92 | std::span<const u8> ReadFromClient() override { | 101 | std::span<const u8> ReadFromClient() override { |
| 93 | return ReceiveInto(client_socket, client_data); | 102 | return ReceiveInto(state->client_socket, state->client_data); |
| 94 | } | 103 | } |
| 95 | 104 | ||
| 96 | void WriteToClient(std::span<const u8> data) override { | 105 | void WriteToClient(std::span<const u8> data) override { |
| 97 | boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes())); | 106 | boost::asio::write(state->client_socket, |
| 107 | boost::asio::buffer(data.data(), data.size_bytes())); | ||
| 98 | } | 108 | } |
| 99 | 109 | ||
| 100 | void SetActiveThread(Kernel::KThread* thread) override { | 110 | void SetActiveThread(Kernel::KThread* thread) override { |
| 101 | active_thread = thread; | 111 | state->active_thread = thread; |
| 102 | } | 112 | } |
| 103 | 113 | ||
| 104 | Kernel::KThread* GetActiveThread() override { | 114 | Kernel::KThread* GetActiveThread() override { |
| 105 | return active_thread; | 115 | return state->active_thread; |
| 106 | } | 116 | } |
| 107 | 117 | ||
| 108 | private: | 118 | private: |
| @@ -113,65 +123,78 @@ private: | |||
| 113 | 123 | ||
| 114 | // Run the connection thread. | 124 | // Run the connection thread. |
| 115 | connection_thread = std::jthread([&, port](std::stop_token stop_token) { | 125 | connection_thread = std::jthread([&, port](std::stop_token stop_token) { |
| 126 | Common::SetCurrentThreadName("Debugger"); | ||
| 127 | |||
| 116 | try { | 128 | try { |
| 117 | // Initialize the listening socket and accept a new client. | 129 | // Initialize the listening socket and accept a new client. |
| 118 | tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port}; | 130 | tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port}; |
| 119 | tcp::acceptor acceptor{io_context, endpoint}; | 131 | tcp::acceptor acceptor{io_context, endpoint}; |
| 120 | 132 | ||
| 121 | acceptor.async_accept(client_socket, [](const auto&) {}); | 133 | AsyncAccept(acceptor, [&](auto&& peer) { AcceptConnection(std::move(peer)); }); |
| 122 | io_context.run_one(); | ||
| 123 | io_context.restart(); | ||
| 124 | 134 | ||
| 125 | if (stop_token.stop_requested()) { | 135 | while (!stop_token.stop_requested() && io_context.run()) { |
| 126 | return; | ||
| 127 | } | 136 | } |
| 128 | |||
| 129 | ThreadLoop(stop_token); | ||
| 130 | } catch (const std::exception& ex) { | 137 | } catch (const std::exception& ex) { |
| 131 | LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what()); | 138 | LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what()); |
| 132 | } | 139 | } |
| 133 | }); | 140 | }); |
| 134 | } | 141 | } |
| 135 | 142 | ||
| 136 | void ShutdownServer() { | 143 | void AcceptConnection(boost::asio::ip::tcp::socket&& peer) { |
| 137 | connection_thread.request_stop(); | 144 | LOG_INFO(Debug_GDBStub, "Accepting new peer connection"); |
| 138 | io_context.stop(); | ||
| 139 | connection_thread.join(); | ||
| 140 | } | ||
| 141 | 145 | ||
| 142 | void ThreadLoop(std::stop_token stop_token) { | 146 | std::scoped_lock lk{connection_lock}; |
| 143 | Common::SetCurrentThreadName("Debugger"); | 147 | |
| 148 | // Ensure everything is stopped. | ||
| 149 | PauseEmulation(); | ||
| 150 | |||
| 151 | // Set up the new frontend. | ||
| 152 | frontend = std::make_unique<GDBStub>(*this, system); | ||
| 153 | |||
| 154 | // Set the new state. This will tear down any existing state. | ||
| 155 | state = ConnectionState{ | ||
| 156 | .client_socket{std::move(peer)}, | ||
| 157 | .signal_pipe{io_context}, | ||
| 158 | .info{}, | ||
| 159 | .active_thread{}, | ||
| 160 | .client_data{}, | ||
| 161 | .pipe_data{}, | ||
| 162 | }; | ||
| 144 | 163 | ||
| 145 | // Set up the client signals for new data. | 164 | // Set up the client signals for new data. |
| 146 | AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); | 165 | AsyncReceiveInto(state->signal_pipe, state->pipe_data, [&](auto d) { PipeData(d); }); |
| 147 | AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); | 166 | AsyncReceiveInto(state->client_socket, state->client_data, [&](auto d) { ClientData(d); }); |
| 148 | 167 | ||
| 149 | // Set the active thread. | 168 | // Set the active thread. |
| 150 | UpdateActiveThread(); | 169 | UpdateActiveThread(); |
| 151 | 170 | ||
| 152 | // Set up the frontend. | 171 | // Set up the frontend. |
| 153 | frontend->Connected(); | 172 | frontend->Connected(); |
| 173 | } | ||
| 154 | 174 | ||
| 155 | // Main event loop. | 175 | void ShutdownServer() { |
| 156 | while (!stop_token.stop_requested() && io_context.run()) { | 176 | connection_thread.request_stop(); |
| 157 | } | 177 | io_context.stop(); |
| 178 | connection_thread.join(); | ||
| 158 | } | 179 | } |
| 159 | 180 | ||
| 160 | void PipeData(std::span<const u8> data) { | 181 | void PipeData(std::span<const u8> data) { |
| 161 | switch (info.type) { | 182 | std::scoped_lock lk{connection_lock}; |
| 183 | |||
| 184 | switch (state->info.type) { | ||
| 162 | case SignalType::Stopped: | 185 | case SignalType::Stopped: |
| 163 | case SignalType::Watchpoint: | 186 | case SignalType::Watchpoint: |
| 164 | // Stop emulation. | 187 | // Stop emulation. |
| 165 | PauseEmulation(); | 188 | PauseEmulation(); |
| 166 | 189 | ||
| 167 | // Notify the client. | 190 | // Notify the client. |
| 168 | active_thread = info.thread; | 191 | state->active_thread = state->info.thread; |
| 169 | UpdateActiveThread(); | 192 | UpdateActiveThread(); |
| 170 | 193 | ||
| 171 | if (info.type == SignalType::Watchpoint) { | 194 | if (state->info.type == SignalType::Watchpoint) { |
| 172 | frontend->Watchpoint(active_thread, *info.watchpoint); | 195 | frontend->Watchpoint(state->active_thread, *state->info.watchpoint); |
| 173 | } else { | 196 | } else { |
| 174 | frontend->Stopped(active_thread); | 197 | frontend->Stopped(state->active_thread); |
| 175 | } | 198 | } |
| 176 | 199 | ||
| 177 | break; | 200 | break; |
| @@ -179,8 +202,8 @@ private: | |||
| 179 | frontend->ShuttingDown(); | 202 | frontend->ShuttingDown(); |
| 180 | 203 | ||
| 181 | // Wait for emulation to shut down gracefully now. | 204 | // Wait for emulation to shut down gracefully now. |
| 182 | signal_pipe.close(); | 205 | state->signal_pipe.close(); |
| 183 | client_socket.shutdown(boost::asio::socket_base::shutdown_both); | 206 | state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); |
| 184 | LOG_INFO(Debug_GDBStub, "Shut down server"); | 207 | LOG_INFO(Debug_GDBStub, "Shut down server"); |
| 185 | 208 | ||
| 186 | break; | 209 | break; |
| @@ -188,17 +211,16 @@ private: | |||
| 188 | } | 211 | } |
| 189 | 212 | ||
| 190 | void ClientData(std::span<const u8> data) { | 213 | void ClientData(std::span<const u8> data) { |
| 214 | std::scoped_lock lk{connection_lock}; | ||
| 215 | |||
| 191 | const auto actions{frontend->ClientData(data)}; | 216 | const auto actions{frontend->ClientData(data)}; |
| 192 | for (const auto action : actions) { | 217 | for (const auto action : actions) { |
| 193 | switch (action) { | 218 | switch (action) { |
| 194 | case DebuggerAction::Interrupt: { | 219 | case DebuggerAction::Interrupt: { |
| 195 | { | 220 | stopped = true; |
| 196 | std::scoped_lock lk{connection_lock}; | ||
| 197 | stopped = true; | ||
| 198 | } | ||
| 199 | PauseEmulation(); | 221 | PauseEmulation(); |
| 200 | UpdateActiveThread(); | 222 | UpdateActiveThread(); |
| 201 | frontend->Stopped(active_thread); | 223 | frontend->Stopped(state->active_thread); |
| 202 | break; | 224 | break; |
| 203 | } | 225 | } |
| 204 | case DebuggerAction::Continue: | 226 | case DebuggerAction::Continue: |
| @@ -206,15 +228,15 @@ private: | |||
| 206 | break; | 228 | break; |
| 207 | case DebuggerAction::StepThreadUnlocked: | 229 | case DebuggerAction::StepThreadUnlocked: |
| 208 | MarkResumed([&] { | 230 | MarkResumed([&] { |
| 209 | active_thread->SetStepState(Kernel::StepState::StepPending); | 231 | state->active_thread->SetStepState(Kernel::StepState::StepPending); |
| 210 | active_thread->Resume(Kernel::SuspendType::Debug); | 232 | state->active_thread->Resume(Kernel::SuspendType::Debug); |
| 211 | ResumeEmulation(active_thread); | 233 | ResumeEmulation(state->active_thread); |
| 212 | }); | 234 | }); |
| 213 | break; | 235 | break; |
| 214 | case DebuggerAction::StepThreadLocked: { | 236 | case DebuggerAction::StepThreadLocked: { |
| 215 | MarkResumed([&] { | 237 | MarkResumed([&] { |
| 216 | active_thread->SetStepState(Kernel::StepState::StepPending); | 238 | state->active_thread->SetStepState(Kernel::StepState::StepPending); |
| 217 | active_thread->Resume(Kernel::SuspendType::Debug); | 239 | state->active_thread->Resume(Kernel::SuspendType::Debug); |
| 218 | }); | 240 | }); |
| 219 | break; | 241 | break; |
| 220 | } | 242 | } |
| @@ -254,15 +276,14 @@ private: | |||
| 254 | template <typename Callback> | 276 | template <typename Callback> |
| 255 | void MarkResumed(Callback&& cb) { | 277 | void MarkResumed(Callback&& cb) { |
| 256 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; | 278 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; |
| 257 | std::scoped_lock cl{connection_lock}; | ||
| 258 | stopped = false; | 279 | stopped = false; |
| 259 | cb(); | 280 | cb(); |
| 260 | } | 281 | } |
| 261 | 282 | ||
| 262 | void UpdateActiveThread() { | 283 | void UpdateActiveThread() { |
| 263 | const auto& threads{ThreadList()}; | 284 | const auto& threads{ThreadList()}; |
| 264 | if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) { | 285 | if (std::find(threads.begin(), threads.end(), state->active_thread) == threads.end()) { |
| 265 | active_thread = threads[0]; | 286 | state->active_thread = threads[0]; |
| 266 | } | 287 | } |
| 267 | } | 288 | } |
| 268 | 289 | ||
| @@ -274,18 +295,22 @@ private: | |||
| 274 | System& system; | 295 | System& system; |
| 275 | std::unique_ptr<DebuggerFrontend> frontend; | 296 | std::unique_ptr<DebuggerFrontend> frontend; |
| 276 | 297 | ||
| 298 | boost::asio::io_context io_context; | ||
| 277 | std::jthread connection_thread; | 299 | std::jthread connection_thread; |
| 278 | std::mutex connection_lock; | 300 | std::mutex connection_lock; |
| 279 | boost::asio::io_context io_context; | ||
| 280 | boost::process::async_pipe signal_pipe; | ||
| 281 | boost::asio::ip::tcp::socket client_socket; | ||
| 282 | 301 | ||
| 283 | SignalInfo info; | 302 | struct ConnectionState { |
| 284 | Kernel::KThread* active_thread; | 303 | boost::asio::ip::tcp::socket client_socket; |
| 285 | bool pipe_data; | 304 | boost::process::async_pipe signal_pipe; |
| 286 | bool stopped; | 305 | |
| 306 | SignalInfo info; | ||
| 307 | Kernel::KThread* active_thread; | ||
| 308 | std::array<u8, 4096> client_data; | ||
| 309 | bool pipe_data; | ||
| 310 | }; | ||
| 287 | 311 | ||
| 288 | std::array<u8, 4096> client_data; | 312 | std::optional<ConnectionState> state{}; |
| 313 | bool stopped{}; | ||
| 289 | }; | 314 | }; |
| 290 | 315 | ||
| 291 | Debugger::Debugger(Core::System& system, u16 port) { | 316 | Debugger::Debugger(Core::System& system, u16 port) { |
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 884229c77..a64a9ac64 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp | |||
| @@ -606,6 +606,8 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 606 | } else if (command.starts_with("StartNoAckMode")) { | 606 | } else if (command.starts_with("StartNoAckMode")) { |
| 607 | no_ack = true; | 607 | no_ack = true; |
| 608 | SendReply(GDB_STUB_REPLY_OK); | 608 | SendReply(GDB_STUB_REPLY_OK); |
| 609 | } else if (command.starts_with("Rcmd,")) { | ||
| 610 | HandleRcmd(Common::HexStringToVector(command.substr(5), false)); | ||
| 609 | } else { | 611 | } else { |
| 610 | SendReply(GDB_STUB_REPLY_EMPTY); | 612 | SendReply(GDB_STUB_REPLY_EMPTY); |
| 611 | } | 613 | } |
| @@ -645,6 +647,155 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>& | |||
| 645 | } | 647 | } |
| 646 | } | 648 | } |
| 647 | 649 | ||
| 650 | constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{ | ||
| 651 | {"----- Free -----", Kernel::Svc::MemoryState::Free}, | ||
| 652 | {"Io ", Kernel::Svc::MemoryState::Io}, | ||
| 653 | {"Static ", Kernel::Svc::MemoryState::Static}, | ||
| 654 | {"Code ", Kernel::Svc::MemoryState::Code}, | ||
| 655 | {"CodeData ", Kernel::Svc::MemoryState::CodeData}, | ||
| 656 | {"Normal ", Kernel::Svc::MemoryState::Normal}, | ||
| 657 | {"Shared ", Kernel::Svc::MemoryState::Shared}, | ||
| 658 | {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, | ||
| 659 | {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, | ||
| 660 | {"Ipc ", Kernel::Svc::MemoryState::Ipc}, | ||
| 661 | {"Stack ", Kernel::Svc::MemoryState::Stack}, | ||
| 662 | {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, | ||
| 663 | {"Transfered ", Kernel::Svc::MemoryState::Transfered}, | ||
| 664 | {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered}, | ||
| 665 | {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, | ||
| 666 | {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, | ||
| 667 | {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, | ||
| 668 | {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, | ||
| 669 | {"Kernel ", Kernel::Svc::MemoryState::Kernel}, | ||
| 670 | {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, | ||
| 671 | {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, | ||
| 672 | {"Coverage ", Kernel::Svc::MemoryState::Coverage}, | ||
| 673 | }}; | ||
| 674 | |||
| 675 | static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { | ||
| 676 | for (size_t i = 0; i < MemoryStateNames.size(); i++) { | ||
| 677 | if (std::get<1>(MemoryStateNames[i]) == state) { | ||
| 678 | return std::get<0>(MemoryStateNames[i]); | ||
| 679 | } | ||
| 680 | } | ||
| 681 | return "Unknown "; | ||
| 682 | } | ||
| 683 | |||
| 684 | static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::MemoryInfo& info) { | ||
| 685 | if (info.state == Kernel::Svc::MemoryState::Free) { | ||
| 686 | return " "; | ||
| 687 | } | ||
| 688 | |||
| 689 | switch (info.permission) { | ||
| 690 | case Kernel::Svc::MemoryPermission::ReadExecute: | ||
| 691 | return "r-x"; | ||
| 692 | case Kernel::Svc::MemoryPermission::Read: | ||
| 693 | return "r--"; | ||
| 694 | case Kernel::Svc::MemoryPermission::ReadWrite: | ||
| 695 | return "rw-"; | ||
| 696 | default: | ||
| 697 | return "---"; | ||
| 698 | } | ||
| 699 | } | ||
| 700 | |||
| 701 | static VAddr GetModuleEnd(Kernel::KPageTable& page_table, VAddr base) { | ||
| 702 | Kernel::Svc::MemoryInfo mem_info; | ||
| 703 | VAddr cur_addr{base}; | ||
| 704 | |||
| 705 | // Expect: r-x Code (.text) | ||
| 706 | mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); | ||
| 707 | cur_addr = mem_info.base_address + mem_info.size; | ||
| 708 | if (mem_info.state != Kernel::Svc::MemoryState::Code || | ||
| 709 | mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) { | ||
| 710 | return cur_addr - 1; | ||
| 711 | } | ||
| 712 | |||
| 713 | // Expect: r-- Code (.rodata) | ||
| 714 | mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); | ||
| 715 | cur_addr = mem_info.base_address + mem_info.size; | ||
| 716 | if (mem_info.state != Kernel::Svc::MemoryState::Code || | ||
| 717 | mem_info.permission != Kernel::Svc::MemoryPermission::Read) { | ||
| 718 | return cur_addr - 1; | ||
| 719 | } | ||
| 720 | |||
| 721 | // Expect: rw- CodeData (.data) | ||
| 722 | mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); | ||
| 723 | cur_addr = mem_info.base_address + mem_info.size; | ||
| 724 | return cur_addr - 1; | ||
| 725 | } | ||
| 726 | |||
| 727 | void GDBStub::HandleRcmd(const std::vector<u8>& command) { | ||
| 728 | std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; | ||
| 729 | std::string reply; | ||
| 730 | |||
| 731 | auto* process = system.CurrentProcess(); | ||
| 732 | auto& page_table = process->PageTable(); | ||
| 733 | |||
| 734 | if (command_str == "get info") { | ||
| 735 | Loader::AppLoader::Modules modules; | ||
| 736 | system.GetAppLoader().ReadNSOModules(modules); | ||
| 737 | |||
| 738 | reply = fmt::format("Process: {:#x} ({})\n" | ||
| 739 | "Program Id: {:#018x}\n", | ||
| 740 | process->GetProcessID(), process->GetName(), process->GetProgramID()); | ||
| 741 | reply += | ||
| 742 | fmt::format("Layout:\n" | ||
| 743 | " Alias: {:#012x} - {:#012x}\n" | ||
| 744 | " Heap: {:#012x} - {:#012x}\n" | ||
| 745 | " Aslr: {:#012x} - {:#012x}\n" | ||
| 746 | " Stack: {:#012x} - {:#012x}\n" | ||
| 747 | "Modules:\n", | ||
| 748 | page_table.GetAliasRegionStart(), page_table.GetAliasRegionEnd(), | ||
| 749 | page_table.GetHeapRegionStart(), page_table.GetHeapRegionEnd(), | ||
| 750 | page_table.GetAliasCodeRegionStart(), page_table.GetAliasCodeRegionEnd(), | ||
| 751 | page_table.GetStackRegionStart(), page_table.GetStackRegionEnd()); | ||
| 752 | |||
| 753 | for (const auto& [vaddr, name] : modules) { | ||
| 754 | reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, | ||
| 755 | GetModuleEnd(page_table, vaddr), name); | ||
| 756 | } | ||
| 757 | } else if (command_str == "get mappings") { | ||
| 758 | reply = "Mappings:\n"; | ||
| 759 | VAddr cur_addr = 0; | ||
| 760 | |||
| 761 | while (true) { | ||
| 762 | using MemoryAttribute = Kernel::Svc::MemoryAttribute; | ||
| 763 | |||
| 764 | auto mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); | ||
| 765 | |||
| 766 | if (mem_info.state != Kernel::Svc::MemoryState::Inaccessible || | ||
| 767 | mem_info.base_address + mem_info.size - 1 != std::numeric_limits<u64>::max()) { | ||
| 768 | const char* state = GetMemoryStateName(mem_info.state); | ||
| 769 | const char* perm = GetMemoryPermissionString(mem_info); | ||
| 770 | |||
| 771 | const char l = True(mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-'; | ||
| 772 | const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-'; | ||
| 773 | const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-'; | ||
| 774 | const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-'; | ||
| 775 | |||
| 776 | reply += | ||
| 777 | fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n", | ||
| 778 | mem_info.base_address, mem_info.base_address + mem_info.size - 1, | ||
| 779 | perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count); | ||
| 780 | } | ||
| 781 | |||
| 782 | const uintptr_t next_address = mem_info.base_address + mem_info.size; | ||
| 783 | if (next_address <= cur_addr) { | ||
| 784 | break; | ||
| 785 | } | ||
| 786 | |||
| 787 | cur_addr = next_address; | ||
| 788 | } | ||
| 789 | } else if (command_str == "help") { | ||
| 790 | reply = "Commands:\n get info\n get mappings\n"; | ||
| 791 | } else { | ||
| 792 | reply = "Unknown command.\nCommands:\n get info\n get mappings\n"; | ||
| 793 | } | ||
| 794 | |||
| 795 | std::span<const u8> reply_span{reinterpret_cast<u8*>(&reply.front()), reply.size()}; | ||
| 796 | SendReply(Common::HexToString(reply_span, false)); | ||
| 797 | } | ||
| 798 | |||
| 648 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | 799 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { |
| 649 | const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; | 800 | const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; |
| 650 | for (auto* thread : threads) { | 801 | for (auto* thread : threads) { |
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index 0b0f56e4b..368197920 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h | |||
| @@ -32,6 +32,7 @@ private: | |||
| 32 | void ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions); | 32 | void ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions); |
| 33 | void HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions); | 33 | void HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions); |
| 34 | void HandleQuery(std::string_view command); | 34 | void HandleQuery(std::string_view command); |
| 35 | void HandleRcmd(const std::vector<u8>& command); | ||
| 35 | void HandleBreakpointInsert(std::string_view command); | 36 | void HandleBreakpointInsert(std::string_view command); |
| 36 | void HandleBreakpointRemove(std::string_view command); | 37 | void HandleBreakpointRemove(std::string_view command); |
| 37 | std::vector<char>::const_iterator CommandEnd() const; | 38 | std::vector<char>::const_iterator CommandEnd() const; |
diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp new file mode 100644 index 000000000..26c7fefe3 --- /dev/null +++ b/src/core/frontend/applets/cabinet.cpp | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/logging/log.h" | ||
| 5 | #include "core/frontend/applets/cabinet.h" | ||
| 6 | |||
| 7 | #include <thread> | ||
| 8 | |||
| 9 | namespace Core::Frontend { | ||
| 10 | |||
| 11 | CabinetApplet::~CabinetApplet() = default; | ||
| 12 | |||
| 13 | void DefaultCabinetApplet::ShowCabinetApplet( | ||
| 14 | const CabinetCallback& callback, const CabinetParameters& parameters, | ||
| 15 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { | ||
| 16 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 17 | callback(false, {}); | ||
| 18 | } | ||
| 19 | |||
| 20 | } // namespace Core::Frontend | ||
diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h new file mode 100644 index 000000000..c28a235c1 --- /dev/null +++ b/src/core/frontend/applets/cabinet.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <functional> | ||
| 7 | #include "core/hle/service/nfp/nfp_types.h" | ||
| 8 | |||
| 9 | namespace Service::NFP { | ||
| 10 | class NfpDevice; | ||
| 11 | } // namespace Service::NFP | ||
| 12 | |||
| 13 | namespace Core::Frontend { | ||
| 14 | |||
| 15 | struct CabinetParameters { | ||
| 16 | Service::NFP::TagInfo tag_info; | ||
| 17 | Service::NFP::RegisterInfo register_info; | ||
| 18 | Service::NFP::CabinetMode mode; | ||
| 19 | }; | ||
| 20 | |||
| 21 | using CabinetCallback = std::function<void(bool, const std::string&)>; | ||
| 22 | |||
| 23 | class CabinetApplet { | ||
| 24 | public: | ||
| 25 | virtual ~CabinetApplet(); | ||
| 26 | virtual void ShowCabinetApplet(const CabinetCallback& callback, | ||
| 27 | const CabinetParameters& parameters, | ||
| 28 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0; | ||
| 29 | }; | ||
| 30 | |||
| 31 | class DefaultCabinetApplet final : public CabinetApplet { | ||
| 32 | public: | ||
| 33 | void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, | ||
| 34 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; | ||
| 35 | }; | ||
| 36 | |||
| 37 | } // namespace Core::Frontend | ||
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index aac45907d..fb7e5802a 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp | |||
| @@ -19,27 +19,26 @@ void EmulatedConsole::ReloadFromSettings() { | |||
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | void EmulatedConsole::SetTouchParams() { | 21 | void EmulatedConsole::SetTouchParams() { |
| 22 | // TODO(german77): Support any number of fingers | ||
| 23 | std::size_t index = 0; | 22 | std::size_t index = 0; |
| 24 | 23 | ||
| 25 | // Hardcode mouse, touchscreen and cemuhook parameters | 24 | // We can't use mouse as touch if native mouse is enabled |
| 26 | if (!Settings::values.mouse_enabled) { | 25 | if (!Settings::values.mouse_enabled) { |
| 27 | // We can't use mouse as touch if native mouse is enabled | ||
| 28 | touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; | 26 | touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; |
| 29 | } | 27 | } |
| 30 | 28 | ||
| 31 | touch_params[index++] = | 29 | touch_params[index++] = |
| 32 | Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"}; | 30 | Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"}; |
| 33 | touch_params[index++] = | 31 | touch_params[index++] = |
| 34 | Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"}; | 32 | Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; |
| 35 | touch_params[index++] = | 33 | |
| 36 | Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"}; | 34 | for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) { |
| 37 | touch_params[index++] = | 35 | Common::ParamPackage touchscreen_param{}; |
| 38 | Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"}; | 36 | touchscreen_param.Set("engine", "touch"); |
| 39 | touch_params[index++] = | 37 | touchscreen_param.Set("axis_x", i * 2); |
| 40 | Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"}; | 38 | touchscreen_param.Set("axis_y", (i * 2) + 1); |
| 41 | touch_params[index++] = | 39 | touchscreen_param.Set("button", i); |
| 42 | Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"}; | 40 | touch_params[index++] = touchscreen_param; |
| 41 | } | ||
| 43 | 42 | ||
| 44 | const auto button_index = | 43 | const auto button_index = |
| 45 | static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); | 44 | static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); |
| @@ -47,7 +46,7 @@ void EmulatedConsole::SetTouchParams() { | |||
| 47 | 46 | ||
| 48 | // Map the rest of the fingers from touch from button configuration | 47 | // Map the rest of the fingers from touch from button configuration |
| 49 | for (const auto& config_entry : touch_buttons) { | 48 | for (const auto& config_entry : touch_buttons) { |
| 50 | if (index >= touch_params.size()) { | 49 | if (index >= MaxTouchDevices) { |
| 51 | continue; | 50 | continue; |
| 52 | } | 51 | } |
| 53 | Common::ParamPackage params{config_entry}; | 52 | Common::ParamPackage params{config_entry}; |
| @@ -60,7 +59,6 @@ void EmulatedConsole::SetTouchParams() { | |||
| 60 | touch_button_params.Set("button", params.Serialize()); | 59 | touch_button_params.Set("button", params.Serialize()); |
| 61 | touch_button_params.Set("x", x); | 60 | touch_button_params.Set("x", x); |
| 62 | touch_button_params.Set("y", y); | 61 | touch_button_params.Set("y", y); |
| 63 | touch_button_params.Set("touch_id", static_cast<int>(index)); | ||
| 64 | touch_params[index] = touch_button_params; | 62 | touch_params[index] = touch_button_params; |
| 65 | index++; | 63 | index++; |
| 66 | } | 64 | } |
| @@ -178,12 +176,38 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { | |||
| 178 | } | 176 | } |
| 179 | 177 | ||
| 180 | void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { | 178 | void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { |
| 181 | if (index >= console.touch_values.size()) { | 179 | if (index >= MaxTouchDevices) { |
| 182 | return; | 180 | return; |
| 183 | } | 181 | } |
| 184 | std::unique_lock lock{mutex}; | 182 | std::unique_lock lock{mutex}; |
| 185 | 183 | ||
| 186 | console.touch_values[index] = TransformToTouch(callback); | 184 | const auto touch_input = TransformToTouch(callback); |
| 185 | auto touch_index = GetIndexFromFingerId(index); | ||
| 186 | bool is_new_input = false; | ||
| 187 | |||
| 188 | if (!touch_index.has_value() && touch_input.pressed.value) { | ||
| 189 | touch_index = GetNextFreeIndex(); | ||
| 190 | is_new_input = true; | ||
| 191 | } | ||
| 192 | |||
| 193 | // No free entries or invalid state. Ignore input | ||
| 194 | if (!touch_index.has_value()) { | ||
| 195 | return; | ||
| 196 | } | ||
| 197 | |||
| 198 | auto& touch_value = console.touch_values[touch_index.value()]; | ||
| 199 | |||
| 200 | if (is_new_input) { | ||
| 201 | touch_value.pressed.value = true; | ||
| 202 | touch_value.id = static_cast<u32>(index); | ||
| 203 | } | ||
| 204 | |||
| 205 | touch_value.x = touch_input.x; | ||
| 206 | touch_value.y = touch_input.y; | ||
| 207 | |||
| 208 | if (!touch_input.pressed.value) { | ||
| 209 | touch_value.pressed.value = false; | ||
| 210 | } | ||
| 187 | 211 | ||
| 188 | if (is_configuring) { | 212 | if (is_configuring) { |
| 189 | lock.unlock(); | 213 | lock.unlock(); |
| @@ -191,11 +215,15 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st | |||
| 191 | return; | 215 | return; |
| 192 | } | 216 | } |
| 193 | 217 | ||
| 194 | // TODO(german77): Remap touch id in sequential order | 218 | // Touch outside allowed range. Ignore input |
| 195 | console.touch_state[index] = { | 219 | if (touch_index.value() >= MaxActiveTouchInputs) { |
| 196 | .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, | 220 | return; |
| 197 | .id = static_cast<u32>(console.touch_values[index].id), | 221 | } |
| 198 | .pressed = console.touch_values[index].pressed.value, | 222 | |
| 223 | console.touch_state[touch_index.value()] = { | ||
| 224 | .position = {touch_value.x.value, touch_value.y.value}, | ||
| 225 | .id = static_cast<u32>(touch_index.value()), | ||
| 226 | .pressed = touch_input.pressed.value, | ||
| 199 | }; | 227 | }; |
| 200 | 228 | ||
| 201 | lock.unlock(); | 229 | lock.unlock(); |
| @@ -222,6 +250,28 @@ TouchFingerState EmulatedConsole::GetTouch() const { | |||
| 222 | return console.touch_state; | 250 | return console.touch_state; |
| 223 | } | 251 | } |
| 224 | 252 | ||
| 253 | std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const { | ||
| 254 | for (std::size_t index = 0; index < MaxTouchDevices; ++index) { | ||
| 255 | const auto& finger = console.touch_values[index]; | ||
| 256 | if (!finger.pressed.value) { | ||
| 257 | continue; | ||
| 258 | } | ||
| 259 | if (finger.id == static_cast<int>(finger_id)) { | ||
| 260 | return index; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | return std::nullopt; | ||
| 264 | } | ||
| 265 | |||
| 266 | std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const { | ||
| 267 | for (std::size_t index = 0; index < MaxTouchDevices; ++index) { | ||
| 268 | if (!console.touch_values[index].pressed.value) { | ||
| 269 | return index; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | return std::nullopt; | ||
| 273 | } | ||
| 274 | |||
| 225 | void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { | 275 | void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { |
| 226 | std::scoped_lock lock{callback_mutex}; | 276 | std::scoped_lock lock{callback_mutex}; |
| 227 | for (const auto& poller_pair : callback_list) { | 277 | for (const auto& poller_pair : callback_list) { |
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 1c510cd19..697ecd2d6 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <mutex> | 9 | #include <mutex> |
| 10 | #include <optional> | ||
| 10 | #include <unordered_map> | 11 | #include <unordered_map> |
| 11 | 12 | ||
| 12 | #include "common/common_funcs.h" | 13 | #include "common/common_funcs.h" |
| @@ -20,6 +21,8 @@ | |||
| 20 | #include "core/hid/motion_input.h" | 21 | #include "core/hid/motion_input.h" |
| 21 | 22 | ||
| 22 | namespace Core::HID { | 23 | namespace Core::HID { |
| 24 | static constexpr std::size_t MaxTouchDevices = 32; | ||
| 25 | static constexpr std::size_t MaxActiveTouchInputs = 16; | ||
| 23 | 26 | ||
| 24 | struct ConsoleMotionInfo { | 27 | struct ConsoleMotionInfo { |
| 25 | Common::Input::MotionStatus raw_status{}; | 28 | Common::Input::MotionStatus raw_status{}; |
| @@ -27,13 +30,13 @@ struct ConsoleMotionInfo { | |||
| 27 | }; | 30 | }; |
| 28 | 31 | ||
| 29 | using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>; | 32 | using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>; |
| 30 | using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 16>; | 33 | using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>; |
| 31 | 34 | ||
| 32 | using ConsoleMotionParams = Common::ParamPackage; | 35 | using ConsoleMotionParams = Common::ParamPackage; |
| 33 | using TouchParams = std::array<Common::ParamPackage, 16>; | 36 | using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>; |
| 34 | 37 | ||
| 35 | using ConsoleMotionValues = ConsoleMotionInfo; | 38 | using ConsoleMotionValues = ConsoleMotionInfo; |
| 36 | using TouchValues = std::array<Common::Input::TouchStatus, 16>; | 39 | using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>; |
| 37 | 40 | ||
| 38 | struct TouchFinger { | 41 | struct TouchFinger { |
| 39 | u64 last_touch{}; | 42 | u64 last_touch{}; |
| @@ -55,7 +58,7 @@ struct ConsoleMotion { | |||
| 55 | bool is_at_rest{}; | 58 | bool is_at_rest{}; |
| 56 | }; | 59 | }; |
| 57 | 60 | ||
| 58 | using TouchFingerState = std::array<TouchFinger, 16>; | 61 | using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>; |
| 59 | 62 | ||
| 60 | struct ConsoleStatus { | 63 | struct ConsoleStatus { |
| 61 | // Data from input_common | 64 | // Data from input_common |
| @@ -166,6 +169,10 @@ private: | |||
| 166 | */ | 169 | */ |
| 167 | void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); | 170 | void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); |
| 168 | 171 | ||
| 172 | std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const; | ||
| 173 | |||
| 174 | std::optional<std::size_t> GetNextFreeIndex() const; | ||
| 175 | |||
| 169 | /** | 176 | /** |
| 170 | * Triggers a callback that something has changed on the console status | 177 | * Triggers a callback that something has changed on the console status |
| 171 | * @param type Input type of the event to trigger | 178 | * @param type Input type of the event to trigger |
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 5d8b75b50..502692875 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp | |||
| @@ -200,9 +200,6 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& | |||
| 200 | x = std::clamp(x, 0.0f, 1.0f); | 200 | x = std::clamp(x, 0.0f, 1.0f); |
| 201 | y = std::clamp(y, 0.0f, 1.0f); | 201 | y = std::clamp(y, 0.0f, 1.0f); |
| 202 | 202 | ||
| 203 | // Limit id to maximum number of fingers | ||
| 204 | status.id = std::clamp(status.id, 0, 16); | ||
| 205 | |||
| 206 | if (status.pressed.inverted) { | 203 | if (status.pressed.inverted) { |
| 207 | status.pressed.value = !status.pressed.value; | 204 | status.pressed.value = !status.pressed.value; |
| 208 | } | 205 | } |
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index bda098511..7b363eb1e 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp | |||
| @@ -243,6 +243,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { | |||
| 243 | // If we somehow get an invalid type, abort. | 243 | // If we somehow get an invalid type, abort. |
| 244 | default: | 244 | default: |
| 245 | ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); | 245 | ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); |
| 246 | break; | ||
| 246 | } | 247 | } |
| 247 | 248 | ||
| 248 | // If we've hit the end of a gap, free it. | 249 | // If we've hit the end of a gap, free it. |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 5387bf5fe..612fc76fa 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -2301,6 +2301,7 @@ Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size, | |||
| 2301 | break; | 2301 | break; |
| 2302 | default: | 2302 | default: |
| 2303 | ASSERT(false); | 2303 | ASSERT(false); |
| 2304 | break; | ||
| 2304 | } | 2305 | } |
| 2305 | } | 2306 | } |
| 2306 | 2307 | ||
| @@ -2803,6 +2804,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_ | |||
| 2803 | break; | 2804 | break; |
| 2804 | default: | 2805 | default: |
| 2805 | ASSERT(false); | 2806 | ASSERT(false); |
| 2807 | break; | ||
| 2806 | } | 2808 | } |
| 2807 | 2809 | ||
| 2808 | addr += size; | 2810 | addr += size; |
| @@ -2838,6 +2840,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, | |||
| 2838 | break; | 2840 | break; |
| 2839 | default: | 2841 | default: |
| 2840 | ASSERT(false); | 2842 | ASSERT(false); |
| 2843 | break; | ||
| 2841 | } | 2844 | } |
| 2842 | R_SUCCEED(); | 2845 | R_SUCCEED(); |
| 2843 | } | 2846 | } |
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 950850291..f1ca785d7 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -320,6 +320,9 @@ public: | |||
| 320 | constexpr VAddr GetAliasCodeRegionStart() const { | 320 | constexpr VAddr GetAliasCodeRegionStart() const { |
| 321 | return m_alias_code_region_start; | 321 | return m_alias_code_region_start; |
| 322 | } | 322 | } |
| 323 | constexpr VAddr GetAliasCodeRegionEnd() const { | ||
| 324 | return m_alias_code_region_end; | ||
| 325 | } | ||
| 323 | constexpr VAddr GetAliasCodeRegionSize() const { | 326 | constexpr VAddr GetAliasCodeRegionSize() const { |
| 324 | return m_alias_code_region_end - m_alias_code_region_start; | 327 | return m_alias_code_region_end - m_alias_code_region_start; |
| 325 | } | 328 | } |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 55a9c5fae..d1dc62401 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -395,6 +395,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: | |||
| 395 | 395 | ||
| 396 | default: | 396 | default: |
| 397 | ASSERT(false); | 397 | ASSERT(false); |
| 398 | break; | ||
| 398 | } | 399 | } |
| 399 | 400 | ||
| 400 | // Create TLS region | 401 | // Create TLS region |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9962ad171..e520cab47 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -2701,14 +2701,24 @@ static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr ou | |||
| 2701 | return ResultSuccess; | 2701 | return ResultSuccess; |
| 2702 | } | 2702 | } |
| 2703 | 2703 | ||
| 2704 | static Result FlushProcessDataCache32([[maybe_unused]] Core::System& system, | 2704 | static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address, |
| 2705 | [[maybe_unused]] Handle handle, [[maybe_unused]] u32 address, | 2705 | u64 size) { |
| 2706 | [[maybe_unused]] u32 size) { | 2706 | // Validate address/size. |
| 2707 | // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op, | 2707 | R_UNLESS(size > 0, ResultInvalidSize); |
| 2708 | // as all emulation is done in the same cache level in host architecture, thus data cache | 2708 | R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory); |
| 2709 | // does not need flushing. | 2709 | R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory); |
| 2710 | LOG_DEBUG(Kernel_SVC, "called"); | 2710 | |
| 2711 | return ResultSuccess; | 2711 | // Get the process from its handle. |
| 2712 | KScopedAutoObject process = | ||
| 2713 | system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle); | ||
| 2714 | R_UNLESS(process.IsNotNull(), ResultInvalidHandle); | ||
| 2715 | |||
| 2716 | // Verify the region is within range. | ||
| 2717 | auto& page_table = process->PageTable(); | ||
| 2718 | R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); | ||
| 2719 | |||
| 2720 | // Perform the operation. | ||
| 2721 | R_RETURN(system.Memory().FlushDataCache(*process, address, size)); | ||
| 2712 | } | 2722 | } |
| 2713 | 2723 | ||
| 2714 | namespace { | 2724 | namespace { |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 272c54cf7..3730937fe 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -722,4 +722,12 @@ void SvcWrap32(Core::System& system) { | |||
| 722 | FuncReturn(system, retval); | 722 | FuncReturn(system, retval); |
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | // Used by Invalidate/Store/FlushProcessDataCache32 | ||
| 726 | template <Result func(Core::System&, Handle, u64, u64)> | ||
| 727 | void SvcWrap32(Core::System& system) { | ||
| 728 | const u64 address = (Param(system, 3) << 32) | Param(system, 2); | ||
| 729 | const u64 size = (Param(system, 4) << 32) | Param(system, 1); | ||
| 730 | FuncReturn32(system, func(system, Param32(system, 0), address, size).raw); | ||
| 731 | } | ||
| 732 | |||
| 725 | } // namespace Kernel | 733 | } // namespace Kernel |
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 56c990728..240f06689 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -28,30 +28,49 @@ enum class ErrorModule : u32 { | |||
| 28 | Loader = 9, | 28 | Loader = 9, |
| 29 | CMIF = 10, | 29 | CMIF = 10, |
| 30 | HIPC = 11, | 30 | HIPC = 11, |
| 31 | TMA = 12, | ||
| 32 | DMNT = 13, | ||
| 33 | GDS = 14, | ||
| 31 | PM = 15, | 34 | PM = 15, |
| 32 | NS = 16, | 35 | NS = 16, |
| 36 | BSDSockets = 17, | ||
| 33 | HTC = 18, | 37 | HTC = 18, |
| 38 | TSC = 19, | ||
| 34 | NCMContent = 20, | 39 | NCMContent = 20, |
| 35 | SM = 21, | 40 | SM = 21, |
| 36 | RO = 22, | 41 | RO = 22, |
| 42 | GC = 23, | ||
| 37 | SDMMC = 24, | 43 | SDMMC = 24, |
| 38 | OVLN = 25, | 44 | OVLN = 25, |
| 39 | SPL = 26, | 45 | SPL = 26, |
| 46 | Socket = 27, | ||
| 47 | HTCLOW = 29, | ||
| 48 | DDSF = 30, | ||
| 49 | HTCFS = 31, | ||
| 50 | Async = 32, | ||
| 51 | Util = 33, | ||
| 52 | TIPC = 35, | ||
| 53 | ANIF = 37, | ||
| 40 | ETHC = 100, | 54 | ETHC = 100, |
| 41 | I2C = 101, | 55 | I2C = 101, |
| 42 | GPIO = 102, | 56 | GPIO = 102, |
| 43 | UART = 103, | 57 | UART = 103, |
| 58 | CPAD = 104, | ||
| 44 | Settings = 105, | 59 | Settings = 105, |
| 60 | FTM = 106, | ||
| 45 | WLAN = 107, | 61 | WLAN = 107, |
| 46 | XCD = 108, | 62 | XCD = 108, |
| 63 | TMP451 = 109, | ||
| 47 | NIFM = 110, | 64 | NIFM = 110, |
| 48 | Hwopus = 111, | 65 | Hwopus = 111, |
| 66 | LSM6DS3 = 112, | ||
| 49 | Bluetooth = 113, | 67 | Bluetooth = 113, |
| 50 | VI = 114, | 68 | VI = 114, |
| 51 | NFP = 115, | 69 | NFP = 115, |
| 52 | Time = 116, | 70 | Time = 116, |
| 53 | FGM = 117, | 71 | FGM = 117, |
| 54 | OE = 118, | 72 | OE = 118, |
| 73 | BH1730FVC = 119, | ||
| 55 | PCIe = 120, | 74 | PCIe = 120, |
| 56 | Friends = 121, | 75 | Friends = 121, |
| 57 | BCAT = 122, | 76 | BCAT = 122, |
| @@ -65,7 +84,7 @@ enum class ErrorModule : u32 { | |||
| 65 | AHID = 130, | 84 | AHID = 130, |
| 66 | Qlaunch = 132, | 85 | Qlaunch = 132, |
| 67 | PCV = 133, | 86 | PCV = 133, |
| 68 | OMM = 134, | 87 | USBPD = 134, |
| 69 | BPC = 135, | 88 | BPC = 135, |
| 70 | PSM = 136, | 89 | PSM = 136, |
| 71 | NIM = 137, | 90 | NIM = 137, |
| @@ -75,18 +94,22 @@ enum class ErrorModule : u32 { | |||
| 75 | NSD = 141, | 94 | NSD = 141, |
| 76 | PCTL = 142, | 95 | PCTL = 142, |
| 77 | BTM = 143, | 96 | BTM = 143, |
| 97 | LA = 144, | ||
| 78 | ETicket = 145, | 98 | ETicket = 145, |
| 79 | NGC = 146, | 99 | NGC = 146, |
| 80 | ERPT = 147, | 100 | ERPT = 147, |
| 81 | APM = 148, | 101 | APM = 148, |
| 102 | CEC = 149, | ||
| 82 | Profiler = 150, | 103 | Profiler = 150, |
| 83 | ErrorUpload = 151, | 104 | ErrorUpload = 151, |
| 105 | LIDBE = 152, | ||
| 84 | Audio = 153, | 106 | Audio = 153, |
| 85 | NPNS = 154, | 107 | NPNS = 154, |
| 86 | NPNSHTTPSTREAM = 155, | 108 | NPNSHTTPSTREAM = 155, |
| 87 | ARP = 157, | 109 | ARP = 157, |
| 88 | SWKBD = 158, | 110 | SWKBD = 158, |
| 89 | BOOT = 159, | 111 | BOOT = 159, |
| 112 | NetDiag = 160, | ||
| 90 | NFCMifare = 161, | 113 | NFCMifare = 161, |
| 91 | UserlandAssert = 162, | 114 | UserlandAssert = 162, |
| 92 | Fatal = 163, | 115 | Fatal = 163, |
| @@ -94,17 +117,68 @@ enum class ErrorModule : u32 { | |||
| 94 | SPSM = 165, | 117 | SPSM = 165, |
| 95 | BGTC = 167, | 118 | BGTC = 167, |
| 96 | UserlandCrash = 168, | 119 | UserlandCrash = 168, |
| 120 | SASBUS = 169, | ||
| 121 | PI = 170, | ||
| 122 | AudioCtrl = 172, | ||
| 123 | LBL = 173, | ||
| 124 | JIT = 175, | ||
| 125 | HDCP = 176, | ||
| 126 | OMM = 177, | ||
| 127 | PDM = 178, | ||
| 128 | OLSC = 179, | ||
| 97 | SREPO = 180, | 129 | SREPO = 180, |
| 98 | Dauth = 181, | 130 | Dauth = 181, |
| 131 | STDFU = 182, | ||
| 132 | DBG = 183, | ||
| 133 | DHCPS = 186, | ||
| 134 | SPI = 187, | ||
| 135 | AVM = 188, | ||
| 136 | PWM = 189, | ||
| 137 | RTC = 191, | ||
| 138 | Regulator = 192, | ||
| 139 | LED = 193, | ||
| 140 | SIO = 195, | ||
| 141 | PCM = 196, | ||
| 142 | CLKRST = 197, | ||
| 143 | POWCTL = 198, | ||
| 144 | AudioOld = 201, | ||
| 99 | HID = 202, | 145 | HID = 202, |
| 100 | LDN = 203, | 146 | LDN = 203, |
| 147 | CS = 204, | ||
| 101 | Irsensor = 205, | 148 | Irsensor = 205, |
| 102 | Capture = 206, | 149 | Capture = 206, |
| 103 | Manu = 208, | 150 | Manu = 208, |
| 104 | ATK = 209, | 151 | ATK = 209, |
| 152 | WEB = 210, | ||
| 153 | LCS = 211, | ||
| 105 | GRC = 212, | 154 | GRC = 212, |
| 155 | Repair = 213, | ||
| 156 | Album = 214, | ||
| 157 | RID = 215, | ||
| 106 | Migration = 216, | 158 | Migration = 216, |
| 107 | MigrationLdcServ = 217, | 159 | MigrationLdcServ = 217, |
| 160 | HIDBUS = 218, | ||
| 161 | ENS = 219, | ||
| 162 | WebSocket = 223, | ||
| 163 | DCDMTP = 227, | ||
| 164 | PGL = 228, | ||
| 165 | Notification = 229, | ||
| 166 | INS = 230, | ||
| 167 | LP2P = 231, | ||
| 168 | RCD = 232, | ||
| 169 | LCM40607 = 233, | ||
| 170 | PRC = 235, | ||
| 171 | TMAHTC = 237, | ||
| 172 | ECTX = 238, | ||
| 173 | MNPP = 239, | ||
| 174 | HSHL = 240, | ||
| 175 | CAPMTP = 242, | ||
| 176 | DP2HDMI = 244, | ||
| 177 | Cradle = 245, | ||
| 178 | SProfile = 246, | ||
| 179 | NDRM = 250, | ||
| 180 | TSPM = 499, | ||
| 181 | DevMenu = 500, | ||
| 108 | GeneralWebApplet = 800, | 182 | GeneralWebApplet = 800, |
| 109 | WifiWebAuthApplet = 809, | 183 | WifiWebAuthApplet = 809, |
| 110 | WhitelistedApplet = 810, | 184 | WhitelistedApplet = 810, |
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp new file mode 100644 index 000000000..d0969b0f1 --- /dev/null +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/assert.h" | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/frontend/applets/cabinet.h" | ||
| 8 | #include "core/hid/hid_core.h" | ||
| 9 | #include "core/hle/kernel/k_event.h" | ||
| 10 | #include "core/hle/kernel/k_readable_event.h" | ||
| 11 | #include "core/hle/service/am/am.h" | ||
| 12 | #include "core/hle/service/am/applets/applet_cabinet.h" | ||
| 13 | #include "core/hle/service/mii/mii_manager.h" | ||
| 14 | #include "core/hle/service/nfp/nfp_device.h" | ||
| 15 | |||
| 16 | namespace Service::AM::Applets { | ||
| 17 | |||
| 18 | Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, | ||
| 19 | const Core::Frontend::CabinetApplet& frontend_) | ||
| 20 | : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ | ||
| 21 | system_, | ||
| 22 | "CabinetApplet"} { | ||
| 23 | |||
| 24 | availability_change_event = | ||
| 25 | service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); | ||
| 26 | } | ||
| 27 | |||
| 28 | Cabinet::~Cabinet() = default; | ||
| 29 | |||
| 30 | void Cabinet::Initialize() { | ||
| 31 | Applet::Initialize(); | ||
| 32 | |||
| 33 | LOG_INFO(Service_HID, "Initializing Cabinet Applet."); | ||
| 34 | |||
| 35 | LOG_DEBUG(Service_HID, | ||
| 36 | "Initializing Applet with common_args: arg_version={}, lib_version={}, " | ||
| 37 | "play_startup_sound={}, size={}, system_tick={}, theme_color={}", | ||
| 38 | common_args.arguments_version, common_args.library_version, | ||
| 39 | common_args.play_startup_sound, common_args.size, common_args.system_tick, | ||
| 40 | common_args.theme_color); | ||
| 41 | |||
| 42 | const auto storage = broker.PopNormalDataToApplet(); | ||
| 43 | ASSERT(storage != nullptr); | ||
| 44 | |||
| 45 | const auto applet_input_data = storage->GetData(); | ||
| 46 | ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings)); | ||
| 47 | |||
| 48 | std::memcpy(&applet_input_common, applet_input_data.data(), | ||
| 49 | sizeof(StartParamForAmiiboSettings)); | ||
| 50 | } | ||
| 51 | |||
| 52 | bool Cabinet::TransactionComplete() const { | ||
| 53 | return is_complete; | ||
| 54 | } | ||
| 55 | |||
| 56 | Result Cabinet::GetStatus() const { | ||
| 57 | return ResultSuccess; | ||
| 58 | } | ||
| 59 | |||
| 60 | void Cabinet::ExecuteInteractive() { | ||
| 61 | ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); | ||
| 62 | } | ||
| 63 | |||
| 64 | void Cabinet::Execute() { | ||
| 65 | if (is_complete) { | ||
| 66 | return; | ||
| 67 | } | ||
| 68 | |||
| 69 | const auto callback = [this](bool apply_changes, const std::string& amiibo_name) { | ||
| 70 | DisplayCompleted(apply_changes, amiibo_name); | ||
| 71 | }; | ||
| 72 | |||
| 73 | // TODO: listen on all controllers | ||
| 74 | if (nfp_device == nullptr) { | ||
| 75 | nfp_device = std::make_shared<Service::NFP::NfpDevice>( | ||
| 76 | system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); | ||
| 77 | nfp_device->Initialize(); | ||
| 78 | nfp_device->StartDetection(Service::NFP::TagProtocol::All); | ||
| 79 | } | ||
| 80 | |||
| 81 | const Core::Frontend::CabinetParameters parameters{ | ||
| 82 | .tag_info = applet_input_common.tag_info, | ||
| 83 | .register_info = applet_input_common.register_info, | ||
| 84 | .mode = applet_input_common.applet_mode, | ||
| 85 | }; | ||
| 86 | |||
| 87 | switch (applet_input_common.applet_mode) { | ||
| 88 | case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: | ||
| 89 | case Service::NFP::CabinetMode::StartGameDataEraser: | ||
| 90 | case Service::NFP::CabinetMode::StartRestorer: | ||
| 91 | case Service::NFP::CabinetMode::StartFormatter: | ||
| 92 | frontend.ShowCabinetApplet(callback, parameters, nfp_device); | ||
| 93 | break; | ||
| 94 | default: | ||
| 95 | UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); | ||
| 96 | DisplayCompleted(false, {}); | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) { | ||
| 102 | Service::Mii::MiiManager manager; | ||
| 103 | ReturnValueForAmiiboSettings applet_output{}; | ||
| 104 | |||
| 105 | if (!apply_changes) { | ||
| 106 | Cancel(); | ||
| 107 | } | ||
| 108 | |||
| 109 | if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && | ||
| 110 | nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { | ||
| 111 | Cancel(); | ||
| 112 | } | ||
| 113 | |||
| 114 | if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) { | ||
| 115 | nfp_device->Mount(Service::NFP::MountTarget::All); | ||
| 116 | } | ||
| 117 | |||
| 118 | switch (applet_input_common.applet_mode) { | ||
| 119 | case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { | ||
| 120 | Service::NFP::AmiiboName name{}; | ||
| 121 | std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); | ||
| 122 | nfp_device->SetNicknameAndOwner(name); | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | case Service::NFP::CabinetMode::StartGameDataEraser: | ||
| 126 | nfp_device->DeleteApplicationArea(); | ||
| 127 | break; | ||
| 128 | case Service::NFP::CabinetMode::StartRestorer: | ||
| 129 | nfp_device->RestoreAmiibo(); | ||
| 130 | break; | ||
| 131 | case Service::NFP::CabinetMode::StartFormatter: | ||
| 132 | nfp_device->DeleteAllData(); | ||
| 133 | break; | ||
| 134 | default: | ||
| 135 | UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | |||
| 139 | applet_output.device_handle = applet_input_common.device_handle; | ||
| 140 | applet_output.result = CabinetResult::Cancel; | ||
| 141 | const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); | ||
| 142 | const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); | ||
| 143 | nfp_device->Finalize(); | ||
| 144 | |||
| 145 | if (reg_result.IsSuccess()) { | ||
| 146 | applet_output.result |= CabinetResult::RegisterInfo; | ||
| 147 | } | ||
| 148 | |||
| 149 | if (tag_result.IsSuccess()) { | ||
| 150 | applet_output.result |= CabinetResult::TagInfo; | ||
| 151 | } | ||
| 152 | |||
| 153 | std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings)); | ||
| 154 | std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); | ||
| 155 | |||
| 156 | is_complete = true; | ||
| 157 | |||
| 158 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); | ||
| 159 | broker.SignalStateChanged(); | ||
| 160 | } | ||
| 161 | |||
| 162 | void Cabinet::Cancel() { | ||
| 163 | ReturnValueForAmiiboSettings applet_output{}; | ||
| 164 | applet_output.device_handle = applet_input_common.device_handle; | ||
| 165 | applet_output.result = CabinetResult::Cancel; | ||
| 166 | nfp_device->Finalize(); | ||
| 167 | |||
| 168 | std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings)); | ||
| 169 | std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); | ||
| 170 | |||
| 171 | is_complete = true; | ||
| 172 | |||
| 173 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); | ||
| 174 | broker.SignalStateChanged(); | ||
| 175 | } | ||
| 176 | |||
| 177 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h new file mode 100644 index 000000000..84197a807 --- /dev/null +++ b/src/core/hle/service/am/applets/applet_cabinet.h | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "core/hle/result.h" | ||
| 9 | #include "core/hle/service/am/applets/applets.h" | ||
| 10 | #include "core/hle/service/kernel_helpers.h" | ||
| 11 | #include "core/hle/service/nfp/nfp_types.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | class KEvent; | ||
| 15 | class KReadableEvent; | ||
| 16 | } // namespace Kernel | ||
| 17 | |||
| 18 | namespace Core { | ||
| 19 | class System; | ||
| 20 | } // namespace Core | ||
| 21 | |||
| 22 | namespace Service::NFP { | ||
| 23 | class NfpDevice; | ||
| 24 | } | ||
| 25 | |||
| 26 | namespace Service::AM::Applets { | ||
| 27 | |||
| 28 | enum class CabinetAppletVersion : u32 { | ||
| 29 | Version1 = 0x1, | ||
| 30 | }; | ||
| 31 | |||
| 32 | enum class CabinetResult : u8 { | ||
| 33 | Cancel = 0, | ||
| 34 | TagInfo = 1 << 1, | ||
| 35 | RegisterInfo = 1 << 2, | ||
| 36 | All = TagInfo | RegisterInfo, | ||
| 37 | }; | ||
| 38 | DECLARE_ENUM_FLAG_OPERATORS(CabinetResult) | ||
| 39 | |||
| 40 | // This is nn::nfp::AmiiboSettingsStartParam | ||
| 41 | struct AmiiboSettingsStartParam { | ||
| 42 | u64 device_handle; | ||
| 43 | std::array<u8, 0x20> param_1; | ||
| 44 | u8 param_2; | ||
| 45 | }; | ||
| 46 | static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, | ||
| 47 | "AmiiboSettingsStartParam is an invalid size"); | ||
| 48 | |||
| 49 | #pragma pack(push, 1) | ||
| 50 | // This is nn::nfp::StartParamForAmiiboSettings | ||
| 51 | struct StartParamForAmiiboSettings { | ||
| 52 | u8 param_1; | ||
| 53 | Service::NFP::CabinetMode applet_mode; | ||
| 54 | u8 flags; | ||
| 55 | u8 amiibo_settings_1; | ||
| 56 | u64 device_handle; | ||
| 57 | Service::NFP::TagInfo tag_info; | ||
| 58 | Service::NFP::RegisterInfo register_info; | ||
| 59 | std::array<u8, 0x20> amiibo_settings_3; | ||
| 60 | INSERT_PADDING_BYTES(0x24); | ||
| 61 | }; | ||
| 62 | static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, | ||
| 63 | "StartParamForAmiiboSettings is an invalid size"); | ||
| 64 | |||
| 65 | // This is nn::nfp::ReturnValueForAmiiboSettings | ||
| 66 | struct ReturnValueForAmiiboSettings { | ||
| 67 | CabinetResult result; | ||
| 68 | INSERT_PADDING_BYTES(0x3); | ||
| 69 | u64 device_handle; | ||
| 70 | Service::NFP::TagInfo tag_info; | ||
| 71 | Service::NFP::RegisterInfo register_info; | ||
| 72 | INSERT_PADDING_BYTES(0x24); | ||
| 73 | }; | ||
| 74 | static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, | ||
| 75 | "ReturnValueForAmiiboSettings is an invalid size"); | ||
| 76 | #pragma pack(pop) | ||
| 77 | |||
| 78 | class Cabinet final : public Applet { | ||
| 79 | public: | ||
| 80 | explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, | ||
| 81 | const Core::Frontend::CabinetApplet& frontend_); | ||
| 82 | ~Cabinet() override; | ||
| 83 | |||
| 84 | void Initialize() override; | ||
| 85 | |||
| 86 | bool TransactionComplete() const override; | ||
| 87 | Result GetStatus() const override; | ||
| 88 | void ExecuteInteractive() override; | ||
| 89 | void Execute() override; | ||
| 90 | void DisplayCompleted(bool apply_changes, std::string_view amiibo_name); | ||
| 91 | void Cancel(); | ||
| 92 | |||
| 93 | private: | ||
| 94 | const Core::Frontend::CabinetApplet& frontend; | ||
| 95 | Core::System& system; | ||
| 96 | |||
| 97 | bool is_complete{false}; | ||
| 98 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device; | ||
| 99 | Kernel::KEvent* availability_change_event; | ||
| 100 | KernelHelpers::ServiceContext service_context; | ||
| 101 | StartParamForAmiiboSettings applet_input_common{}; | ||
| 102 | }; | ||
| 103 | |||
| 104 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index fcf34bf7e..bae0d99a6 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp | |||
| @@ -144,6 +144,7 @@ void Error::Initialize() { | |||
| 144 | break; | 144 | break; |
| 145 | default: | 145 | default: |
| 146 | UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); | 146 | UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); |
| 147 | break; | ||
| 147 | } | 148 | } |
| 148 | } | 149 | } |
| 149 | 150 | ||
diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index c34ef08b3..e50acdaf6 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp | |||
| @@ -129,6 +129,7 @@ void Auth::Execute() { | |||
| 129 | } | 129 | } |
| 130 | default: | 130 | default: |
| 131 | unimplemented_log(); | 131 | unimplemented_log(); |
| 132 | break; | ||
| 132 | } | 133 | } |
| 133 | } | 134 | } |
| 134 | 135 | ||
| @@ -192,6 +193,7 @@ void PhotoViewer::Execute() { | |||
| 192 | break; | 193 | break; |
| 193 | default: | 194 | default: |
| 194 | UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); | 195 | UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); |
| 196 | break; | ||
| 195 | } | 197 | } |
| 196 | } | 198 | } |
| 197 | 199 | ||
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7062df21c..10afbc2da 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/frontend/applets/cabinet.h" | ||
| 8 | #include "core/frontend/applets/controller.h" | 9 | #include "core/frontend/applets/controller.h" |
| 9 | #include "core/frontend/applets/error.h" | 10 | #include "core/frontend/applets/error.h" |
| 10 | #include "core/frontend/applets/general_frontend.h" | 11 | #include "core/frontend/applets/general_frontend.h" |
| @@ -16,6 +17,7 @@ | |||
| 16 | #include "core/hle/service/am/am.h" | 17 | #include "core/hle/service/am/am.h" |
| 17 | #include "core/hle/service/am/applet_ae.h" | 18 | #include "core/hle/service/am/applet_ae.h" |
| 18 | #include "core/hle/service/am/applet_oe.h" | 19 | #include "core/hle/service/am/applet_oe.h" |
| 20 | #include "core/hle/service/am/applets/applet_cabinet.h" | ||
| 19 | #include "core/hle/service/am/applets/applet_controller.h" | 21 | #include "core/hle/service/am/applets/applet_controller.h" |
| 20 | #include "core/hle/service/am/applets/applet_error.h" | 22 | #include "core/hle/service/am/applets/applet_error.h" |
| 21 | #include "core/hle/service/am/applets/applet_general_backend.h" | 23 | #include "core/hle/service/am/applets/applet_general_backend.h" |
| @@ -171,13 +173,15 @@ void Applet::Initialize() { | |||
| 171 | 173 | ||
| 172 | AppletFrontendSet::AppletFrontendSet() = default; | 174 | AppletFrontendSet::AppletFrontendSet() = default; |
| 173 | 175 | ||
| 174 | AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, | 176 | AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet, |
| 177 | ControllerApplet controller_applet, ErrorApplet error_applet, | ||
| 175 | MiiEdit mii_edit_, | 178 | MiiEdit mii_edit_, |
| 176 | ParentalControlsApplet parental_controls_applet, | 179 | ParentalControlsApplet parental_controls_applet, |
| 177 | PhotoViewer photo_viewer_, ProfileSelect profile_select_, | 180 | PhotoViewer photo_viewer_, ProfileSelect profile_select_, |
| 178 | SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) | 181 | SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) |
| 179 | : controller{std::move(controller_applet)}, error{std::move(error_applet)}, | 182 | : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, |
| 180 | mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)}, | 183 | error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, |
| 184 | parental_controls{std::move(parental_controls_applet)}, | ||
| 181 | photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, | 185 | photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, |
| 182 | software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} | 186 | software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} |
| 183 | 187 | ||
| @@ -196,6 +200,10 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { | |||
| 196 | } | 200 | } |
| 197 | 201 | ||
| 198 | void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { | 202 | void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { |
| 203 | if (set.cabinet != nullptr) { | ||
| 204 | frontend.cabinet = std::move(set.cabinet); | ||
| 205 | } | ||
| 206 | |||
| 199 | if (set.controller != nullptr) { | 207 | if (set.controller != nullptr) { |
| 200 | frontend.controller = std::move(set.controller); | 208 | frontend.controller = std::move(set.controller); |
| 201 | } | 209 | } |
| @@ -235,6 +243,10 @@ void AppletManager::SetDefaultAppletFrontendSet() { | |||
| 235 | } | 243 | } |
| 236 | 244 | ||
| 237 | void AppletManager::SetDefaultAppletsIfMissing() { | 245 | void AppletManager::SetDefaultAppletsIfMissing() { |
| 246 | if (frontend.cabinet == nullptr) { | ||
| 247 | frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>(); | ||
| 248 | } | ||
| 249 | |||
| 238 | if (frontend.controller == nullptr) { | 250 | if (frontend.controller == nullptr) { |
| 239 | frontend.controller = | 251 | frontend.controller = |
| 240 | std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); | 252 | std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); |
| @@ -279,6 +291,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode | |||
| 279 | switch (id) { | 291 | switch (id) { |
| 280 | case AppletId::Auth: | 292 | case AppletId::Auth: |
| 281 | return std::make_shared<Auth>(system, mode, *frontend.parental_controls); | 293 | return std::make_shared<Auth>(system, mode, *frontend.parental_controls); |
| 294 | case AppletId::Cabinet: | ||
| 295 | return std::make_shared<Cabinet>(system, mode, *frontend.cabinet); | ||
| 282 | case AppletId::Controller: | 296 | case AppletId::Controller: |
| 283 | return std::make_shared<Controller>(system, mode, *frontend.controller); | 297 | return std::make_shared<Controller>(system, mode, *frontend.controller); |
| 284 | case AppletId::Error: | 298 | case AppletId::Error: |
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 12c6a5b1a..a22eb62a8 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -16,6 +16,7 @@ class System; | |||
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | namespace Core::Frontend { | 18 | namespace Core::Frontend { |
| 19 | class CabinetApplet; | ||
| 19 | class ControllerApplet; | 20 | class ControllerApplet; |
| 20 | class ECommerceApplet; | 21 | class ECommerceApplet; |
| 21 | class ErrorApplet; | 22 | class ErrorApplet; |
| @@ -176,6 +177,7 @@ protected: | |||
| 176 | }; | 177 | }; |
| 177 | 178 | ||
| 178 | struct AppletFrontendSet { | 179 | struct AppletFrontendSet { |
| 180 | using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>; | ||
| 179 | using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; | 181 | using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; |
| 180 | using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; | 182 | using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; |
| 181 | using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; | 183 | using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; |
| @@ -186,10 +188,11 @@ struct AppletFrontendSet { | |||
| 186 | using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; | 188 | using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; |
| 187 | 189 | ||
| 188 | AppletFrontendSet(); | 190 | AppletFrontendSet(); |
| 189 | AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, | 191 | AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, |
| 190 | MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, | 192 | ErrorApplet error_applet, MiiEdit mii_edit_, |
| 191 | PhotoViewer photo_viewer_, ProfileSelect profile_select_, | 193 | ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, |
| 192 | SoftwareKeyboard software_keyboard_, WebBrowser web_browser_); | 194 | ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, |
| 195 | WebBrowser web_browser_); | ||
| 193 | ~AppletFrontendSet(); | 196 | ~AppletFrontendSet(); |
| 194 | 197 | ||
| 195 | AppletFrontendSet(const AppletFrontendSet&) = delete; | 198 | AppletFrontendSet(const AppletFrontendSet&) = delete; |
| @@ -198,6 +201,7 @@ struct AppletFrontendSet { | |||
| 198 | AppletFrontendSet(AppletFrontendSet&&) noexcept; | 201 | AppletFrontendSet(AppletFrontendSet&&) noexcept; |
| 199 | AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; | 202 | AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; |
| 200 | 203 | ||
| 204 | CabinetApplet cabinet; | ||
| 201 | ControllerApplet controller; | 205 | ControllerApplet controller; |
| 202 | ErrorApplet error; | 206 | ErrorApplet error; |
| 203 | MiiEdit mii_edit; | 207 | MiiEdit mii_edit; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 79375bd2f..bf28440c6 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -36,8 +36,9 @@ namespace Service::HID { | |||
| 36 | 36 | ||
| 37 | // Updating period for each HID device. | 37 | // Updating period for each HID device. |
| 38 | // Period time is obtained by measuring the number of samples in a second on HW using a homebrew | 38 | // Period time is obtained by measuring the number of samples in a second on HW using a homebrew |
| 39 | // Correct pad_update_ns is 4ms this is overclocked to lower input lag | 39 | // Correct npad_update_ns is 4ms this is overclocked to lower input lag |
| 40 | constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) | 40 | constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) |
| 41 | constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz) | ||
| 41 | constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) | 42 | constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) |
| 42 | constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) | 43 | constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) |
| 43 | 44 | ||
| @@ -75,11 +76,19 @@ IAppletResource::IAppletResource(Core::System& system_, | |||
| 75 | GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); | 76 | GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); |
| 76 | 77 | ||
| 77 | // Register update callbacks | 78 | // Register update callbacks |
| 78 | pad_update_event = Core::Timing::CreateEvent( | 79 | npad_update_event = Core::Timing::CreateEvent( |
| 79 | "HID::UpdatePadCallback", | 80 | "HID::UpdatePadCallback", |
| 80 | [this](std::uintptr_t user_data, s64 time, | 81 | [this](std::uintptr_t user_data, s64 time, |
| 81 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | 82 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 82 | const auto guard = LockService(); | 83 | const auto guard = LockService(); |
| 84 | UpdateNpad(user_data, ns_late); | ||
| 85 | return std::nullopt; | ||
| 86 | }); | ||
| 87 | default_update_event = Core::Timing::CreateEvent( | ||
| 88 | "HID::UpdateDefaultCallback", | ||
| 89 | [this](std::uintptr_t user_data, s64 time, | ||
| 90 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 91 | const auto guard = LockService(); | ||
| 83 | UpdateControllers(user_data, ns_late); | 92 | UpdateControllers(user_data, ns_late); |
| 84 | return std::nullopt; | 93 | return std::nullopt; |
| 85 | }); | 94 | }); |
| @@ -100,7 +109,9 @@ IAppletResource::IAppletResource(Core::System& system_, | |||
| 100 | return std::nullopt; | 109 | return std::nullopt; |
| 101 | }); | 110 | }); |
| 102 | 111 | ||
| 103 | system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); | 112 | system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event); |
| 113 | system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns, | ||
| 114 | default_update_event); | ||
| 104 | system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, | 115 | system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, |
| 105 | mouse_keyboard_update_event); | 116 | mouse_keyboard_update_event); |
| 106 | system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, | 117 | system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, |
| @@ -118,7 +129,8 @@ void IAppletResource::DeactivateController(HidController controller) { | |||
| 118 | } | 129 | } |
| 119 | 130 | ||
| 120 | IAppletResource::~IAppletResource() { | 131 | IAppletResource::~IAppletResource() { |
| 121 | system.CoreTiming().UnscheduleEvent(pad_update_event, 0); | 132 | system.CoreTiming().UnscheduleEvent(npad_update_event, 0); |
| 133 | system.CoreTiming().UnscheduleEvent(default_update_event, 0); | ||
| 122 | system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); | 134 | system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); |
| 123 | system.CoreTiming().UnscheduleEvent(motion_update_event, 0); | 135 | system.CoreTiming().UnscheduleEvent(motion_update_event, 0); |
| 124 | } | 136 | } |
| @@ -144,10 +156,20 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, | |||
| 144 | if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { | 156 | if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { |
| 145 | continue; | 157 | continue; |
| 146 | } | 158 | } |
| 159 | // Npad has it's own update event | ||
| 160 | if (controller == controllers[static_cast<size_t>(HidController::NPad)]) { | ||
| 161 | continue; | ||
| 162 | } | ||
| 147 | controller->OnUpdate(core_timing); | 163 | controller->OnUpdate(core_timing); |
| 148 | } | 164 | } |
| 149 | } | 165 | } |
| 150 | 166 | ||
| 167 | void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | ||
| 168 | auto& core_timing = system.CoreTiming(); | ||
| 169 | |||
| 170 | controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing); | ||
| 171 | } | ||
| 172 | |||
| 151 | void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, | 173 | void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, |
| 152 | std::chrono::nanoseconds ns_late) { | 174 | std::chrono::nanoseconds ns_late) { |
| 153 | auto& core_timing = system.CoreTiming(); | 175 | auto& core_timing = system.CoreTiming(); |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 340d26fdc..b7c2a23ef 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -71,12 +71,14 @@ private: | |||
| 71 | 71 | ||
| 72 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); | 72 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); |
| 73 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 73 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| 74 | void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | ||
| 74 | void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 75 | void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| 75 | void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 76 | void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| 76 | 77 | ||
| 77 | KernelHelpers::ServiceContext& service_context; | 78 | KernelHelpers::ServiceContext& service_context; |
| 78 | 79 | ||
| 79 | std::shared_ptr<Core::Timing::EventType> pad_update_event; | 80 | std::shared_ptr<Core::Timing::EventType> npad_update_event; |
| 81 | std::shared_ptr<Core::Timing::EventType> default_update_event; | ||
| 80 | std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; | 82 | std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; |
| 81 | std::shared_ptr<Core::Timing::EventType> motion_update_event; | 83 | std::shared_ptr<Core::Timing::EventType> motion_update_event; |
| 82 | 84 | ||
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 296603764..c860fd1a1 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp | |||
| @@ -75,6 +75,9 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { | |||
| 75 | LoadAmiibo(nfc_status.data); | 75 | LoadAmiibo(nfc_status.data); |
| 76 | break; | 76 | break; |
| 77 | case Common::Input::NfcState::AmiiboRemoved: | 77 | case Common::Input::NfcState::AmiiboRemoved: |
| 78 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | ||
| 79 | break; | ||
| 80 | } | ||
| 78 | if (device_state != DeviceState::SearchingForTag) { | 81 | if (device_state != DeviceState::SearchingForTag) { |
| 79 | CloseAmiibo(); | 82 | CloseAmiibo(); |
| 80 | } | 83 | } |
| @@ -95,6 +98,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) { | |||
| 95 | return false; | 98 | return false; |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 101 | // TODO: Filter by allowed_protocols here | ||
| 102 | |||
| 98 | memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); | 103 | memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); |
| 99 | 104 | ||
| 100 | device_state = DeviceState::TagFound; | 105 | device_state = DeviceState::TagFound; |
| @@ -141,7 +146,7 @@ void NfpDevice::Finalize() { | |||
| 141 | device_state = DeviceState::Unavailable; | 146 | device_state = DeviceState::Unavailable; |
| 142 | } | 147 | } |
| 143 | 148 | ||
| 144 | Result NfpDevice::StartDetection(s32 protocol_) { | 149 | Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { |
| 145 | if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { | 150 | if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { |
| 146 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | 151 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); |
| 147 | return WrongDeviceState; | 152 | return WrongDeviceState; |
| @@ -153,7 +158,7 @@ Result NfpDevice::StartDetection(s32 protocol_) { | |||
| 153 | } | 158 | } |
| 154 | 159 | ||
| 155 | device_state = DeviceState::SearchingForTag; | 160 | device_state = DeviceState::SearchingForTag; |
| 156 | protocol = protocol_; | 161 | allowed_protocols = allowed_protocol; |
| 157 | return ResultSuccess; | 162 | return ResultSuccess; |
| 158 | } | 163 | } |
| 159 | 164 | ||
| @@ -467,6 +472,32 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) { | |||
| 467 | return ResultSuccess; | 472 | return ResultSuccess; |
| 468 | } | 473 | } |
| 469 | 474 | ||
| 475 | Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { | ||
| 476 | application_area_id = {}; | ||
| 477 | |||
| 478 | if (device_state != DeviceState::TagMounted) { | ||
| 479 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 480 | if (device_state == DeviceState::TagRemoved) { | ||
| 481 | return TagRemoved; | ||
| 482 | } | ||
| 483 | return WrongDeviceState; | ||
| 484 | } | ||
| 485 | |||
| 486 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 487 | LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); | ||
| 488 | return WrongDeviceState; | ||
| 489 | } | ||
| 490 | |||
| 491 | if (tag_data.settings.settings.appdata_initialized.Value() == 0) { | ||
| 492 | LOG_WARNING(Service_NFP, "Application area is not initialized"); | ||
| 493 | return ApplicationAreaIsNotInitialized; | ||
| 494 | } | ||
| 495 | |||
| 496 | application_area_id = tag_data.application_area_id; | ||
| 497 | |||
| 498 | return ResultSuccess; | ||
| 499 | } | ||
| 500 | |||
| 470 | Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { | 501 | Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { |
| 471 | if (device_state != DeviceState::TagMounted) { | 502 | if (device_state != DeviceState::TagMounted) { |
| 472 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | 503 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); |
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 6d8fc1099..b6a46f2ac 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <span> | ||
| 6 | #include <vector> | 7 | #include <vector> |
| 7 | 8 | ||
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| @@ -36,7 +37,7 @@ public: | |||
| 36 | void Initialize(); | 37 | void Initialize(); |
| 37 | void Finalize(); | 38 | void Finalize(); |
| 38 | 39 | ||
| 39 | Result StartDetection(s32 protocol_); | 40 | Result StartDetection(TagProtocol allowed_protocol); |
| 40 | Result StopDetection(); | 41 | Result StopDetection(); |
| 41 | Result Mount(MountTarget mount_target); | 42 | Result Mount(MountTarget mount_target); |
| 42 | Result Unmount(); | 43 | Result Unmount(); |
| @@ -52,6 +53,7 @@ public: | |||
| 52 | Result DeleteAllData(); | 53 | Result DeleteAllData(); |
| 53 | 54 | ||
| 54 | Result OpenApplicationArea(u32 access_id); | 55 | Result OpenApplicationArea(u32 access_id); |
| 56 | Result GetApplicationAreaId(u32& application_area_id) const; | ||
| 55 | Result GetApplicationArea(std::vector<u8>& data) const; | 57 | Result GetApplicationArea(std::vector<u8>& data) const; |
| 56 | Result SetApplicationArea(std::span<const u8> data); | 58 | Result SetApplicationArea(std::span<const u8> data); |
| 57 | Result CreateApplicationArea(u32 access_id, std::span<const u8> data); | 59 | Result CreateApplicationArea(u32 access_id, std::span<const u8> data); |
| @@ -87,7 +89,7 @@ private: | |||
| 87 | 89 | ||
| 88 | bool is_data_moddified{}; | 90 | bool is_data_moddified{}; |
| 89 | bool is_app_area_open{}; | 91 | bool is_app_area_open{}; |
| 90 | s32 protocol{}; | 92 | TagProtocol allowed_protocols{}; |
| 91 | s64 current_posix_time{}; | 93 | s64 current_posix_time{}; |
| 92 | MountTarget mount_target{MountTarget::None}; | 94 | MountTarget mount_target{MountTarget::None}; |
| 93 | DeviceState device_state{DeviceState::Unavailable}; | 95 | DeviceState device_state{DeviceState::Unavailable}; |
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 63d5917cb..69858096a 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h | |||
| @@ -88,11 +88,22 @@ enum class PackedTagType : u8 { | |||
| 88 | Type5, // ISO15693 RW/RO 540 bytes 106kbit/s | 88 | Type5, // ISO15693 RW/RO 540 bytes 106kbit/s |
| 89 | }; | 89 | }; |
| 90 | 90 | ||
| 91 | // Verify this enum. It might be completely wrong default protocol is 0x48 | ||
| 91 | enum class TagProtocol : u32 { | 92 | enum class TagProtocol : u32 { |
| 92 | None, | 93 | None, |
| 93 | TypeA, // ISO14443A | 94 | TypeA = 1U << 0, // ISO14443A |
| 94 | TypeB, // ISO14443B | 95 | TypeB = 1U << 1, // ISO14443B |
| 95 | TypeF, // Sony Felica | 96 | TypeF = 1U << 2, // Sony Felica |
| 97 | Unknown1 = 1U << 3, | ||
| 98 | Unknown2 = 1U << 5, | ||
| 99 | All = 0xFFFFFFFFU, | ||
| 100 | }; | ||
| 101 | |||
| 102 | enum class CabinetMode : u8 { | ||
| 103 | StartNicknameAndOwnerSettings, | ||
| 104 | StartGameDataEraser, | ||
| 105 | StartRestorer, | ||
| 106 | StartFormatter, | ||
| 96 | }; | 107 | }; |
| 97 | 108 | ||
| 98 | using UniqueSerialNumber = std::array<u8, 7>; | 109 | using UniqueSerialNumber = std::array<u8, 7>; |
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 3f7f17598..2fe3c0ea0 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp | |||
| @@ -131,7 +131,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) { | |||
| 131 | void IUser::StartDetection(Kernel::HLERequestContext& ctx) { | 131 | void IUser::StartDetection(Kernel::HLERequestContext& ctx) { |
| 132 | IPC::RequestParser rp{ctx}; | 132 | IPC::RequestParser rp{ctx}; |
| 133 | const auto device_handle{rp.Pop<u64>()}; | 133 | const auto device_handle{rp.Pop<u64>()}; |
| 134 | const auto nfp_protocol{rp.Pop<s32>()}; | 134 | const auto nfp_protocol{rp.PopEnum<TagProtocol>()}; |
| 135 | LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); | 135 | LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); |
| 136 | 136 | ||
| 137 | if (state == State::NonInitialized) { | 137 | if (state == State::NonInitialized) { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index ced57dfe6..b97813fbc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -300,11 +300,10 @@ Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) { | |||
| 300 | return error_notifier_event; | 300 | return error_notifier_event; |
| 301 | case 2: | 301 | case 2: |
| 302 | return unknown_event; | 302 | return unknown_event; |
| 303 | default: { | 303 | default: |
| 304 | LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); | 304 | LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); |
| 305 | return nullptr; | ||
| 305 | } | 306 | } |
| 306 | } | ||
| 307 | return nullptr; | ||
| 308 | } | 307 | } |
| 309 | 308 | ||
| 310 | } // namespace Service::Nvidia::Devices | 309 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 45a759fa8..e123564c6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -364,11 +364,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) { | |||
| 364 | return sm_exception_breakpoint_pause_report_event; | 364 | return sm_exception_breakpoint_pause_report_event; |
| 365 | case 3: | 365 | case 3: |
| 366 | return error_notifier_event; | 366 | return error_notifier_event; |
| 367 | default: { | 367 | default: |
| 368 | LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); | 368 | LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); |
| 369 | return nullptr; | ||
| 369 | } | 370 | } |
| 370 | } | ||
| 371 | return nullptr; | ||
| 372 | } | 371 | } |
| 373 | 372 | ||
| 374 | } // namespace Service::Nvidia::Devices | 373 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index ea4a14ea4..3d1338e66 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp | |||
| @@ -23,15 +23,17 @@ void BufferQueueCore::NotifyShutdown() { | |||
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | void BufferQueueCore::SignalDequeueCondition() { | 25 | void BufferQueueCore::SignalDequeueCondition() { |
| 26 | dequeue_possible.store(true); | ||
| 26 | dequeue_condition.notify_all(); | 27 | dequeue_condition.notify_all(); |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | bool BufferQueueCore::WaitForDequeueCondition() { | 30 | bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) { |
| 30 | if (is_shutting_down) { | 31 | if (is_shutting_down) { |
| 31 | return false; | 32 | return false; |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | dequeue_condition.wait(mutex); | 35 | dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); |
| 36 | dequeue_possible.store(false); | ||
| 35 | 37 | ||
| 36 | return true; | 38 | return true; |
| 37 | } | 39 | } |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h index ca6baefaf..85b3bc4c1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h | |||
| @@ -38,7 +38,7 @@ public: | |||
| 38 | 38 | ||
| 39 | private: | 39 | private: |
| 40 | void SignalDequeueCondition(); | 40 | void SignalDequeueCondition(); |
| 41 | bool WaitForDequeueCondition(); | 41 | bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk); |
| 42 | 42 | ||
| 43 | s32 GetMinUndequeuedBufferCountLocked(bool async) const; | 43 | s32 GetMinUndequeuedBufferCountLocked(bool async) const; |
| 44 | s32 GetMinMaxBufferCountLocked(bool async) const; | 44 | s32 GetMinMaxBufferCountLocked(bool async) const; |
| @@ -60,7 +60,8 @@ private: | |||
| 60 | BufferQueueDefs::SlotsType slots{}; | 60 | BufferQueueDefs::SlotsType slots{}; |
| 61 | std::vector<BufferItem> queue; | 61 | std::vector<BufferItem> queue; |
| 62 | s32 override_max_buffer_count{}; | 62 | s32 override_max_buffer_count{}; |
| 63 | mutable std::condition_variable_any dequeue_condition; | 63 | std::condition_variable dequeue_condition; |
| 64 | std::atomic<bool> dequeue_possible{}; | ||
| 64 | const bool use_async_buffer{}; // This is always disabled on HOS | 65 | const bool use_async_buffer{}; // This is always disabled on HOS |
| 65 | bool dequeue_buffer_cannot_block{}; | 66 | bool dequeue_buffer_cannot_block{}; |
| 66 | PixelFormat default_buffer_format{PixelFormat::Rgba8888}; | 67 | PixelFormat default_buffer_format{PixelFormat::Rgba8888}; |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 41ba44b21..e601b5da1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp | |||
| @@ -121,8 +121,8 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) { | |||
| 121 | return Status::NoError; | 121 | return Status::NoError; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, | 124 | Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, |
| 125 | Status* return_flags) const { | 125 | std::unique_lock<std::mutex>& lk) const { |
| 126 | bool try_again = true; | 126 | bool try_again = true; |
| 127 | 127 | ||
| 128 | while (try_again) { | 128 | while (try_again) { |
| @@ -214,7 +214,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, | |||
| 214 | return Status::WouldBlock; | 214 | return Status::WouldBlock; |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | if (!core->WaitForDequeueCondition()) { | 217 | if (!core->WaitForDequeueCondition(lk)) { |
| 218 | // We are no longer running | 218 | // We are no longer running |
| 219 | return Status::NoError; | 219 | return Status::NoError; |
| 220 | } | 220 | } |
| @@ -237,7 +237,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool | |||
| 237 | Status return_flags = Status::NoError; | 237 | Status return_flags = Status::NoError; |
| 238 | bool attached_by_consumer = false; | 238 | bool attached_by_consumer = false; |
| 239 | { | 239 | { |
| 240 | std::scoped_lock lock{core->mutex}; | 240 | std::unique_lock lock{core->mutex}; |
| 241 | core->WaitWhileAllocatingLocked(); | 241 | core->WaitWhileAllocatingLocked(); |
| 242 | 242 | ||
| 243 | if (format == PixelFormat::NoFormat) { | 243 | if (format == PixelFormat::NoFormat) { |
| @@ -248,7 +248,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool | |||
| 248 | usage |= core->consumer_usage_bit; | 248 | usage |= core->consumer_usage_bit; |
| 249 | 249 | ||
| 250 | s32 found{}; | 250 | s32 found{}; |
| 251 | Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); | 251 | Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock); |
| 252 | if (status != Status::NoError) { | 252 | if (status != Status::NoError) { |
| 253 | return status; | 253 | return status; |
| 254 | } | 254 | } |
| @@ -400,13 +400,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot, | |||
| 400 | return Status::BadValue; | 400 | return Status::BadValue; |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | std::scoped_lock lock{core->mutex}; | 403 | std::unique_lock lock{core->mutex}; |
| 404 | core->WaitWhileAllocatingLocked(); | 404 | core->WaitWhileAllocatingLocked(); |
| 405 | 405 | ||
| 406 | Status return_flags = Status::NoError; | 406 | Status return_flags = Status::NoError; |
| 407 | s32 found{}; | 407 | s32 found{}; |
| 408 | 408 | ||
| 409 | const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags); | 409 | const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock); |
| 410 | if (status != Status::NoError) { | 410 | if (status != Status::NoError) { |
| 411 | return status; | 411 | return status; |
| 412 | } | 412 | } |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h index 7526bf8ec..1d380480f 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h | |||
| @@ -70,7 +70,8 @@ public: | |||
| 70 | private: | 70 | private: |
| 71 | BufferQueueProducer(const BufferQueueProducer&) = delete; | 71 | BufferQueueProducer(const BufferQueueProducer&) = delete; |
| 72 | 72 | ||
| 73 | Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const; | 73 | Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, |
| 74 | std::unique_lock<std::mutex>& lk) const; | ||
| 74 | 75 | ||
| 75 | Kernel::KEvent* buffer_wait_event{}; | 76 | Kernel::KEvent* buffer_wait_event{}; |
| 76 | Service::KernelHelpers::ServiceContext& service_context; | 77 | Service::KernelHelpers::ServiceContext& service_context; |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5ab41c0c4..0de67f1e1 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -228,6 +228,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, | |||
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); | 230 | UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); |
| 231 | break; | ||
| 231 | } | 232 | } |
| 232 | 233 | ||
| 233 | // If emulation was shutdown, we are closing service threads, do not write the response back to | 234 | // If emulation was shutdown, we are closing service threads, do not write the response back to |
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 2aa675df9..f9ada7c93 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp | |||
| @@ -280,6 +280,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) { | |||
| 280 | } | 280 | } |
| 281 | default: | 281 | default: |
| 282 | ASSERT(false); | 282 | ASSERT(false); |
| 283 | break; | ||
| 283 | } | 284 | } |
| 284 | return value + rule.transition_time + offset; | 285 | return value + rule.transition_time + offset; |
| 285 | } | 286 | } |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3ca80c8ff..3141122f1 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/atomic_ops.h" | 8 | #include "common/atomic_ops.h" |
| 9 | #include "common/cache_management.h" | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 11 | #include "common/page_table.h" | 12 | #include "common/page_table.h" |
| @@ -329,6 +330,55 @@ struct Memory::Impl { | |||
| 329 | }); | 330 | }); |
| 330 | } | 331 | } |
| 331 | 332 | ||
| 333 | template <typename Callback> | ||
| 334 | Result PerformCacheOperation(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size, | ||
| 335 | Callback&& cb) { | ||
| 336 | class InvalidMemoryException : public std::exception {}; | ||
| 337 | |||
| 338 | try { | ||
| 339 | WalkBlock( | ||
| 340 | process, dest_addr, size, | ||
| 341 | [&](const std::size_t block_size, const VAddr current_vaddr) { | ||
| 342 | LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr); | ||
| 343 | throw InvalidMemoryException(); | ||
| 344 | }, | ||
| 345 | [&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); }, | ||
| 346 | [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) { | ||
| 347 | system.GPU().FlushRegion(current_vaddr, block_size); | ||
| 348 | cb(block_size, host_ptr); | ||
| 349 | }, | ||
| 350 | [](const std::size_t block_size) {}); | ||
| 351 | } catch (InvalidMemoryException&) { | ||
| 352 | return Kernel::ResultInvalidCurrentMemory; | ||
| 353 | } | ||
| 354 | |||
| 355 | return ResultSuccess; | ||
| 356 | } | ||
| 357 | |||
| 358 | Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { | ||
| 359 | auto perform = [&](const std::size_t block_size, u8* const host_ptr) { | ||
| 360 | // Do nothing; this operation (dc ivac) cannot be supported | ||
| 361 | // from EL0 | ||
| 362 | }; | ||
| 363 | return PerformCacheOperation(process, dest_addr, size, perform); | ||
| 364 | } | ||
| 365 | |||
| 366 | Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { | ||
| 367 | auto perform = [&](const std::size_t block_size, u8* const host_ptr) { | ||
| 368 | // dc cvac: Store to point of coherency | ||
| 369 | Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size); | ||
| 370 | }; | ||
| 371 | return PerformCacheOperation(process, dest_addr, size, perform); | ||
| 372 | } | ||
| 373 | |||
| 374 | Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { | ||
| 375 | auto perform = [&](const std::size_t block_size, u8* const host_ptr) { | ||
| 376 | // dc civac: Store to point of coherency, and invalidate from cache | ||
| 377 | Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size); | ||
| 378 | }; | ||
| 379 | return PerformCacheOperation(process, dest_addr, size, perform); | ||
| 380 | } | ||
| 381 | |||
| 332 | void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { | 382 | void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { |
| 333 | if (vaddr == 0) { | 383 | if (vaddr == 0) { |
| 334 | return; | 384 | return; |
| @@ -786,6 +836,21 @@ void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, const s | |||
| 786 | impl->ZeroBlock(process, dest_addr, size); | 836 | impl->ZeroBlock(process, dest_addr, size); |
| 787 | } | 837 | } |
| 788 | 838 | ||
| 839 | Result Memory::InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, | ||
| 840 | const std::size_t size) { | ||
| 841 | return impl->InvalidateDataCache(process, dest_addr, size); | ||
| 842 | } | ||
| 843 | |||
| 844 | Result Memory::StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, | ||
| 845 | const std::size_t size) { | ||
| 846 | return impl->StoreDataCache(process, dest_addr, size); | ||
| 847 | } | ||
| 848 | |||
| 849 | Result Memory::FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, | ||
| 850 | const std::size_t size) { | ||
| 851 | return impl->FlushDataCache(process, dest_addr, size); | ||
| 852 | } | ||
| 853 | |||
| 789 | void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { | 854 | void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { |
| 790 | impl->RasterizerMarkRegionCached(vaddr, size, cached); | 855 | impl->RasterizerMarkRegionCached(vaddr, size, cached); |
| 791 | } | 856 | } |
diff --git a/src/core/memory.h b/src/core/memory.h index 81eac448b..31fe699d8 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "core/hle/result.h" | ||
| 10 | 11 | ||
| 11 | namespace Common { | 12 | namespace Common { |
| 12 | struct PageTable; | 13 | struct PageTable; |
| @@ -450,6 +451,39 @@ public: | |||
| 450 | void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); | 451 | void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); |
| 451 | 452 | ||
| 452 | /** | 453 | /** |
| 454 | * Invalidates a range of bytes within the current process' address space at the specified | ||
| 455 | * virtual address. | ||
| 456 | * | ||
| 457 | * @param process The process that will have data invalidated within its address space. | ||
| 458 | * @param dest_addr The destination virtual address to invalidate the data from. | ||
| 459 | * @param size The size of the range to invalidate, in bytes. | ||
| 460 | * | ||
| 461 | */ | ||
| 462 | Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); | ||
| 463 | |||
| 464 | /** | ||
| 465 | * Stores a range of bytes within the current process' address space at the specified | ||
| 466 | * virtual address. | ||
| 467 | * | ||
| 468 | * @param process The process that will have data stored within its address space. | ||
| 469 | * @param dest_addr The destination virtual address to store the data from. | ||
| 470 | * @param size The size of the range to store, in bytes. | ||
| 471 | * | ||
| 472 | */ | ||
| 473 | Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); | ||
| 474 | |||
| 475 | /** | ||
| 476 | * Flushes a range of bytes within the current process' address space at the specified | ||
| 477 | * virtual address. | ||
| 478 | * | ||
| 479 | * @param process The process that will have data flushed within its address space. | ||
| 480 | * @param dest_addr The destination virtual address to flush the data from. | ||
| 481 | * @param size The size of the range to flush, in bytes. | ||
| 482 | * | ||
| 483 | */ | ||
| 484 | Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); | ||
| 485 | |||
| 486 | /** | ||
| 453 | * Marks each page within the specified address range as cached or uncached. | 487 | * Marks each page within the specified address range as cached or uncached. |
| 454 | * | 488 | * |
| 455 | * @param vaddr The virtual address indicating the start of the address range. | 489 | * @param vaddr The virtual address indicating the start of the address range. |
diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 0cd5129da..564a188e5 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp | |||
| @@ -60,6 +60,8 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData( | |||
| 60 | return Common::Input::NfcState::WriteFailed; | 60 | return Common::Input::NfcState::WriteFailed; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | amiibo_data = data; | ||
| 64 | |||
| 63 | return Common::Input::NfcState::Success; | 65 | return Common::Input::NfcState::Success; |
| 64 | } | 66 | } |
| 65 | 67 | ||
| @@ -91,6 +93,15 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { | |||
| 91 | return Info::Success; | 93 | return Info::Success; |
| 92 | } | 94 | } |
| 93 | 95 | ||
| 96 | VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | ||
| 97 | if (state == State::AmiiboIsOpen) { | ||
| 98 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); | ||
| 99 | return Info::Success; | ||
| 100 | } | ||
| 101 | |||
| 102 | return LoadAmiibo(file_path); | ||
| 103 | } | ||
| 104 | |||
| 94 | VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { | 105 | VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { |
| 95 | state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo | 106 | state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo |
| 96 | : State::Initialized; | 107 | : State::Initialized; |
| @@ -98,4 +109,8 @@ VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { | |||
| 98 | return Info::Success; | 109 | return Info::Success; |
| 99 | } | 110 | } |
| 100 | 111 | ||
| 112 | std::string VirtualAmiibo::GetLastFilePath() const { | ||
| 113 | return file_path; | ||
| 114 | } | ||
| 115 | |||
| 101 | } // namespace InputCommon | 116 | } // namespace InputCommon |
diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 9eac07544..9baeb3997 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h | |||
| @@ -47,8 +47,11 @@ public: | |||
| 47 | State GetCurrentState() const; | 47 | State GetCurrentState() const; |
| 48 | 48 | ||
| 49 | Info LoadAmiibo(const std::string& amiibo_file); | 49 | Info LoadAmiibo(const std::string& amiibo_file); |
| 50 | Info ReloadAmiibo(); | ||
| 50 | Info CloseAmiibo(); | 51 | Info CloseAmiibo(); |
| 51 | 52 | ||
| 53 | std::string GetLastFilePath() const; | ||
| 54 | |||
| 52 | private: | 55 | private: |
| 53 | static constexpr std::size_t amiibo_size = 0x21C; | 56 | static constexpr std::size_t amiibo_size = 0x21C; |
| 54 | static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8; | 57 | static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8; |
diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index da4a3dca5..003a38da5 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp | |||
| @@ -10,8 +10,8 @@ namespace InputCommon { | |||
| 10 | class TouchFromButtonDevice final : public Common::Input::InputDevice { | 10 | class TouchFromButtonDevice final : public Common::Input::InputDevice { |
| 11 | public: | 11 | public: |
| 12 | using Button = std::unique_ptr<Common::Input::InputDevice>; | 12 | using Button = std::unique_ptr<Common::Input::InputDevice>; |
| 13 | TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_) | 13 | TouchFromButtonDevice(Button button_, float x_, float y_) |
| 14 | : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { | 14 | : button(std::move(button_)), x(x_), y(y_) { |
| 15 | last_button_value = false; | 15 | last_button_value = false; |
| 16 | button->SetCallback({ | 16 | button->SetCallback({ |
| 17 | .on_change = | 17 | .on_change = |
| @@ -34,7 +34,6 @@ public: | |||
| 34 | .pressed = button_status, | 34 | .pressed = button_status, |
| 35 | .x = {}, | 35 | .x = {}, |
| 36 | .y = {}, | 36 | .y = {}, |
| 37 | .id = touch_id, | ||
| 38 | }; | 37 | }; |
| 39 | status.x.properties = properties; | 38 | status.x.properties = properties; |
| 40 | status.y.properties = properties; | 39 | status.y.properties = properties; |
| @@ -62,7 +61,6 @@ public: | |||
| 62 | private: | 61 | private: |
| 63 | Button button; | 62 | Button button; |
| 64 | bool last_button_value; | 63 | bool last_button_value; |
| 65 | const int touch_id; | ||
| 66 | const float x; | 64 | const float x; |
| 67 | const float y; | 65 | const float y; |
| 68 | const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; | 66 | const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; |
| @@ -73,10 +71,9 @@ std::unique_ptr<Common::Input::InputDevice> TouchFromButton::Create( | |||
| 73 | const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); | 71 | const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); |
| 74 | auto button = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( | 72 | auto button = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( |
| 75 | params.Get("button", null_engine)); | 73 | params.Get("button", null_engine)); |
| 76 | const auto touch_id = params.Get("touch_id", 0); | ||
| 77 | const float x = params.Get("x", 0.0f) / 1280.0f; | 74 | const float x = params.Get("x", 0.0f) / 1280.0f; |
| 78 | const float y = params.Get("y", 0.0f) / 720.0f; | 75 | const float y = params.Get("y", 0.0f) / 720.0f; |
| 79 | return std::make_unique<TouchFromButtonDevice>(std::move(button), touch_id, x, y); | 76 | return std::make_unique<TouchFromButtonDevice>(std::move(button), x, y); |
| 80 | } | 77 | } |
| 81 | 78 | ||
| 82 | } // namespace InputCommon | 79 | } // namespace InputCommon |
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index d4c264a8e..6cbcf5207 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h | |||
| @@ -133,7 +133,7 @@ public: | |||
| 133 | return Common::Input::CameraError::NotSupported; | 133 | return Common::Input::CameraError::NotSupported; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | // Request nfc data from a controller | 136 | // Returns success if nfc is supported |
| 137 | virtual Common::Input::NfcState SupportsNfc( | 137 | virtual Common::Input::NfcState SupportsNfc( |
| 138 | [[maybe_unused]] const PadIdentifier& identifier) const { | 138 | [[maybe_unused]] const PadIdentifier& identifier) const { |
| 139 | return Common::Input::NfcState::NotSupported; | 139 | return Common::Input::NfcState::NotSupported; |
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 4ac182147..fb8be42e2 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp | |||
| @@ -229,13 +229,12 @@ private: | |||
| 229 | 229 | ||
| 230 | class InputFromTouch final : public Common::Input::InputDevice { | 230 | class InputFromTouch final : public Common::Input::InputDevice { |
| 231 | public: | 231 | public: |
| 232 | explicit InputFromTouch(PadIdentifier identifier_, int touch_id_, int button_, bool toggle_, | 232 | explicit InputFromTouch(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, |
| 233 | bool inverted_, int axis_x_, int axis_y_, | 233 | int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_, |
| 234 | Common::Input::AnalogProperties properties_x_, | ||
| 235 | Common::Input::AnalogProperties properties_y_, | 234 | Common::Input::AnalogProperties properties_y_, |
| 236 | InputEngine* input_engine_) | 235 | InputEngine* input_engine_) |
| 237 | : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_), | 236 | : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), |
| 238 | inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), | 237 | axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), |
| 239 | properties_y(properties_y_), input_engine(input_engine_) { | 238 | properties_y(properties_y_), input_engine(input_engine_) { |
| 240 | UpdateCallback engine_callback{[this]() { OnChange(); }}; | 239 | UpdateCallback engine_callback{[this]() { OnChange(); }}; |
| 241 | const InputIdentifier button_input_identifier{ | 240 | const InputIdentifier button_input_identifier{ |
| @@ -271,8 +270,7 @@ public: | |||
| 271 | } | 270 | } |
| 272 | 271 | ||
| 273 | Common::Input::TouchStatus GetStatus() const { | 272 | Common::Input::TouchStatus GetStatus() const { |
| 274 | Common::Input::TouchStatus status; | 273 | Common::Input::TouchStatus status{}; |
| 275 | status.id = touch_id; | ||
| 276 | status.pressed = { | 274 | status.pressed = { |
| 277 | .value = input_engine->GetButton(identifier, button), | 275 | .value = input_engine->GetButton(identifier, button), |
| 278 | .inverted = inverted, | 276 | .inverted = inverted, |
| @@ -307,7 +305,6 @@ public: | |||
| 307 | 305 | ||
| 308 | private: | 306 | private: |
| 309 | const PadIdentifier identifier; | 307 | const PadIdentifier identifier; |
| 310 | const int touch_id; | ||
| 311 | const int button; | 308 | const int button; |
| 312 | const bool toggle; | 309 | const bool toggle; |
| 313 | const bool inverted; | 310 | const bool inverted; |
| @@ -919,7 +916,6 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTriggerDevice( | |||
| 919 | 916 | ||
| 920 | std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice( | 917 | std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice( |
| 921 | const Common::ParamPackage& params) { | 918 | const Common::ParamPackage& params) { |
| 922 | const auto touch_id = params.Get("touch_id", 0); | ||
| 923 | const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); | 919 | const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); |
| 924 | const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); | 920 | const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); |
| 925 | const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); | 921 | const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); |
| @@ -954,8 +950,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice( | |||
| 954 | input_engine->PreSetAxis(identifier, axis_x); | 950 | input_engine->PreSetAxis(identifier, axis_x); |
| 955 | input_engine->PreSetAxis(identifier, axis_y); | 951 | input_engine->PreSetAxis(identifier, axis_y); |
| 956 | input_engine->PreSetButton(identifier, button); | 952 | input_engine->PreSetButton(identifier, button); |
| 957 | return std::make_unique<InputFromTouch>(identifier, touch_id, button, toggle, inverted, axis_x, | 953 | return std::make_unique<InputFromTouch>(identifier, button, toggle, inverted, axis_x, axis_y, |
| 958 | axis_y, properties_x, properties_y, input_engine.get()); | 954 | properties_x, properties_y, input_engine.get()); |
| 959 | } | 955 | } |
| 960 | 956 | ||
| 961 | std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice( | 957 | std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice( |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 3b0176bf6..0cb1e193e 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -320,6 +320,7 @@ void SetupOptions(const IR::Program& program, const Profile& profile, | |||
| 320 | } | 320 | } |
| 321 | if (stage == Stage::Fragment) { | 321 | if (stage == Stage::Fragment) { |
| 322 | header += "OPTION ARB_draw_buffers;"; | 322 | header += "OPTION ARB_draw_buffers;"; |
| 323 | header += "OPTION ARB_fragment_layer_viewport;"; | ||
| 323 | } | 324 | } |
| 324 | } | 325 | } |
| 325 | 326 | ||
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index d6562c842..f0bd84ab2 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp | |||
| @@ -104,6 +104,9 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal | |||
| 104 | case IR::Attribute::PrimitiveId: | 104 | case IR::Attribute::PrimitiveId: |
| 105 | ctx.Add("MOV.F {}.x,primitive.id;", inst); | 105 | ctx.Add("MOV.F {}.x,primitive.id;", inst); |
| 106 | break; | 106 | break; |
| 107 | case IR::Attribute::Layer: | ||
| 108 | ctx.Add("MOV.F {}.x,fragment.layer;", inst); | ||
| 109 | break; | ||
| 107 | case IR::Attribute::PositionX: | 110 | case IR::Attribute::PositionX: |
| 108 | case IR::Attribute::PositionY: | 111 | case IR::Attribute::PositionY: |
| 109 | case IR::Attribute::PositionZ: | 112 | case IR::Attribute::PositionZ: |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index c1671c37b..39579cf5d 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp | |||
| @@ -205,6 +205,9 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, | |||
| 205 | case IR::Attribute::PrimitiveId: | 205 | case IR::Attribute::PrimitiveId: |
| 206 | ctx.AddF32("{}=itof(gl_PrimitiveID);", inst); | 206 | ctx.AddF32("{}=itof(gl_PrimitiveID);", inst); |
| 207 | break; | 207 | break; |
| 208 | case IR::Attribute::Layer: | ||
| 209 | ctx.AddF32("{}=itof(gl_Layer);", inst); | ||
| 210 | break; | ||
| 208 | case IR::Attribute::PositionX: | 211 | case IR::Attribute::PositionX: |
| 209 | case IR::Attribute::PositionY: | 212 | case IR::Attribute::PositionY: |
| 210 | case IR::Attribute::PositionZ: | 213 | case IR::Attribute::PositionZ: |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 5b3b5d1f3..01f6ec9b5 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | |||
| @@ -315,6 +315,8 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { | |||
| 315 | switch (attr) { | 315 | switch (attr) { |
| 316 | case IR::Attribute::PrimitiveId: | 316 | case IR::Attribute::PrimitiveId: |
| 317 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id)); | 317 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id)); |
| 318 | case IR::Attribute::Layer: | ||
| 319 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.layer)); | ||
| 318 | case IR::Attribute::PositionX: | 320 | case IR::Attribute::PositionX: |
| 319 | case IR::Attribute::PositionY: | 321 | case IR::Attribute::PositionY: |
| 320 | case IR::Attribute::PositionZ: | 322 | case IR::Attribute::PositionZ: |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 0bfc2dd89..8e3e40cd5 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -1359,6 +1359,11 @@ void EmitContext::DefineInputs(const IR::Program& program) { | |||
| 1359 | if (loads[IR::Attribute::PrimitiveId]) { | 1359 | if (loads[IR::Attribute::PrimitiveId]) { |
| 1360 | primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId); | 1360 | primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId); |
| 1361 | } | 1361 | } |
| 1362 | if (loads[IR::Attribute::Layer]) { | ||
| 1363 | AddCapability(spv::Capability::Geometry); | ||
| 1364 | layer = DefineInput(*this, U32[1], false, spv::BuiltIn::Layer); | ||
| 1365 | Decorate(layer, spv::Decoration::Flat); | ||
| 1366 | } | ||
| 1362 | if (loads.AnyComponent(IR::Attribute::PositionX)) { | 1367 | if (loads.AnyComponent(IR::Attribute::PositionX)) { |
| 1363 | const bool is_fragment{stage != Stage::Fragment}; | 1368 | const bool is_fragment{stage != Stage::Fragment}; |
| 1364 | const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; | 1369 | const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index d502d181c..5bb1427c1 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -232,7 +232,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume | |||
| 232 | use_topology_override = true; | 232 | use_topology_override = true; |
| 233 | return; | 233 | return; |
| 234 | case MAXWELL3D_REG_INDEX(clear_surface): | 234 | case MAXWELL3D_REG_INDEX(clear_surface): |
| 235 | return ProcessClearBuffers(); | 235 | return ProcessClearBuffers(1); |
| 236 | case MAXWELL3D_REG_INDEX(report_semaphore.query): | 236 | case MAXWELL3D_REG_INDEX(report_semaphore.query): |
| 237 | return ProcessQueryGet(); | 237 | return ProcessQueryGet(); |
| 238 | case MAXWELL3D_REG_INDEX(render_enable.mode): | 238 | case MAXWELL3D_REG_INDEX(render_enable.mode): |
| @@ -596,8 +596,8 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const { | |||
| 596 | return regs.reg_array[method]; | 596 | return regs.reg_array[method]; |
| 597 | } | 597 | } |
| 598 | 598 | ||
| 599 | void Maxwell3D::ProcessClearBuffers() { | 599 | void Maxwell3D::ProcessClearBuffers(u32 layer_count) { |
| 600 | rasterizer->Clear(); | 600 | rasterizer->Clear(layer_count); |
| 601 | } | 601 | } |
| 602 | 602 | ||
| 603 | void Maxwell3D::ProcessDraw(u32 instance_count) { | 603 | void Maxwell3D::ProcessDraw(u32 instance_count) { |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 34b085388..c3099f9a6 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -3086,6 +3086,9 @@ public: | |||
| 3086 | 3086 | ||
| 3087 | std::vector<u8> inline_index_draw_indexes; | 3087 | std::vector<u8> inline_index_draw_indexes; |
| 3088 | 3088 | ||
| 3089 | /// Handles a write to the CLEAR_BUFFERS register. | ||
| 3090 | void ProcessClearBuffers(u32 layer_count); | ||
| 3091 | |||
| 3089 | private: | 3092 | private: |
| 3090 | void InitializeRegisterDefaults(); | 3093 | void InitializeRegisterDefaults(); |
| 3091 | 3094 | ||
| @@ -3120,9 +3123,6 @@ private: | |||
| 3120 | /// Handles firmware blob 4 | 3123 | /// Handles firmware blob 4 |
| 3121 | void ProcessFirmwareCall4(); | 3124 | void ProcessFirmwareCall4(); |
| 3122 | 3125 | ||
| 3123 | /// Handles a write to the CLEAR_BUFFERS register. | ||
| 3124 | void ProcessClearBuffers(); | ||
| 3125 | |||
| 3126 | /// Handles a write to the QUERY_GET register. | 3126 | /// Handles a write to the QUERY_GET register. |
| 3127 | void ProcessQueryGet(); | 3127 | void ProcessQueryGet(); |
| 3128 | 3128 | ||
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 54523a4b2..1bf6ca2dd 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -314,6 +314,7 @@ void MaxwellDMA::ReleaseSemaphore() { | |||
| 314 | } | 314 | } |
| 315 | default: | 315 | default: |
| 316 | ASSERT_MSG(false, "Unknown semaphore type: {}", static_cast<u32>(type.Value())); | 316 | ASSERT_MSG(false, "Unknown semaphore type: {}", static_cast<u32>(type.Value())); |
| 317 | break; | ||
| 317 | } | 318 | } |
| 318 | } | 319 | } |
| 319 | 320 | ||
diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp index 3977bb0fb..4d2278811 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp | |||
| @@ -50,6 +50,7 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) { | |||
| 50 | break; | 50 | break; |
| 51 | default: | 51 | default: |
| 52 | UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id); | 52 | UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id); |
| 53 | break; | ||
| 53 | } | 54 | } |
| 54 | } | 55 | } |
| 55 | 56 | ||
| @@ -65,6 +66,7 @@ void Puller::ProcessFenceActionMethod() { | |||
| 65 | break; | 66 | break; |
| 66 | default: | 67 | default: |
| 67 | UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value()); | 68 | UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value()); |
| 69 | break; | ||
| 68 | } | 70 | } |
| 69 | } | 71 | } |
| 70 | 72 | ||
| @@ -228,6 +230,7 @@ void Puller::CallEngineMethod(const MethodCall& method_call) { | |||
| 228 | break; | 230 | break; |
| 229 | default: | 231 | default: |
| 230 | UNIMPLEMENTED_MSG("Unimplemented engine"); | 232 | UNIMPLEMENTED_MSG("Unimplemented engine"); |
| 233 | break; | ||
| 231 | } | 234 | } |
| 232 | } | 235 | } |
| 233 | 236 | ||
| @@ -254,6 +257,7 @@ void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_s | |||
| 254 | break; | 257 | break; |
| 255 | default: | 258 | default: |
| 256 | UNIMPLEMENTED_MSG("Unimplemented engine"); | 259 | UNIMPLEMENTED_MSG("Unimplemented engine"); |
| 260 | break; | ||
| 257 | } | 261 | } |
| 258 | } | 262 | } |
| 259 | 263 | ||
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index f896591bf..0f3262edb 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp | |||
| @@ -126,11 +126,25 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | constexpr std::array<std::pair<u64, HLEFunction>, 4> hle_funcs{{ | 129 | // Multi-layer Clear |
| 130 | void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | ||
| 131 | ASSERT(parameters.size() == 1); | ||
| 132 | |||
| 133 | const Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; | ||
| 134 | const u32 rt_index = clear_params.RT; | ||
| 135 | const u32 num_layers = maxwell3d.regs.rt[rt_index].depth; | ||
| 136 | ASSERT(clear_params.layer == 0); | ||
| 137 | |||
| 138 | maxwell3d.regs.clear_surface.raw = clear_params.raw; | ||
| 139 | maxwell3d.ProcessClearBuffers(num_layers); | ||
| 140 | } | ||
| 141 | |||
| 142 | constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{ | ||
| 130 | {0x771BB18C62444DA0, &HLE_771BB18C62444DA0}, | 143 | {0x771BB18C62444DA0, &HLE_771BB18C62444DA0}, |
| 131 | {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD}, | 144 | {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD}, |
| 132 | {0x0217920100488FF7, &HLE_0217920100488FF7}, | 145 | {0x0217920100488FF7, &HLE_0217920100488FF7}, |
| 133 | {0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164}, | 146 | {0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164}, |
| 147 | {0xEAD26C3E2109B06B, &HLE_EAD26C3E2109B06B}, | ||
| 134 | }}; | 148 | }}; |
| 135 | 149 | ||
| 136 | class HLEMacroImpl final : public CachedMacro { | 150 | class HLEMacroImpl final : public CachedMacro { |
diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp index c0d32c112..0d63495a9 100644 --- a/src/video_core/macro/macro_interpreter.cpp +++ b/src/video_core/macro/macro_interpreter.cpp | |||
| @@ -201,6 +201,7 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) { | |||
| 201 | } | 201 | } |
| 202 | default: | 202 | default: |
| 203 | UNIMPLEMENTED_MSG("Unimplemented macro operation {}", opcode.operation.Value()); | 203 | UNIMPLEMENTED_MSG("Unimplemented macro operation {}", opcode.operation.Value()); |
| 204 | break; | ||
| 204 | } | 205 | } |
| 205 | 206 | ||
| 206 | // An instruction with the Exit flag will not actually | 207 | // An instruction with the Exit flag will not actually |
| @@ -297,6 +298,7 @@ void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 r | |||
| 297 | break; | 298 | break; |
| 298 | default: | 299 | default: |
| 299 | UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation); | 300 | UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation); |
| 301 | break; | ||
| 300 | } | 302 | } |
| 301 | } | 303 | } |
| 302 | 304 | ||
diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index 25c1ce798..7347cbd88 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp | |||
| @@ -652,6 +652,7 @@ void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u3 | |||
| 652 | break; | 652 | break; |
| 653 | default: | 653 | default: |
| 654 | UNIMPLEMENTED_MSG("Unimplemented macro operation {}", operation); | 654 | UNIMPLEMENTED_MSG("Unimplemented macro operation {}", operation); |
| 655 | break; | ||
| 655 | } | 656 | } |
| 656 | } | 657 | } |
| 657 | 658 | ||
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 1cbfef090..cfd872a40 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -43,7 +43,7 @@ public: | |||
| 43 | virtual void Draw(bool is_indexed, u32 instance_count) = 0; | 43 | virtual void Draw(bool is_indexed, u32 instance_count) = 0; |
| 44 | 44 | ||
| 45 | /// Clear the current framebuffer | 45 | /// Clear the current framebuffer |
| 46 | virtual void Clear() = 0; | 46 | virtual void Clear(u32 layer_count) = 0; |
| 47 | 47 | ||
| 48 | /// Dispatches a compute shader invocation | 48 | /// Dispatches a compute shader invocation |
| 49 | virtual void DispatchCompute() = 0; | 49 | virtual void DispatchCompute() = 0; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d05a5f60b..115a5e010 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -136,7 +136,7 @@ void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_load | |||
| 136 | shader_cache.LoadDiskResources(title_id, stop_loading, callback); | 136 | shader_cache.LoadDiskResources(title_id, stop_loading, callback); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | void RasterizerOpenGL::Clear() { | 139 | void RasterizerOpenGL::Clear(u32 layer_count) { |
| 140 | MICROPROFILE_SCOPE(OpenGL_Clears); | 140 | MICROPROFILE_SCOPE(OpenGL_Clears); |
| 141 | if (!maxwell3d->ShouldExecute()) { | 141 | if (!maxwell3d->ShouldExecute()) { |
| 142 | return; | 142 | return; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 793e0d608..449a14f12 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -69,7 +69,7 @@ public: | |||
| 69 | ~RasterizerOpenGL() override; | 69 | ~RasterizerOpenGL() override; |
| 70 | 70 | ||
| 71 | void Draw(bool is_indexed, u32 instance_count) override; | 71 | void Draw(bool is_indexed, u32 instance_count) override; |
| 72 | void Clear() override; | 72 | void Clear(u32 layer_count) override; |
| 73 | void DispatchCompute() override; | 73 | void DispatchCompute() override; |
| 74 | void ResetCounter(VideoCore::QueryType type) override; | 74 | void ResetCounter(VideoCore::QueryType type) override; |
| 75 | void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; | 75 | void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 99cd11d1e..9f7ce7414 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -891,6 +891,7 @@ void Image::CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t b | |||
| 891 | break; | 891 | break; |
| 892 | default: | 892 | default: |
| 893 | ASSERT(false); | 893 | ASSERT(false); |
| 894 | break; | ||
| 894 | } | 895 | } |
| 895 | } | 896 | } |
| 896 | 897 | ||
| @@ -927,6 +928,7 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b | |||
| 927 | break; | 928 | break; |
| 928 | default: | 929 | default: |
| 929 | ASSERT(false); | 930 | ASSERT(false); |
| 931 | break; | ||
| 930 | } | 932 | } |
| 931 | // Compressed formats don't have a pixel format or type | 933 | // Compressed formats don't have a pixel format or type |
| 932 | const bool is_compressed = gl_format == GL_NONE; | 934 | const bool is_compressed = gl_format == GL_NONE; |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 8bd5eba7e..f29462f7c 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -340,6 +340,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | |||
| 340 | texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | 340 | texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; |
| 341 | // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", | 341 | // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", |
| 342 | // static_cast<u32>(framebuffer.pixel_format)); | 342 | // static_cast<u32>(framebuffer.pixel_format)); |
| 343 | break; | ||
| 343 | } | 344 | } |
| 344 | 345 | ||
| 345 | texture.resource.Release(); | 346 | texture.resource.Release(); |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d8131232a..c2a95200b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -172,6 +172,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | void RendererVulkan::Report() const { | 174 | void RendererVulkan::Report() const { |
| 175 | using namespace Common::Literals; | ||
| 175 | const std::string vendor_name{device.GetVendorName()}; | 176 | const std::string vendor_name{device.GetVendorName()}; |
| 176 | const std::string model_name{device.GetModelName()}; | 177 | const std::string model_name{device.GetModelName()}; |
| 177 | const std::string driver_version = GetDriverVersion(device); | 178 | const std::string driver_version = GetDriverVersion(device); |
| @@ -181,9 +182,12 @@ void RendererVulkan::Report() const { | |||
| 181 | 182 | ||
| 182 | const std::string extensions = BuildCommaSeparatedExtensions(device.GetAvailableExtensions()); | 183 | const std::string extensions = BuildCommaSeparatedExtensions(device.GetAvailableExtensions()); |
| 183 | 184 | ||
| 185 | const auto available_vram = static_cast<f64>(device.GetDeviceLocalMemory()) / f64{1_GiB}; | ||
| 186 | |||
| 184 | LOG_INFO(Render_Vulkan, "Driver: {}", driver_name); | 187 | LOG_INFO(Render_Vulkan, "Driver: {}", driver_name); |
| 185 | LOG_INFO(Render_Vulkan, "Device: {}", model_name); | 188 | LOG_INFO(Render_Vulkan, "Device: {}", model_name); |
| 186 | LOG_INFO(Render_Vulkan, "Vulkan: {}", api_version); | 189 | LOG_INFO(Render_Vulkan, "Vulkan: {}", api_version); |
| 190 | LOG_INFO(Render_Vulkan, "Available VRAM: {:.2f} GiB", available_vram); | ||
| 187 | 191 | ||
| 188 | static constexpr auto field = Common::Telemetry::FieldType::UserSystem; | 192 | static constexpr auto field = Common::Telemetry::FieldType::UserSystem; |
| 189 | telemetry_session.AddField(field, "GPU_Vendor", vendor_name); | 193 | telemetry_session.AddField(field, "GPU_Vendor", vendor_name); |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f69c0c50f..67b88621a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -213,7 +213,7 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { | |||
| 213 | EndTransformFeedback(); | 213 | EndTransformFeedback(); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | void RasterizerVulkan::Clear() { | 216 | void RasterizerVulkan::Clear(u32 layer_count) { |
| 217 | MICROPROFILE_SCOPE(Vulkan_Clearing); | 217 | MICROPROFILE_SCOPE(Vulkan_Clearing); |
| 218 | 218 | ||
| 219 | if (!maxwell3d->ShouldExecute()) { | 219 | if (!maxwell3d->ShouldExecute()) { |
| @@ -256,7 +256,7 @@ void RasterizerVulkan::Clear() { | |||
| 256 | .rect = regs.clear_control.use_scissor ? GetScissorState(regs, 0, up_scale, down_shift) | 256 | .rect = regs.clear_control.use_scissor ? GetScissorState(regs, 0, up_scale, down_shift) |
| 257 | : default_scissor, | 257 | : default_scissor, |
| 258 | .baseArrayLayer = regs.clear_surface.layer, | 258 | .baseArrayLayer = regs.clear_surface.layer, |
| 259 | .layerCount = 1, | 259 | .layerCount = layer_count, |
| 260 | }; | 260 | }; |
| 261 | if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) { | 261 | if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) { |
| 262 | return; | 262 | return; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index b0bc306f5..70f36d58a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -65,7 +65,7 @@ public: | |||
| 65 | ~RasterizerVulkan() override; | 65 | ~RasterizerVulkan() override; |
| 66 | 66 | ||
| 67 | void Draw(bool is_indexed, u32 instance_count) override; | 67 | void Draw(bool is_indexed, u32 instance_count) override; |
| 68 | void Clear() override; | 68 | void Clear(u32 layer_count) override; |
| 69 | void DispatchCompute() override; | 69 | void DispatchCompute() override; |
| 70 | void ResetCounter(VideoCore::QueryType type) override; | 70 | void ResetCounter(VideoCore::QueryType type) override; |
| 71 | void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; | 71 | void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 7934f2a51..4a7b633b7 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp | |||
| @@ -221,6 +221,7 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s | |||
| 221 | [[fallthrough]]; | 221 | [[fallthrough]]; |
| 222 | default: | 222 | default: |
| 223 | vk::Check(result); | 223 | vk::Check(result); |
| 224 | break; | ||
| 224 | } | 225 | } |
| 225 | }); | 226 | }); |
| 226 | chunk->MarkSubmit(); | 227 | chunk->MarkSubmit(); |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 853b80d8a..a65bbeb1c 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -108,6 +108,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 108 | break; | 108 | break; |
| 109 | default: | 109 | default: |
| 110 | ASSERT_MSG(false, "Invalid surface type"); | 110 | ASSERT_MSG(false, "Invalid surface type"); |
| 111 | break; | ||
| 111 | } | 112 | } |
| 112 | } | 113 | } |
| 113 | if (info.storage) { | 114 | if (info.storage) { |
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index fd1a4b987..59120cd09 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -170,6 +170,7 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe | |||
| 170 | #undef BPP_CASE | 170 | #undef BPP_CASE |
| 171 | default: | 171 | default: |
| 172 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); | 172 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); |
| 173 | break; | ||
| 173 | } | 174 | } |
| 174 | } | 175 | } |
| 175 | 176 | ||
| @@ -217,6 +218,7 @@ void SwizzleSubrect(std::span<u8> output, std::span<const u8> input, u32 bytes_p | |||
| 217 | #undef BPP_CASE | 218 | #undef BPP_CASE |
| 218 | default: | 219 | default: |
| 219 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); | 220 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); |
| 221 | break; | ||
| 220 | } | 222 | } |
| 221 | } | 223 | } |
| 222 | 224 | ||
| @@ -240,6 +242,7 @@ void UnswizzleSubrect(std::span<u8> output, std::span<const u8> input, u32 bytes | |||
| 240 | #undef BPP_CASE | 242 | #undef BPP_CASE |
| 241 | default: | 243 | default: |
| 242 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); | 244 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); |
| 245 | break; | ||
| 243 | } | 246 | } |
| 244 | } | 247 | } |
| 245 | 248 | ||
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 5cc1fbf32..adad36221 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -18,6 +18,9 @@ add_executable(yuzu | |||
| 18 | about_dialog.cpp | 18 | about_dialog.cpp |
| 19 | about_dialog.h | 19 | about_dialog.h |
| 20 | aboutdialog.ui | 20 | aboutdialog.ui |
| 21 | applets/qt_amiibo_settings.cpp | ||
| 22 | applets/qt_amiibo_settings.h | ||
| 23 | applets/qt_amiibo_settings.ui | ||
| 21 | applets/qt_controller.cpp | 24 | applets/qt_controller.cpp |
| 22 | applets/qt_controller.h | 25 | applets/qt_controller.h |
| 23 | applets/qt_controller.ui | 26 | applets/qt_controller.ui |
diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp new file mode 100644 index 000000000..efb7f6ecc --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_settings.cpp | |||
| @@ -0,0 +1,260 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <thread> | ||
| 6 | #include <fmt/format.h> | ||
| 7 | #include <nlohmann/json.hpp> | ||
| 8 | |||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/string_util.h" | ||
| 11 | #include "core/hle/service/nfp/nfp_device.h" | ||
| 12 | #include "core/hle/service/nfp/nfp_result.h" | ||
| 13 | #include "input_common/drivers/virtual_amiibo.h" | ||
| 14 | #include "input_common/main.h" | ||
| 15 | #include "ui_qt_amiibo_settings.h" | ||
| 16 | #include "web_service/web_backend.h" | ||
| 17 | #include "yuzu/applets/qt_amiibo_settings.h" | ||
| 18 | #include "yuzu/main.h" | ||
| 19 | |||
| 20 | QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent, | ||
| 21 | Core::Frontend::CabinetParameters parameters_, | ||
| 22 | InputCommon::InputSubsystem* input_subsystem_, | ||
| 23 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device_) | ||
| 24 | : QDialog(parent), ui(std::make_unique<Ui::QtAmiiboSettingsDialog>()), | ||
| 25 | input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)}, | ||
| 26 | parameters(std::move(parameters_)) { | ||
| 27 | ui->setupUi(this); | ||
| 28 | |||
| 29 | LoadInfo(); | ||
| 30 | |||
| 31 | resize(0, 0); | ||
| 32 | } | ||
| 33 | |||
| 34 | QtAmiiboSettingsDialog::~QtAmiiboSettingsDialog() = default; | ||
| 35 | |||
| 36 | int QtAmiiboSettingsDialog::exec() { | ||
| 37 | if (!is_initalized) { | ||
| 38 | return QDialog::Rejected; | ||
| 39 | } | ||
| 40 | return QDialog::exec(); | ||
| 41 | } | ||
| 42 | |||
| 43 | std::string QtAmiiboSettingsDialog::GetName() const { | ||
| 44 | return ui->amiiboCustomNameValue->text().toStdString(); | ||
| 45 | } | ||
| 46 | |||
| 47 | void QtAmiiboSettingsDialog::LoadInfo() { | ||
| 48 | if (input_subsystem->GetVirtualAmiibo()->ReloadAmiibo() != | ||
| 49 | InputCommon::VirtualAmiibo::Info::Success) { | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | |||
| 53 | if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && | ||
| 54 | nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | nfp_device->Mount(Service::NFP::MountTarget::All); | ||
| 58 | |||
| 59 | LoadAmiiboInfo(); | ||
| 60 | LoadAmiiboData(); | ||
| 61 | LoadAmiiboGameInfo(); | ||
| 62 | |||
| 63 | ui->amiiboDirectoryValue->setText( | ||
| 64 | QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath())); | ||
| 65 | |||
| 66 | SetSettingsDescription(); | ||
| 67 | is_initalized = true; | ||
| 68 | } | ||
| 69 | |||
| 70 | void QtAmiiboSettingsDialog::LoadAmiiboInfo() { | ||
| 71 | Service::NFP::ModelInfo model_info{}; | ||
| 72 | const auto model_result = nfp_device->GetModelInfo(model_info); | ||
| 73 | |||
| 74 | if (model_result.IsFailure()) { | ||
| 75 | ui->amiiboImageLabel->setVisible(false); | ||
| 76 | ui->amiiboInfoGroup->setVisible(false); | ||
| 77 | return; | ||
| 78 | } | ||
| 79 | |||
| 80 | const auto amiibo_id = | ||
| 81 | fmt::format("{:04x}{:02x}{:02x}{:04x}{:02x}02", Common::swap16(model_info.character_id), | ||
| 82 | model_info.character_variant, model_info.amiibo_type, model_info.model_number, | ||
| 83 | model_info.series); | ||
| 84 | |||
| 85 | LOG_DEBUG(Frontend, "Loading amiibo id {}", amiibo_id); | ||
| 86 | // Note: This function is not being used until we host the images on our server | ||
| 87 | // LoadAmiiboApiInfo(amiibo_id); | ||
| 88 | ui->amiiboImageLabel->setVisible(false); | ||
| 89 | ui->amiiboInfoGroup->setVisible(false); | ||
| 90 | } | ||
| 91 | |||
| 92 | void QtAmiiboSettingsDialog::LoadAmiiboApiInfo(std::string_view amiibo_id) { | ||
| 93 | // TODO: Host this data on our website | ||
| 94 | WebService::Client client{"https://amiiboapi.com", {}, {}}; | ||
| 95 | WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}}; | ||
| 96 | const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id); | ||
| 97 | |||
| 98 | const auto amiibo_json = client.GetJson(url_path, true).returned_data; | ||
| 99 | if (amiibo_json.empty()) { | ||
| 100 | ui->amiiboImageLabel->setVisible(false); | ||
| 101 | ui->amiiboInfoGroup->setVisible(false); | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | std::string amiibo_series{}; | ||
| 106 | std::string amiibo_name{}; | ||
| 107 | std::string amiibo_image_url{}; | ||
| 108 | std::string amiibo_type{}; | ||
| 109 | |||
| 110 | const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo"); | ||
| 111 | parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series); | ||
| 112 | parsed_amiibo_json_json.at("name").get_to(amiibo_name); | ||
| 113 | parsed_amiibo_json_json.at("image").get_to(amiibo_image_url); | ||
| 114 | parsed_amiibo_json_json.at("type").get_to(amiibo_type); | ||
| 115 | |||
| 116 | ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series)); | ||
| 117 | ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name)); | ||
| 118 | ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type)); | ||
| 119 | |||
| 120 | if (amiibo_image_url.size() < 34) { | ||
| 121 | ui->amiiboImageLabel->setVisible(false); | ||
| 122 | } | ||
| 123 | |||
| 124 | const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34); | ||
| 125 | const auto image_data = image_client.GetImage(image_url_path, true).returned_data; | ||
| 126 | |||
| 127 | if (image_data.empty()) { | ||
| 128 | ui->amiiboImageLabel->setVisible(false); | ||
| 129 | } | ||
| 130 | |||
| 131 | QPixmap pixmap; | ||
| 132 | pixmap.loadFromData(reinterpret_cast<const u8*>(image_data.data()), | ||
| 133 | static_cast<uint>(image_data.size())); | ||
| 134 | pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio, | ||
| 135 | Qt::TransformationMode::SmoothTransformation); | ||
| 136 | ui->amiiboImageLabel->setPixmap(pixmap); | ||
| 137 | } | ||
| 138 | |||
| 139 | void QtAmiiboSettingsDialog::LoadAmiiboData() { | ||
| 140 | Service::NFP::RegisterInfo register_info{}; | ||
| 141 | Service::NFP::CommonInfo common_info{}; | ||
| 142 | const auto register_result = nfp_device->GetRegisterInfo(register_info); | ||
| 143 | const auto common_result = nfp_device->GetCommonInfo(common_info); | ||
| 144 | |||
| 145 | if (register_result.IsFailure()) { | ||
| 146 | ui->creationDateValue->setDisabled(true); | ||
| 147 | ui->modificationDateValue->setDisabled(true); | ||
| 148 | ui->amiiboCustomNameValue->setReadOnly(false); | ||
| 149 | ui->amiiboOwnerValue->setReadOnly(false); | ||
| 150 | return; | ||
| 151 | } | ||
| 152 | |||
| 153 | if (parameters.mode == Service::NFP::CabinetMode::StartNicknameAndOwnerSettings) { | ||
| 154 | ui->creationDateValue->setDisabled(true); | ||
| 155 | ui->modificationDateValue->setDisabled(true); | ||
| 156 | } | ||
| 157 | |||
| 158 | const auto amiibo_name = std::string(register_info.amiibo_name.data()); | ||
| 159 | const auto owner_name = Common::UTF16ToUTF8(register_info.mii_char_info.name.data()); | ||
| 160 | const auto creation_date = | ||
| 161 | QDate(register_info.creation_date.year, register_info.creation_date.month, | ||
| 162 | register_info.creation_date.day); | ||
| 163 | |||
| 164 | ui->amiiboCustomNameValue->setText(QString::fromStdString(amiibo_name)); | ||
| 165 | ui->amiiboOwnerValue->setText(QString::fromStdString(owner_name)); | ||
| 166 | ui->amiiboCustomNameValue->setReadOnly(true); | ||
| 167 | ui->amiiboOwnerValue->setReadOnly(true); | ||
| 168 | ui->creationDateValue->setDate(creation_date); | ||
| 169 | |||
| 170 | if (common_result.IsFailure()) { | ||
| 171 | ui->modificationDateValue->setDisabled(true); | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | |||
| 175 | const auto modification_date = | ||
| 176 | QDate(common_info.last_write_date.year, common_info.last_write_date.month, | ||
| 177 | common_info.last_write_date.day); | ||
| 178 | ui->modificationDateValue->setDate(modification_date); | ||
| 179 | } | ||
| 180 | |||
| 181 | void QtAmiiboSettingsDialog::LoadAmiiboGameInfo() { | ||
| 182 | u32 application_area_id{}; | ||
| 183 | const auto application_result = nfp_device->GetApplicationAreaId(application_area_id); | ||
| 184 | |||
| 185 | if (application_result.IsFailure()) { | ||
| 186 | ui->gameIdValue->setVisible(false); | ||
| 187 | ui->gameIdLabel->setText(tr("No game data present")); | ||
| 188 | return; | ||
| 189 | } | ||
| 190 | |||
| 191 | SetGameDataName(application_area_id); | ||
| 192 | } | ||
| 193 | |||
| 194 | void QtAmiiboSettingsDialog::SetGameDataName(u32 application_area_id) { | ||
| 195 | static constexpr std::array<std::pair<u32, const char*>, 12> game_name_list = { | ||
| 196 | // 3ds, wii u | ||
| 197 | std::pair<u32, const char*>{0x10110E00, "Super Smash Bros (3DS/WiiU)"}, | ||
| 198 | {0x00132600, "Mario & Luigi: Paper Jam"}, | ||
| 199 | {0x0014F000, "Animal Crossing: Happy Home Designer"}, | ||
| 200 | {0x00152600, "Chibi-Robo!: Zip Lash"}, | ||
| 201 | {0x10161f00, "Mario Party 10"}, | ||
| 202 | {0x1019C800, "The Legend of Zelda: Twilight Princess HD"}, | ||
| 203 | // switch | ||
| 204 | {0x10162B00, "Splatoon 2"}, | ||
| 205 | {0x1016e100, "Shovel Knight: Treasure Trove"}, | ||
| 206 | {0x1019C800, "The Legend of Zelda: Breath of the Wild"}, | ||
| 207 | {0x34F80200, "Super Smash Bros. Ultimate"}, | ||
| 208 | {0x38600500, "Splatoon 3"}, | ||
| 209 | {0x3B440400, "The Legend of Zelda: Link's Awakening"}, | ||
| 210 | }; | ||
| 211 | |||
| 212 | for (const auto& [game_id, game_name] : game_name_list) { | ||
| 213 | if (application_area_id == game_id) { | ||
| 214 | ui->gameIdValue->setText(QString::fromStdString(game_name)); | ||
| 215 | return; | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | const auto application_area_string = fmt::format("{:016x}", application_area_id); | ||
| 220 | ui->gameIdValue->setText(QString::fromStdString(application_area_string)); | ||
| 221 | } | ||
| 222 | |||
| 223 | void QtAmiiboSettingsDialog::SetSettingsDescription() { | ||
| 224 | switch (parameters.mode) { | ||
| 225 | case Service::NFP::CabinetMode::StartFormatter: | ||
| 226 | ui->cabinetActionDescriptionLabel->setText( | ||
| 227 | tr("The following amiibo data will be formatted:")); | ||
| 228 | break; | ||
| 229 | case Service::NFP::CabinetMode::StartGameDataEraser: | ||
| 230 | ui->cabinetActionDescriptionLabel->setText(tr("The following game data will removed:")); | ||
| 231 | break; | ||
| 232 | case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: | ||
| 233 | ui->cabinetActionDescriptionLabel->setText(tr("Set nickname and owner:")); | ||
| 234 | break; | ||
| 235 | case Service::NFP::CabinetMode::StartRestorer: | ||
| 236 | ui->cabinetActionDescriptionLabel->setText(tr("Do you wish to restore this amiibo?")); | ||
| 237 | break; | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) { | ||
| 242 | connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent, | ||
| 243 | &GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection); | ||
| 244 | connect(&parent, &GMainWindow::AmiiboSettingsFinished, this, | ||
| 245 | &QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection); | ||
| 246 | } | ||
| 247 | |||
| 248 | QtAmiiboSettings::~QtAmiiboSettings() = default; | ||
| 249 | |||
| 250 | void QtAmiiboSettings::ShowCabinetApplet( | ||
| 251 | const Core::Frontend::CabinetCallback& callback_, | ||
| 252 | const Core::Frontend::CabinetParameters& parameters, | ||
| 253 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { | ||
| 254 | callback = std::move(callback_); | ||
| 255 | emit MainWindowShowAmiiboSettings(parameters, nfp_device); | ||
| 256 | } | ||
| 257 | |||
| 258 | void QtAmiiboSettings::MainWindowFinished(bool is_success, const std::string& name) { | ||
| 259 | callback(is_success, name); | ||
| 260 | } | ||
diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h new file mode 100644 index 000000000..930c96739 --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_settings.h | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <memory> | ||
| 8 | #include <QDialog> | ||
| 9 | #include "core/frontend/applets/cabinet.h" | ||
| 10 | |||
| 11 | class GMainWindow; | ||
| 12 | class QCheckBox; | ||
| 13 | class QComboBox; | ||
| 14 | class QDialogButtonBox; | ||
| 15 | class QGroupBox; | ||
| 16 | class QLabel; | ||
| 17 | |||
| 18 | namespace InputCommon { | ||
| 19 | class InputSubsystem; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Ui { | ||
| 23 | class QtAmiiboSettingsDialog; | ||
| 24 | } | ||
| 25 | |||
| 26 | namespace Service::NFP { | ||
| 27 | class NfpDevice; | ||
| 28 | } // namespace Service::NFP | ||
| 29 | |||
| 30 | class QtAmiiboSettingsDialog final : public QDialog { | ||
| 31 | Q_OBJECT | ||
| 32 | |||
| 33 | public: | ||
| 34 | explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_, | ||
| 35 | InputCommon::InputSubsystem* input_subsystem_, | ||
| 36 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device_); | ||
| 37 | ~QtAmiiboSettingsDialog() override; | ||
| 38 | |||
| 39 | int exec() override; | ||
| 40 | |||
| 41 | std::string GetName() const; | ||
| 42 | |||
| 43 | private: | ||
| 44 | void LoadInfo(); | ||
| 45 | void LoadAmiiboInfo(); | ||
| 46 | void LoadAmiiboApiInfo(std::string_view amiibo_id); | ||
| 47 | void LoadAmiiboData(); | ||
| 48 | void LoadAmiiboGameInfo(); | ||
| 49 | void SetGameDataName(u32 application_area_id); | ||
| 50 | void SetSettingsDescription(); | ||
| 51 | |||
| 52 | std::unique_ptr<Ui::QtAmiiboSettingsDialog> ui; | ||
| 53 | |||
| 54 | InputCommon::InputSubsystem* input_subsystem; | ||
| 55 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device; | ||
| 56 | |||
| 57 | // Parameters sent in from the backend HLE applet. | ||
| 58 | Core::Frontend::CabinetParameters parameters; | ||
| 59 | |||
| 60 | // If false amiibo settings failed to load | ||
| 61 | bool is_initalized{}; | ||
| 62 | }; | ||
| 63 | |||
| 64 | class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApplet { | ||
| 65 | Q_OBJECT | ||
| 66 | |||
| 67 | public: | ||
| 68 | explicit QtAmiiboSettings(GMainWindow& parent); | ||
| 69 | ~QtAmiiboSettings() override; | ||
| 70 | |||
| 71 | void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_, | ||
| 72 | const Core::Frontend::CabinetParameters& parameters, | ||
| 73 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; | ||
| 74 | |||
| 75 | signals: | ||
| 76 | void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters, | ||
| 77 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const; | ||
| 78 | |||
| 79 | private: | ||
| 80 | void MainWindowFinished(bool is_success, const std::string& name); | ||
| 81 | |||
| 82 | mutable Core::Frontend::CabinetCallback callback; | ||
| 83 | }; | ||
diff --git a/src/yuzu/applets/qt_amiibo_settings.ui b/src/yuzu/applets/qt_amiibo_settings.ui new file mode 100644 index 000000000..f377a6e61 --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_settings.ui | |||
| @@ -0,0 +1,494 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>QtAmiiboSettingsDialog</class> | ||
| 4 | <widget class="QDialog" name="QtAmiiboSettingsDialog"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>839</width> | ||
| 10 | <height>500</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Amiibo Settings</string> | ||
| 15 | </property> | ||
| 16 | <property name="styleSheet"> | ||
| 17 | <string notr="true"/> | ||
| 18 | </property> | ||
| 19 | <layout class="QVBoxLayout" name="verticalLayout" stretch="0"> | ||
| 20 | <property name="leftMargin"> | ||
| 21 | <number>0</number> | ||
| 22 | </property> | ||
| 23 | <property name="topMargin"> | ||
| 24 | <number>0</number> | ||
| 25 | </property> | ||
| 26 | <property name="rightMargin"> | ||
| 27 | <number>0</number> | ||
| 28 | </property> | ||
| 29 | <property name="bottomMargin"> | ||
| 30 | <number>0</number> | ||
| 31 | </property> | ||
| 32 | <item> | ||
| 33 | <widget class="QWidget" name="mainControllerApplet" native="true"> | ||
| 34 | <layout class="QVBoxLayout" name="verticalLayout_1" stretch="0,3,0"> | ||
| 35 | <property name="spacing"> | ||
| 36 | <number>0</number> | ||
| 37 | </property> | ||
| 38 | <property name="leftMargin"> | ||
| 39 | <number>0</number> | ||
| 40 | </property> | ||
| 41 | <property name="topMargin"> | ||
| 42 | <number>0</number> | ||
| 43 | </property> | ||
| 44 | <property name="rightMargin"> | ||
| 45 | <number>0</number> | ||
| 46 | </property> | ||
| 47 | <property name="bottomMargin"> | ||
| 48 | <number>0</number> | ||
| 49 | </property> | ||
| 50 | <item> | ||
| 51 | <widget class="QWidget" name="topControllerApplet" native="true"> | ||
| 52 | <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| 53 | <property name="spacing"> | ||
| 54 | <number>10</number> | ||
| 55 | </property> | ||
| 56 | <property name="leftMargin"> | ||
| 57 | <number>20</number> | ||
| 58 | </property> | ||
| 59 | <property name="topMargin"> | ||
| 60 | <number>15</number> | ||
| 61 | </property> | ||
| 62 | <property name="rightMargin"> | ||
| 63 | <number>0</number> | ||
| 64 | </property> | ||
| 65 | <property name="bottomMargin"> | ||
| 66 | <number>15</number> | ||
| 67 | </property> | ||
| 68 | <item> | ||
| 69 | <widget class="QLabel" name="cabinetActionDescriptionLabel"> | ||
| 70 | <property name="font"> | ||
| 71 | <font> | ||
| 72 | <pointsize>12</pointsize> | ||
| 73 | <weight>75</weight> | ||
| 74 | <bold>true</bold> | ||
| 75 | </font> | ||
| 76 | </property> | ||
| 77 | <property name="text"> | ||
| 78 | <string/> | ||
| 79 | </property> | ||
| 80 | <property name="alignment"> | ||
| 81 | <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> | ||
| 82 | </property> | ||
| 83 | <property name="wordWrap"> | ||
| 84 | <bool>false</bool> | ||
| 85 | </property> | ||
| 86 | </widget> | ||
| 87 | </item> | ||
| 88 | <item> | ||
| 89 | <spacer name="horizontalSpacer_2"> | ||
| 90 | <property name="orientation"> | ||
| 91 | <enum>Qt::Horizontal</enum> | ||
| 92 | </property> | ||
| 93 | <property name="sizeHint" stdset="0"> | ||
| 94 | <size> | ||
| 95 | <width>40</width> | ||
| 96 | <height>20</height> | ||
| 97 | </size> | ||
| 98 | </property> | ||
| 99 | </spacer> | ||
| 100 | </item> | ||
| 101 | </layout> | ||
| 102 | </widget> | ||
| 103 | </item> | ||
| 104 | <item> | ||
| 105 | <widget class="QWidget" name="middleControllerApplet" native="true"> | ||
| 106 | <layout class="QVBoxLayout" name="verticalLayout_3"> | ||
| 107 | <property name="spacing"> | ||
| 108 | <number>0</number> | ||
| 109 | </property> | ||
| 110 | <property name="leftMargin"> | ||
| 111 | <number>0</number> | ||
| 112 | </property> | ||
| 113 | <property name="topMargin"> | ||
| 114 | <number>0</number> | ||
| 115 | </property> | ||
| 116 | <property name="rightMargin"> | ||
| 117 | <number>0</number> | ||
| 118 | </property> | ||
| 119 | <property name="bottomMargin"> | ||
| 120 | <number>0</number> | ||
| 121 | </property> | ||
| 122 | <item> | ||
| 123 | <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||
| 124 | <property name="spacing"> | ||
| 125 | <number>20</number> | ||
| 126 | </property> | ||
| 127 | <property name="leftMargin"> | ||
| 128 | <number>15</number> | ||
| 129 | </property> | ||
| 130 | <property name="rightMargin"> | ||
| 131 | <number>15</number> | ||
| 132 | </property> | ||
| 133 | <item> | ||
| 134 | <widget class="QLabel" name="amiiboImageLabel"> | ||
| 135 | <property name="minimumSize"> | ||
| 136 | <size> | ||
| 137 | <width>250</width> | ||
| 138 | <height>350</height> | ||
| 139 | </size> | ||
| 140 | </property> | ||
| 141 | <property name="maximumSize"> | ||
| 142 | <size> | ||
| 143 | <width>236</width> | ||
| 144 | <height>350</height> | ||
| 145 | </size> | ||
| 146 | </property> | ||
| 147 | <property name="text"> | ||
| 148 | <string/> | ||
| 149 | </property> | ||
| 150 | <property name="alignment"> | ||
| 151 | <set>Qt::AlignCenter</set> | ||
| 152 | </property> | ||
| 153 | </widget> | ||
| 154 | </item> | ||
| 155 | <item> | ||
| 156 | <layout class="QVBoxLayout" name="verticalLayout_4"> | ||
| 157 | <property name="leftMargin"> | ||
| 158 | <number>0</number> | ||
| 159 | </property> | ||
| 160 | <property name="topMargin"> | ||
| 161 | <number>8</number> | ||
| 162 | </property> | ||
| 163 | <property name="bottomMargin"> | ||
| 164 | <number>15</number> | ||
| 165 | </property> | ||
| 166 | <item> | ||
| 167 | <widget class="QGroupBox" name="amiiboInfoGroup"> | ||
| 168 | <property name="title"> | ||
| 169 | <string>Amiibo Info</string> | ||
| 170 | </property> | ||
| 171 | <layout class="QVBoxLayout" name="verticalLayout_5"> | ||
| 172 | <item> | ||
| 173 | <layout class="QGridLayout" name="gridLayout_1"> | ||
| 174 | <item row="0" column="0"> | ||
| 175 | <widget class="QLabel" name="amiiboSeriesLabel"> | ||
| 176 | <property name="text"> | ||
| 177 | <string>Series</string> | ||
| 178 | </property> | ||
| 179 | </widget> | ||
| 180 | </item> | ||
| 181 | <item row="0" column="1"> | ||
| 182 | <widget class="QLineEdit" name="amiiboSeriesValue"> | ||
| 183 | <property name="sizePolicy"> | ||
| 184 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||
| 185 | <horstretch>0</horstretch> | ||
| 186 | <verstretch>0</verstretch> | ||
| 187 | </sizepolicy> | ||
| 188 | </property> | ||
| 189 | <property name="readOnly"> | ||
| 190 | <bool>true</bool> | ||
| 191 | </property> | ||
| 192 | </widget> | ||
| 193 | </item> | ||
| 194 | <item row="1" column="0"> | ||
| 195 | <widget class="QLabel" name="amiiboTypeLabel"> | ||
| 196 | <property name="text"> | ||
| 197 | <string>Type</string> | ||
| 198 | </property> | ||
| 199 | </widget> | ||
| 200 | </item> | ||
| 201 | <item row="1" column="1"> | ||
| 202 | <widget class="QLineEdit" name="amiiboTypeValue"> | ||
| 203 | <property name="sizePolicy"> | ||
| 204 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||
| 205 | <horstretch>0</horstretch> | ||
| 206 | <verstretch>0</verstretch> | ||
| 207 | </sizepolicy> | ||
| 208 | </property> | ||
| 209 | <property name="readOnly"> | ||
| 210 | <bool>true</bool> | ||
| 211 | </property> | ||
| 212 | </widget> | ||
| 213 | </item> | ||
| 214 | <item row="2" column="0"> | ||
| 215 | <widget class="QLabel" name="amiiboNameLabel"> | ||
| 216 | <property name="text"> | ||
| 217 | <string>Name</string> | ||
| 218 | </property> | ||
| 219 | </widget> | ||
| 220 | </item> | ||
| 221 | <item row="2" column="1"> | ||
| 222 | <widget class="QLineEdit" name="amiiboNameValue"> | ||
| 223 | <property name="sizePolicy"> | ||
| 224 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||
| 225 | <horstretch>0</horstretch> | ||
| 226 | <verstretch>0</verstretch> | ||
| 227 | </sizepolicy> | ||
| 228 | </property> | ||
| 229 | <property name="readOnly"> | ||
| 230 | <bool>true</bool> | ||
| 231 | </property> | ||
| 232 | </widget> | ||
| 233 | </item> | ||
| 234 | </layout> | ||
| 235 | </item> | ||
| 236 | </layout> | ||
| 237 | </widget> | ||
| 238 | </item> | ||
| 239 | <item> | ||
| 240 | <widget class="QGroupBox" name="amiiboDataGroup"> | ||
| 241 | <property name="title"> | ||
| 242 | <string>Amiibo Data</string> | ||
| 243 | </property> | ||
| 244 | <layout class="QVBoxLayout" name="verticalLayout_6"> | ||
| 245 | <item> | ||
| 246 | <layout class="QGridLayout" name="gridLayout_2"> | ||
| 247 | <item row="0" column="0"> | ||
| 248 | <widget class="QLabel" name="amiiboCustomNameLabel"> | ||
| 249 | <property name="text"> | ||
| 250 | <string>Custom Name</string> | ||
| 251 | </property> | ||
| 252 | </widget> | ||
| 253 | </item> | ||
| 254 | <item row="0" column="1"> | ||
| 255 | <widget class="QLineEdit" name="amiiboCustomNameValue"> | ||
| 256 | <property name="sizePolicy"> | ||
| 257 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||
| 258 | <horstretch>0</horstretch> | ||
| 259 | <verstretch>0</verstretch> | ||
| 260 | </sizepolicy> | ||
| 261 | </property> | ||
| 262 | <property name="maxLength"> | ||
| 263 | <number>10</number> | ||
| 264 | </property> | ||
| 265 | </widget> | ||
| 266 | </item> | ||
| 267 | <item row="1" column="0"> | ||
| 268 | <widget class="QLabel" name="amiiboOwnerLabel"> | ||
| 269 | <property name="text"> | ||
| 270 | <string>Owner</string> | ||
| 271 | </property> | ||
| 272 | </widget> | ||
| 273 | </item> | ||
| 274 | <item row="1" column="1"> | ||
| 275 | <widget class="QLineEdit" name="amiiboOwnerValue"> | ||
| 276 | <property name="sizePolicy"> | ||
| 277 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||
| 278 | <horstretch>0</horstretch> | ||
| 279 | <verstretch>0</verstretch> | ||
| 280 | </sizepolicy> | ||
| 281 | </property> | ||
| 282 | <property name="maxLength"> | ||
| 283 | <number>10</number> | ||
| 284 | </property> | ||
| 285 | </widget> | ||
| 286 | </item> | ||
| 287 | <item row="2" column="0"> | ||
| 288 | <widget class="QLabel" name="creationDateLabel"> | ||
| 289 | <property name="text"> | ||
| 290 | <string>Creation Date</string> | ||
| 291 | </property> | ||
| 292 | </widget> | ||
| 293 | </item> | ||
| 294 | <item row="2" column="1"> | ||
| 295 | <widget class="QDateTimeEdit" name="creationDateValue"> | ||
| 296 | <property name="readOnly"> | ||
| 297 | <bool>true</bool> | ||
| 298 | </property> | ||
| 299 | <property name="minimumDate"> | ||
| 300 | <date> | ||
| 301 | <year>1970</year> | ||
| 302 | <month>1</month> | ||
| 303 | <day>1</day> | ||
| 304 | </date> | ||
| 305 | </property> | ||
| 306 | <property name="displayFormat"> | ||
| 307 | <string>dd/MM/yyyy</string> | ||
| 308 | </property> | ||
| 309 | </widget> | ||
| 310 | </item> | ||
| 311 | <item row="3" column="0"> | ||
| 312 | <widget class="QLabel" name="modificationDateLabel"> | ||
| 313 | <property name="text"> | ||
| 314 | <string>Modification Date</string> | ||
| 315 | </property> | ||
| 316 | </widget> | ||
| 317 | </item> | ||
| 318 | <item row="3" column="1"> | ||
| 319 | <widget class="QDateTimeEdit" name="modificationDateValue"> | ||
| 320 | <property name="readOnly"> | ||
| 321 | <bool>true</bool> | ||
| 322 | </property> | ||
| 323 | <property name="minimumDate"> | ||
| 324 | <date> | ||
| 325 | <year>1970</year> | ||
| 326 | <month>1</month> | ||
| 327 | <day>1</day> | ||
| 328 | </date> | ||
| 329 | </property> | ||
| 330 | <property name="displayFormat"> | ||
| 331 | <string>dd/MM/yyyy </string> | ||
| 332 | </property> | ||
| 333 | </widget> | ||
| 334 | </item> | ||
| 335 | </layout> | ||
| 336 | </item> | ||
| 337 | </layout> | ||
| 338 | </widget> | ||
| 339 | </item> | ||
| 340 | <item> | ||
| 341 | <widget class="QGroupBox" name="gameDataGroup"> | ||
| 342 | <property name="minimumSize"> | ||
| 343 | <size> | ||
| 344 | <width>500</width> | ||
| 345 | <height>0</height> | ||
| 346 | </size> | ||
| 347 | </property> | ||
| 348 | <property name="title"> | ||
| 349 | <string>Game Data</string> | ||
| 350 | </property> | ||
| 351 | <layout class="QGridLayout" name="gridLayout_3"> | ||
| 352 | <item row="0" column="0"> | ||
| 353 | <widget class="QLabel" name="gameIdLabel"> | ||
| 354 | <property name="text"> | ||
| 355 | <string>Game Id</string> | ||
| 356 | </property> | ||
| 357 | </widget> | ||
| 358 | </item> | ||
| 359 | <item row="0" column="1"> | ||
| 360 | <widget class="QLineEdit" name="gameIdValue"> | ||
| 361 | <property name="sizePolicy"> | ||
| 362 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||
| 363 | <horstretch>0</horstretch> | ||
| 364 | <verstretch>0</verstretch> | ||
| 365 | </sizepolicy> | ||
| 366 | </property> | ||
| 367 | <property name="readOnly"> | ||
| 368 | <bool>true</bool> | ||
| 369 | </property> | ||
| 370 | </widget> | ||
| 371 | </item> | ||
| 372 | </layout> | ||
| 373 | </widget> | ||
| 374 | </item> | ||
| 375 | <item> | ||
| 376 | <widget class="QGroupBox" name="MountAmiiboGroup"> | ||
| 377 | <property name="minimumSize"> | ||
| 378 | <size> | ||
| 379 | <width>500</width> | ||
| 380 | <height>0</height> | ||
| 381 | </size> | ||
| 382 | </property> | ||
| 383 | <property name="title"> | ||
| 384 | <string>Mount Amiibo</string> | ||
| 385 | </property> | ||
| 386 | <layout class="QGridLayout" name="gridLayout_4"> | ||
| 387 | <item row="0" column="3"> | ||
| 388 | <widget class="QToolButton" name="amiiboDirectoryButton"> | ||
| 389 | <property name="text"> | ||
| 390 | <string>...</string> | ||
| 391 | </property> | ||
| 392 | </widget> | ||
| 393 | </item> | ||
| 394 | <item row="0" column="1"> | ||
| 395 | <spacer name="horizontalSpacer"> | ||
| 396 | <property name="orientation"> | ||
| 397 | <enum>Qt::Horizontal</enum> | ||
| 398 | </property> | ||
| 399 | <property name="sizeType"> | ||
| 400 | <enum>QSizePolicy::Maximum</enum> | ||
| 401 | </property> | ||
| 402 | <property name="sizeHint" stdset="0"> | ||
| 403 | <size> | ||
| 404 | <width>60</width> | ||
| 405 | <height>20</height> | ||
| 406 | </size> | ||
| 407 | </property> | ||
| 408 | </spacer> | ||
| 409 | </item> | ||
| 410 | <item row="0" column="0"> | ||
| 411 | <widget class="QLabel" name="amiiboDirectoryLabel"> | ||
| 412 | <property name="text"> | ||
| 413 | <string>File Path</string> | ||
| 414 | </property> | ||
| 415 | </widget> | ||
| 416 | </item> | ||
| 417 | <item row="0" column="2"> | ||
| 418 | <widget class="QLineEdit" name="amiiboDirectoryValue"/> | ||
| 419 | </item> | ||
| 420 | </layout> | ||
| 421 | </widget> | ||
| 422 | </item> | ||
| 423 | <item> | ||
| 424 | <spacer name="verticalSpacer"> | ||
| 425 | <property name="orientation"> | ||
| 426 | <enum>Qt::Vertical</enum> | ||
| 427 | </property> | ||
| 428 | <property name="sizeHint" stdset="0"> | ||
| 429 | <size> | ||
| 430 | <width>20</width> | ||
| 431 | <height>40</height> | ||
| 432 | </size> | ||
| 433 | </property> | ||
| 434 | </spacer> | ||
| 435 | </item> | ||
| 436 | </layout> | ||
| 437 | </item> | ||
| 438 | </layout> | ||
| 439 | </item> | ||
| 440 | </layout> | ||
| 441 | </widget> | ||
| 442 | </item> | ||
| 443 | <item> | ||
| 444 | <widget class="QWidget" name="bottomControllerApplet" native="true"> | ||
| 445 | <layout class="QHBoxLayout" name="horizontalLayout_6"> | ||
| 446 | <property name="spacing"> | ||
| 447 | <number>15</number> | ||
| 448 | </property> | ||
| 449 | <property name="leftMargin"> | ||
| 450 | <number>15</number> | ||
| 451 | </property> | ||
| 452 | <property name="topMargin"> | ||
| 453 | <number>8</number> | ||
| 454 | </property> | ||
| 455 | <property name="rightMargin"> | ||
| 456 | <number>20</number> | ||
| 457 | </property> | ||
| 458 | <property name="bottomMargin"> | ||
| 459 | <number>8</number> | ||
| 460 | </property> | ||
| 461 | <item alignment="Qt::AlignBottom"> | ||
| 462 | <widget class="QDialogButtonBox" name="buttonBox"> | ||
| 463 | <property name="enabled"> | ||
| 464 | <bool>true</bool> | ||
| 465 | </property> | ||
| 466 | <property name="standardButtons"> | ||
| 467 | <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||
| 468 | </property> | ||
| 469 | </widget> | ||
| 470 | </item> | ||
| 471 | </layout> | ||
| 472 | </widget> | ||
| 473 | </item> | ||
| 474 | </layout> | ||
| 475 | </widget> | ||
| 476 | </item> | ||
| 477 | </layout> | ||
| 478 | </widget> | ||
| 479 | <resources/> | ||
| 480 | <connections> | ||
| 481 | <connection> | ||
| 482 | <sender>buttonBox</sender> | ||
| 483 | <signal>accepted()</signal> | ||
| 484 | <receiver>QtAmiiboSettingsDialog</receiver> | ||
| 485 | <slot>accept()</slot> | ||
| 486 | </connection> | ||
| 487 | <connection> | ||
| 488 | <sender>buttonBox</sender> | ||
| 489 | <signal>rejected()</signal> | ||
| 490 | <receiver>QtAmiiboSettingsDialog</receiver> | ||
| 491 | <slot>reject()</slot> | ||
| 492 | </connection> | ||
| 493 | </connections> | ||
| 494 | </ui> | ||
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp index b03e71248..05f49c0d2 100644 --- a/src/yuzu/compatdb.cpp +++ b/src/yuzu/compatdb.cpp | |||
| @@ -126,6 +126,7 @@ void CompatDB::Submit() { | |||
| 126 | break; | 126 | break; |
| 127 | default: | 127 | default: |
| 128 | LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); | 128 | LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); |
| 129 | break; | ||
| 129 | } | 130 | } |
| 130 | } | 131 | } |
| 131 | 132 | ||
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index 5c0217ba8..a47089988 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp | |||
| @@ -2,6 +2,9 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <algorithm> | 4 | #include <algorithm> |
| 5 | #include <functional> | ||
| 6 | #include <QDialog> | ||
| 7 | #include <QDialogButtonBox> | ||
| 5 | #include <QFileDialog> | 8 | #include <QFileDialog> |
| 6 | #include <QGraphicsItem> | 9 | #include <QGraphicsItem> |
| 7 | #include <QHeaderView> | 10 | #include <QHeaderView> |
| @@ -108,9 +111,12 @@ ConfigureProfileManager::ConfigureProfileManager(const Core::System& system_, QW | |||
| 108 | 111 | ||
| 109 | connect(ui->pm_add, &QPushButton::clicked, this, &ConfigureProfileManager::AddUser); | 112 | connect(ui->pm_add, &QPushButton::clicked, this, &ConfigureProfileManager::AddUser); |
| 110 | connect(ui->pm_rename, &QPushButton::clicked, this, &ConfigureProfileManager::RenameUser); | 113 | connect(ui->pm_rename, &QPushButton::clicked, this, &ConfigureProfileManager::RenameUser); |
| 111 | connect(ui->pm_remove, &QPushButton::clicked, this, &ConfigureProfileManager::DeleteUser); | 114 | connect(ui->pm_remove, &QPushButton::clicked, this, |
| 115 | &ConfigureProfileManager::ConfirmDeleteUser); | ||
| 112 | connect(ui->pm_set_image, &QPushButton::clicked, this, &ConfigureProfileManager::SetUserImage); | 116 | connect(ui->pm_set_image, &QPushButton::clicked, this, &ConfigureProfileManager::SetUserImage); |
| 113 | 117 | ||
| 118 | confirm_dialog = new ConfigureProfileManagerDeleteDialog(this); | ||
| 119 | |||
| 114 | scene = new QGraphicsScene; | 120 | scene = new QGraphicsScene; |
| 115 | ui->current_user_icon->setScene(scene); | 121 | ui->current_user_icon->setScene(scene); |
| 116 | 122 | ||
| @@ -230,26 +236,23 @@ void ConfigureProfileManager::RenameUser() { | |||
| 230 | UpdateCurrentUser(); | 236 | UpdateCurrentUser(); |
| 231 | } | 237 | } |
| 232 | 238 | ||
| 233 | void ConfigureProfileManager::DeleteUser() { | 239 | void ConfigureProfileManager::ConfirmDeleteUser() { |
| 234 | const auto index = tree_view->currentIndex().row(); | 240 | const auto index = tree_view->currentIndex().row(); |
| 235 | const auto uuid = profile_manager->GetUser(index); | 241 | const auto uuid = profile_manager->GetUser(index); |
| 236 | ASSERT(uuid); | 242 | ASSERT(uuid); |
| 237 | const auto username = GetAccountUsername(*profile_manager, *uuid); | 243 | const auto username = GetAccountUsername(*profile_manager, *uuid); |
| 238 | 244 | ||
| 239 | const auto confirm = QMessageBox::question( | 245 | confirm_dialog->SetInfo(username, *uuid, [this, uuid]() { DeleteUser(*uuid); }); |
| 240 | this, tr("Confirm Delete"), | 246 | confirm_dialog->show(); |
| 241 | tr("You are about to delete user with name \"%1\". Are you sure?").arg(username)); | 247 | } |
| 242 | |||
| 243 | if (confirm == QMessageBox::No) { | ||
| 244 | return; | ||
| 245 | } | ||
| 246 | 248 | ||
| 249 | void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) { | ||
| 247 | if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) { | 250 | if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) { |
| 248 | Settings::values.current_user = 0; | 251 | Settings::values.current_user = 0; |
| 249 | } | 252 | } |
| 250 | UpdateCurrentUser(); | 253 | UpdateCurrentUser(); |
| 251 | 254 | ||
| 252 | if (!profile_manager->RemoveUser(*uuid)) { | 255 | if (!profile_manager->RemoveUser(uuid)) { |
| 253 | return; | 256 | return; |
| 254 | } | 257 | } |
| 255 | 258 | ||
| @@ -319,3 +322,47 @@ void ConfigureProfileManager::SetUserImage() { | |||
| 319 | new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)}); | 322 | new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)}); |
| 320 | UpdateCurrentUser(); | 323 | UpdateCurrentUser(); |
| 321 | } | 324 | } |
| 325 | |||
| 326 | ConfigureProfileManagerDeleteDialog::ConfigureProfileManagerDeleteDialog(QWidget* parent) | ||
| 327 | : QDialog{parent} { | ||
| 328 | auto dialog_vbox_layout = new QVBoxLayout(this); | ||
| 329 | dialog_button_box = | ||
| 330 | new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No, Qt::Horizontal, parent); | ||
| 331 | auto label_message = | ||
| 332 | new QLabel(tr("Delete this user? All of the user's save data will be deleted."), this); | ||
| 333 | label_info = new QLabel(this); | ||
| 334 | auto dialog_hbox_layout_widget = new QWidget(this); | ||
| 335 | auto dialog_hbox_layout = new QHBoxLayout(dialog_hbox_layout_widget); | ||
| 336 | icon_scene = new QGraphicsScene(0, 0, 64, 64, this); | ||
| 337 | auto icon_view = new QGraphicsView(icon_scene, this); | ||
| 338 | |||
| 339 | dialog_hbox_layout_widget->setLayout(dialog_hbox_layout); | ||
| 340 | icon_view->setMaximumSize(64, 64); | ||
| 341 | icon_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | ||
| 342 | icon_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | ||
| 343 | this->setLayout(dialog_vbox_layout); | ||
| 344 | this->setWindowTitle(tr("Confirm Delete")); | ||
| 345 | this->setSizeGripEnabled(false); | ||
| 346 | dialog_vbox_layout->addWidget(label_message); | ||
| 347 | dialog_vbox_layout->addWidget(dialog_hbox_layout_widget); | ||
| 348 | dialog_vbox_layout->addWidget(dialog_button_box); | ||
| 349 | dialog_hbox_layout->addWidget(icon_view); | ||
| 350 | dialog_hbox_layout->addWidget(label_info); | ||
| 351 | |||
| 352 | connect(dialog_button_box, &QDialogButtonBox::rejected, this, [this]() { close(); }); | ||
| 353 | } | ||
| 354 | |||
| 355 | ConfigureProfileManagerDeleteDialog::~ConfigureProfileManagerDeleteDialog() = default; | ||
| 356 | |||
| 357 | void ConfigureProfileManagerDeleteDialog::SetInfo(const QString& username, const Common::UUID& uuid, | ||
| 358 | std::function<void()> accept_callback) { | ||
| 359 | label_info->setText( | ||
| 360 | tr("Name: %1\nUUID: %2").arg(username, QString::fromStdString(uuid.FormattedString()))); | ||
| 361 | icon_scene->clear(); | ||
| 362 | icon_scene->addPixmap(GetIcon(uuid)); | ||
| 363 | |||
| 364 | connect(dialog_button_box, &QDialogButtonBox::accepted, this, [this, accept_callback]() { | ||
| 365 | close(); | ||
| 366 | accept_callback(); | ||
| 367 | }); | ||
| 368 | } | ||
diff --git a/src/yuzu/configuration/configure_profile_manager.h b/src/yuzu/configuration/configure_profile_manager.h index fe9033779..c4b1a334e 100644 --- a/src/yuzu/configuration/configure_profile_manager.h +++ b/src/yuzu/configuration/configure_profile_manager.h | |||
| @@ -3,16 +3,24 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <functional> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | 8 | ||
| 9 | #include <QDialog> | ||
| 8 | #include <QList> | 10 | #include <QList> |
| 9 | #include <QWidget> | 11 | #include <QWidget> |
| 10 | 12 | ||
| 13 | namespace Common { | ||
| 14 | struct UUID; | ||
| 15 | } | ||
| 16 | |||
| 11 | namespace Core { | 17 | namespace Core { |
| 12 | class System; | 18 | class System; |
| 13 | } | 19 | } |
| 14 | 20 | ||
| 15 | class QGraphicsScene; | 21 | class QGraphicsScene; |
| 22 | class QDialogButtonBox; | ||
| 23 | class QLabel; | ||
| 16 | class QStandardItem; | 24 | class QStandardItem; |
| 17 | class QStandardItemModel; | 25 | class QStandardItemModel; |
| 18 | class QTreeView; | 26 | class QTreeView; |
| @@ -26,6 +34,20 @@ namespace Ui { | |||
| 26 | class ConfigureProfileManager; | 34 | class ConfigureProfileManager; |
| 27 | } | 35 | } |
| 28 | 36 | ||
| 37 | class ConfigureProfileManagerDeleteDialog : public QDialog { | ||
| 38 | public: | ||
| 39 | explicit ConfigureProfileManagerDeleteDialog(QWidget* parent); | ||
| 40 | ~ConfigureProfileManagerDeleteDialog(); | ||
| 41 | |||
| 42 | void SetInfo(const QString& username, const Common::UUID& uuid, | ||
| 43 | std::function<void()> accept_callback); | ||
| 44 | |||
| 45 | private: | ||
| 46 | QDialogButtonBox* dialog_button_box; | ||
| 47 | QGraphicsScene* icon_scene; | ||
| 48 | QLabel* label_info; | ||
| 49 | }; | ||
| 50 | |||
| 29 | class ConfigureProfileManager : public QWidget { | 51 | class ConfigureProfileManager : public QWidget { |
| 30 | Q_OBJECT | 52 | Q_OBJECT |
| 31 | 53 | ||
| @@ -47,7 +69,8 @@ private: | |||
| 47 | void SelectUser(const QModelIndex& index); | 69 | void SelectUser(const QModelIndex& index); |
| 48 | void AddUser(); | 70 | void AddUser(); |
| 49 | void RenameUser(); | 71 | void RenameUser(); |
| 50 | void DeleteUser(); | 72 | void ConfirmDeleteUser(); |
| 73 | void DeleteUser(const Common::UUID& uuid); | ||
| 51 | void SetUserImage(); | 74 | void SetUserImage(); |
| 52 | 75 | ||
| 53 | QVBoxLayout* layout; | 76 | QVBoxLayout* layout; |
| @@ -55,6 +78,8 @@ private: | |||
| 55 | QStandardItemModel* item_model; | 78 | QStandardItemModel* item_model; |
| 56 | QGraphicsScene* scene; | 79 | QGraphicsScene* scene; |
| 57 | 80 | ||
| 81 | ConfigureProfileManagerDeleteDialog* confirm_dialog; | ||
| 82 | |||
| 58 | std::vector<QList<QStandardItem*>> list_items; | 83 | std::vector<QList<QStandardItem*>> list_items; |
| 59 | 84 | ||
| 60 | std::unique_ptr<Ui::ConfigureProfileManager> ui; | 85 | std::unique_ptr<Ui::ConfigureProfileManager> ui; |
diff --git a/src/yuzu/configuration/configure_profile_manager.ui b/src/yuzu/configuration/configure_profile_manager.ui index cfe7478c8..bd6dea4f4 100644 --- a/src/yuzu/configuration/configure_profile_manager.ui +++ b/src/yuzu/configuration/configure_profile_manager.ui | |||
| @@ -57,6 +57,12 @@ | |||
| 57 | <height>48</height> | 57 | <height>48</height> |
| 58 | </size> | 58 | </size> |
| 59 | </property> | 59 | </property> |
| 60 | <property name="frameShape"> | ||
| 61 | <enum>QFrame::NoFrame</enum> | ||
| 62 | </property> | ||
| 63 | <property name="frameShadow"> | ||
| 64 | <enum>QFrame::Plain</enum> | ||
| 65 | </property> | ||
| 60 | <property name="verticalScrollBarPolicy"> | 66 | <property name="verticalScrollBarPolicy"> |
| 61 | <enum>Qt::ScrollBarAlwaysOff</enum> | 67 | <enum>Qt::ScrollBarAlwaysOff</enum> |
| 62 | </property> | 68 | </property> |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 032ff1cbc..4081af391 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #endif | 15 | #endif |
| 16 | 16 | ||
| 17 | // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. | 17 | // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. |
| 18 | #include "applets/qt_amiibo_settings.h" | ||
| 18 | #include "applets/qt_controller.h" | 19 | #include "applets/qt_controller.h" |
| 19 | #include "applets/qt_error.h" | 20 | #include "applets/qt_error.h" |
| 20 | #include "applets/qt_profile_select.h" | 21 | #include "applets/qt_profile_select.h" |
| @@ -26,6 +27,7 @@ | |||
| 26 | #include "configuration/configure_tas.h" | 27 | #include "configuration/configure_tas.h" |
| 27 | #include "core/file_sys/vfs.h" | 28 | #include "core/file_sys/vfs.h" |
| 28 | #include "core/file_sys/vfs_real.h" | 29 | #include "core/file_sys/vfs_real.h" |
| 30 | #include "core/frontend/applets/cabinet.h" | ||
| 29 | #include "core/frontend/applets/controller.h" | 31 | #include "core/frontend/applets/controller.h" |
| 30 | #include "core/frontend/applets/general_frontend.h" | 32 | #include "core/frontend/applets/general_frontend.h" |
| 31 | #include "core/frontend/applets/mii_edit.h" | 33 | #include "core/frontend/applets/mii_edit.h" |
| @@ -361,11 +363,10 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan | |||
| 361 | } | 363 | } |
| 362 | } | 364 | } |
| 363 | LOG_INFO(Frontend, "Host CPU: {}", cpu_string); | 365 | LOG_INFO(Frontend, "Host CPU: {}", cpu_string); |
| 364 | #endif | ||
| 365 | |||
| 366 | if (std::optional<int> processor_core = Common::GetProcessorCount()) { | 366 | if (std::optional<int> processor_core = Common::GetProcessorCount()) { |
| 367 | LOG_INFO(Frontend, "Host CPU Cores: {}", *processor_core); | 367 | LOG_INFO(Frontend, "Host CPU Cores: {}", *processor_core); |
| 368 | } | 368 | } |
| 369 | #endif | ||
| 369 | LOG_INFO(Frontend, "Host CPU Threads: {}", processor_count); | 370 | LOG_INFO(Frontend, "Host CPU Threads: {}", processor_count); |
| 370 | LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString()); | 371 | LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString()); |
| 371 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", | 372 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", |
| @@ -549,6 +550,11 @@ void GMainWindow::RegisterMetaTypes() { | |||
| 549 | 550 | ||
| 550 | // Register applet types | 551 | // Register applet types |
| 551 | 552 | ||
| 553 | // Cabinet Applet | ||
| 554 | qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters"); | ||
| 555 | qRegisterMetaType<std::shared_ptr<Service::NFP::NfpDevice>>( | ||
| 556 | "std::shared_ptr<Service::NFP::NfpDevice>"); | ||
| 557 | |||
| 552 | // Controller Applet | 558 | // Controller Applet |
| 553 | qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); | 559 | qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); |
| 554 | 560 | ||
| @@ -570,6 +576,21 @@ void GMainWindow::RegisterMetaTypes() { | |||
| 570 | qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus"); | 576 | qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus"); |
| 571 | } | 577 | } |
| 572 | 578 | ||
| 579 | void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, | ||
| 580 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device) { | ||
| 581 | QtAmiiboSettingsDialog dialog(this, parameters, input_subsystem.get(), nfp_device); | ||
| 582 | |||
| 583 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | | ||
| 584 | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); | ||
| 585 | dialog.setWindowModality(Qt::WindowModal); | ||
| 586 | if (dialog.exec() == QDialog::Rejected) { | ||
| 587 | emit AmiiboSettingsFinished(false, {}); | ||
| 588 | return; | ||
| 589 | } | ||
| 590 | |||
| 591 | emit AmiiboSettingsFinished(true, dialog.GetName()); | ||
| 592 | } | ||
| 593 | |||
| 573 | void GMainWindow::ControllerSelectorReconfigureControllers( | 594 | void GMainWindow::ControllerSelectorReconfigureControllers( |
| 574 | const Core::Frontend::ControllerParameters& parameters) { | 595 | const Core::Frontend::ControllerParameters& parameters) { |
| 575 | QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system); | 596 | QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system); |
| @@ -1547,6 +1568,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p | |||
| 1547 | system->SetFilesystem(vfs); | 1568 | system->SetFilesystem(vfs); |
| 1548 | 1569 | ||
| 1549 | system->SetAppletFrontendSet({ | 1570 | system->SetAppletFrontendSet({ |
| 1571 | std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings | ||
| 1550 | std::make_unique<QtControllerSelector>(*this), // Controller Selector | 1572 | std::make_unique<QtControllerSelector>(*this), // Controller Selector |
| 1551 | std::make_unique<QtErrorDisplay>(*this), // Error Display | 1573 | std::make_unique<QtErrorDisplay>(*this), // Error Display |
| 1552 | nullptr, // Mii Editor | 1574 | nullptr, // Mii Editor |
| @@ -1957,6 +1979,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | |||
| 1957 | } | 1979 | } |
| 1958 | default: | 1980 | default: |
| 1959 | UNIMPLEMENTED(); | 1981 | UNIMPLEMENTED(); |
| 1982 | break; | ||
| 1960 | } | 1983 | } |
| 1961 | 1984 | ||
| 1962 | const QString qpath = QString::fromStdString(Common::FS::PathToUTF8String(path)); | 1985 | const QString qpath = QString::fromStdString(Common::FS::PathToUTF8String(path)); |
| @@ -3200,6 +3223,7 @@ void GMainWindow::OnToggleGpuAccuracy() { | |||
| 3200 | case Settings::GPUAccuracy::Extreme: | 3223 | case Settings::GPUAccuracy::Extreme: |
| 3201 | default: { | 3224 | default: { |
| 3202 | Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High); | 3225 | Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High); |
| 3226 | break; | ||
| 3203 | } | 3227 | } |
| 3204 | } | 3228 | } |
| 3205 | 3229 | ||
| @@ -3532,6 +3556,7 @@ void GMainWindow::UpdateGPUAccuracyButton() { | |||
| 3532 | default: { | 3556 | default: { |
| 3533 | gpu_accuracy_button->setText(tr("GPU ERROR")); | 3557 | gpu_accuracy_button->setText(tr("GPU ERROR")); |
| 3534 | gpu_accuracy_button->setChecked(true); | 3558 | gpu_accuracy_button->setChecked(true); |
| 3559 | break; | ||
| 3535 | } | 3560 | } |
| 3536 | } | 3561 | } |
| 3537 | } | 3562 | } |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b73f550dd..6a9992d05 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -55,6 +55,7 @@ class System; | |||
| 55 | } // namespace Core | 55 | } // namespace Core |
| 56 | 56 | ||
| 57 | namespace Core::Frontend { | 57 | namespace Core::Frontend { |
| 58 | struct CabinetParameters; | ||
| 58 | struct ControllerParameters; | 59 | struct ControllerParameters; |
| 59 | struct InlineAppearParameters; | 60 | struct InlineAppearParameters; |
| 60 | struct InlineTextParameters; | 61 | struct InlineTextParameters; |
| @@ -82,6 +83,10 @@ enum class SwkbdReplyType : u32; | |||
| 82 | enum class WebExitReason : u32; | 83 | enum class WebExitReason : u32; |
| 83 | } // namespace Service::AM::Applets | 84 | } // namespace Service::AM::Applets |
| 84 | 85 | ||
| 86 | namespace Service::NFP { | ||
| 87 | class NfpDevice; | ||
| 88 | } // namespace Service::NFP | ||
| 89 | |||
| 85 | namespace Ui { | 90 | namespace Ui { |
| 86 | class MainWindow; | 91 | class MainWindow; |
| 87 | } | 92 | } |
| @@ -149,6 +154,8 @@ signals: | |||
| 149 | 154 | ||
| 150 | void UpdateInstallProgress(); | 155 | void UpdateInstallProgress(); |
| 151 | 156 | ||
| 157 | void AmiiboSettingsFinished(bool is_success, const std::string& name); | ||
| 158 | |||
| 152 | void ControllerSelectorReconfigureFinished(); | 159 | void ControllerSelectorReconfigureFinished(); |
| 153 | 160 | ||
| 154 | void ErrorDisplayFinished(); | 161 | void ErrorDisplayFinished(); |
| @@ -170,6 +177,8 @@ public slots: | |||
| 170 | void OnExecuteProgram(std::size_t program_index); | 177 | void OnExecuteProgram(std::size_t program_index); |
| 171 | void OnExit(); | 178 | void OnExit(); |
| 172 | void OnSaveConfig(); | 179 | void OnSaveConfig(); |
| 180 | void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, | ||
| 181 | std::shared_ptr<Service::NFP::NfpDevice> nfp_device); | ||
| 173 | void ControllerSelectorReconfigureControllers( | 182 | void ControllerSelectorReconfigureControllers( |
| 174 | const Core::Frontend::ControllerParameters& parameters); | 183 | const Core::Frontend::ControllerParameters& parameters); |
| 175 | void SoftwareKeyboardInitialize( | 184 | void SoftwareKeyboardInitialize( |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 65455c86e..25948328c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | |||
| @@ -84,6 +84,7 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste | |||
| 84 | default: | 84 | default: |
| 85 | LOG_CRITICAL(Frontend, "Window manager subsystem not implemented"); | 85 | LOG_CRITICAL(Frontend, "Window manager subsystem not implemented"); |
| 86 | std::exit(EXIT_FAILURE); | 86 | std::exit(EXIT_FAILURE); |
| 87 | break; | ||
| 87 | } | 88 | } |
| 88 | 89 | ||
| 89 | OnResize(); | 90 | OnResize(); |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index e16f79eb4..dfe5a30ea 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -351,6 +351,7 @@ int main(int argc, char** argv) { | |||
| 351 | "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}", | 351 | "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}", |
| 352 | loader_id, error_id, static_cast<Loader::ResultStatus>(error_id)); | 352 | loader_id, error_id, static_cast<Loader::ResultStatus>(error_id)); |
| 353 | } | 353 | } |
| 354 | break; | ||
| 354 | } | 355 | } |
| 355 | 356 | ||
| 356 | system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL"); | 357 | system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL"); |