Compare commits

..

57 Commits

Author SHA1 Message Date
Robin Kertels
dce242858a vk_scheduler: Remove recorded_counts 2022-10-28 03:42:43 +02:00
liamwhite
8ce6256722 Merge pull request #9138 from liamwhite/hbl-stacktrace
arm_interface: curb infinite recursion in stacktrace generation
2022-10-27 20:07:48 -04:00
Liam
3e6840a74c arm_interface: curb infinite recursion in stacktrace generation 2022-10-27 16:01:05 -04:00
bunnei
25d53e66d1 Merge pull request #9115 from vonchenplus/game_name_by_language
file_sys: Priority display of game titles in the current language
2022-10-27 11:33:02 -07:00
bunnei
20118075c5 Merge pull request #9126 from vonchenplus/revert-8068-shader-if-false
Revert "shader_recompiler/dead_code_elimination: Add DeadBranchElimination pass"
2022-10-27 10:11:02 -07:00
liamwhite
86a3a0b1b4 Merge pull request #9134 from lioncash/init
audio_in/out_system: Pass Initialize members by value where applicable
2022-10-27 08:10:24 -04:00
bunnei
2dd6a2352d Merge pull request #9125 from liamwhite/dummy-scheduler
kernel: refactor dummy thread wakeups
2022-10-26 09:51:44 -07:00
Lioncash
e0ec9ffc36 audio_in/out_system: Pass Initialize members by value where applicable
applet_resource_user_id isn't actually modified and is just assigned to
a member variable, so this doesn't need to be a mutable reference.

Similarly, the device name itself isn't modified and is only moved. We
pass by value here, since we can still perform the move, but eliminate a
sneaky set of calls that can unintentionally destroy the original
string. Given how nested the calls are, it's good to get rid of this
potential vector for a use-after-move bug.
2022-10-26 11:21:48 -04:00
Mai
041eb5bf57 Merge pull request #9131 from Morph1984/contiguous
concepts: Use the std::contiguous_iterator concept
2022-10-26 15:12:48 +00:00
Morph
8b4d5aeb4f concepts: Use the std::contiguous_iterator concept
This also covers std::span, which does not have a const iterator.

Also renames IsSTLContainer to IsContiguousContainer to explicitly convey its semantics.
2022-10-26 00:41:54 -04:00
liamwhite
d8e3380ea5 Merge pull request #9128 from abouvier/patch-1
tests: fix for -Wall
2022-10-25 12:36:25 -04:00
liamwhite
e59bd6c335 Merge pull request #9113 from german77/peer_pressure
service: nfp: Allow amiibos without keys
2022-10-25 12:13:31 -04:00
liamwhite
77803d96be Merge pull request #9107 from german77/gidoly_rules
input_common: cache vibration tests
2022-10-25 12:13:18 -04:00
Alexandre Bouvier
fa9b7db76f tests: fix for -Wall
Fix #9123
2022-10-25 15:20:23 +00:00
liamwhite
fa913a702f Merge pull request #9112 from vonchenplus/deferred_draw
video_core: Reimplementing the maxwell drawing trigger mechanism
2022-10-25 09:42:59 -04:00
liamwhite
3c38bd7cf0 Merge pull request #9119 from liamwhite/shutdown-barrier
core: barrier service thread shutdown
2022-10-25 06:45:51 -04:00
Feng Chen
165bce3c2d Revert "shader_recompiler/dead_code_elimination: Add DeadBranchElimination pass" 2022-10-25 12:57:25 +08:00
Liam
1a378a7769 kernel: refactor dummy thread wakeups 2022-10-24 19:52:01 -04:00
bunnei
cbb6c24215 Merge pull request #8873 from vonchenplus/fix_legacy_location_error
video_core: Fix legacy to generic location unpaired
2022-10-24 10:50:24 -07:00
FengChen
1689e0a71f file_sys: Priority display of game titles in the current language 2022-10-24 21:55:25 +08:00
Fernando S
2e782a154d Merge pull request #9122 from liamwhite/burnt-chicken
nvdrv: fix container destruction order
2022-10-24 12:41:46 +02:00
bunnei
0313ee7793 Merge pull request #9105 from Morph1984/warnings
general: Treat more warnings as errors
2022-10-23 17:25:18 -07:00
Liam
05f2673648 nvdrv: fix container destruction order 2022-10-23 19:25:57 -04:00
Liam
2d90a927c9 core: barrier service thread shutdown 2022-10-23 05:45:45 -04:00
german77
2ccbf5abdd core: hid: Add handheld to nfc devices 2022-10-22 14:05:00 -05:00
Morph
120cd450e5 CMakeLists: Disable -Wbraced-scalar-init on Clang
Clang erroneously emits this warning when using designated initializers.
2022-10-22 15:02:04 -04:00
Morph
f51c71e956 yuzu: Resolve -Wpessimizing-move 2022-10-22 15:02:04 -04:00
Morph
bb31b0f261 startup_checks: Resolve -Wstringop-truncation
Copies up to sizeof(p_name) - 1 in strncpy and null terminates it at p_name[254]
2022-10-22 15:02:04 -04:00
Morph
f86774c1ac startup_checks: Resolve -Wformat 2022-10-22 15:02:04 -04:00
Morph
42c4ef7373 general: Resolve -Wunused-but-set-variable 2022-10-22 15:02:04 -04:00
Morph
c7e079a5d4 general: Resolve -Wunused-lambda-capture and C5233 2022-10-22 15:02:04 -04:00
Morph
6908ea2284 general: Resolve -Wclass-memaccess 2022-10-22 15:02:04 -04:00
Morph
347432524c ipc_helpers: Ignore GCC compiler warnings only on GCC
Clang and ICC for whatever reason also defines __GNUC__. Exclude them from this check.
2022-10-22 15:02:04 -04:00
Morph
b02c3f2314 CMakeLists: Enforce C5233 on MSVC
This is similar to Clang's -Wunused-lambda-capture
2022-10-22 15:02:04 -04:00
Morph
3822e31323 CMakeLists: Disable C4100 and C4324
Disabling C4100 is similar to -Wno-unused-parameter
2022-10-22 15:02:04 -04:00
Morph
cae108404a CMakeLists: Remove redundant warnings
These warnings are already included in /W3.
2022-10-22 15:02:04 -04:00
Morph
bad3025951 decoders: Use 2's complement instead of unary -
Resolves C4146 on MSVC
2022-10-22 15:02:04 -04:00
Morph
f3c40f4a20 CMakeLists: Treat MSVC warnings as errors 2022-10-22 15:02:04 -04:00
Morph
e6ab1f673b general: Enforce C4800 everywhere except in video_core 2022-10-22 15:02:04 -04:00
Morph
93297d14d8 CMakeLists: Remove all redundant warnings
These are already explicitly or implicitly set in src/CMakeLists.txt
2022-10-22 15:02:04 -04:00
Morph
91c410c918 CMakeLists: Consolidate all unused warnings into -Wunused 2022-10-22 15:02:04 -04:00
Morph
496695618a CMakeLists: Treat -Wall and -Wextra as errors 2022-10-22 15:02:04 -04:00
Fernando S
0860fffd78 Merge pull request #9095 from FernandoS27/meat-good-vegetable-bad
Maxwell3D/Puller: Fix regressions and syncing issues.
2022-10-22 13:06:03 +02:00
Narr the Reg
3e0aaeba98 service: nfp: Allow amiibos without keys 2022-10-21 23:08:07 -05:00
Narr the Reg
82fdfb33ac service: nfp: remove unnecessary include 2022-10-21 21:54:31 -05:00
liamwhite
efaedcab31 Merge pull request #9106 from lioncash/copy-err
hid/npad: Fix copy size in GetSupportedNpadIdTypes
2022-10-21 03:47:02 -04:00
liamwhite
49682a0481 Merge pull request #9108 from Morph1984/r32-b24g8
format_lookup_table: Implement R32_B24G8 with D32_FLOAT_S8_UINT
2022-10-21 03:45:49 -04:00
liamwhite
aa9e9052a6 Merge pull request #9109 from lioncash/session
k_session_request: Add missing override
2022-10-21 03:44:30 -04:00
Lioncash
93a7058d8e k_session_request: Add missing override specifier 2022-10-21 01:56:14 -04:00
Morph
f16db300c6 format_lookup_table: Implement R32_B24G8 with D32_FLOAT_S8_UINT
This format is similar to Z32_FLOAT_X24S8_UINT, which is implemented with D32_FLOAT_S8_UINT.

Used in Persona 5 Royal
2022-10-21 01:54:57 -04:00
Lioncash
969387a79a k_session_request: Turn C-style array into std::array
Makes for stronger typing and allows tooling bounds checks provided by
the standard library for debugging purposes.
2022-10-21 01:54:34 -04:00
Lioncash
3968faec06 k_session_request: Simplify constructor initialization 2022-10-21 01:53:10 -04:00
german77
7f66050f0c input_common: cache vibration tests 2022-10-21 00:24:08 -05:00
Lioncash
0b181eeef4 hid/npad: Fix copy size in GetSupportedNpadIdTypes
Previously this was passing the size of the vector into memcpy rather
than the size in bytes to copy, which would result in a partial read.

Thankfully, this function isn't used yet, so this gets rid of a bug
before it's able to do anything.
2022-10-21 00:09:22 -04:00
Fernando Sahmkow
3cb4498142 Maxwell3D/Puller: Fix regressions and syncing issues. 2022-10-19 06:21:51 +02:00
FengChen
20139f8a55 Address feedback 2022-10-17 09:40:44 +08:00
FengChen
d4cb0eac87 video_core: Fix legacy to generic location unpaired 2022-09-20 12:03:31 +08:00
84 changed files with 478 additions and 475 deletions

View File

@@ -541,9 +541,9 @@ add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY
# Adjustments for MSVC + Ninja
if (MSVC AND CMAKE_GENERATOR STREQUAL "Ninja")
add_compile_options(
/wd4711 # function 'function' selected for automatic inline expansion
/wd4464 # relative include path contains '..'
/wd4820 # 'identifier1': '4' bytes padding added after data member 'identifier2'
/wd4711 # function 'function' selected for automatic inline expansion
/wd4820 # 'bytes' bytes padding added after construct 'member_name'
)
endif()

View File

@@ -58,13 +58,11 @@ if (MSVC)
# Warnings
/W3
/we4018 # 'expression': signed/unsigned mismatch
/WX
/we4062 # Enumerator 'identifier' in a switch of enum 'enumeration' is not handled
/we4101 # 'identifier': unreferenced local variable
/we4189 # 'identifier': local variable is initialized but not referenced
/we4265 # 'class': class has virtual functions, but destructor is not virtual
/we4267 # 'var': conversion from 'size_t' to 'type', possible loss of data
/we4305 # 'context': truncation from 'type1' to 'type2'
/we4388 # 'expression': signed/unsigned mismatch
/we4389 # 'operator': signed/unsigned mismatch
/we4456 # Declaration of 'identifier' hides previous local declaration
@@ -75,10 +73,13 @@ if (MSVC)
/we4547 # 'operator': operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
/we4555 # Expression has no effect; expected expression with side-effect
/we4715 # 'function': not all control paths return a value
/we4834 # Discarding return value of function with 'nodiscard' attribute
/we4826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior.
/we5038 # data member 'member1' will be initialized after data member 'member2'
/we5233 # explicit lambda capture 'identifier' is not used
/we5245 # 'function': unreferenced function with internal linkage has been removed
/wd4100 # 'identifier': unreferenced formal parameter
/wd4324 # 'struct_name': structure was padded due to __declspec(align())
)
if (USE_CCACHE)
@@ -99,24 +100,18 @@ if (MSVC)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE)
else()
add_compile_options(
-Wall
-Werror=array-bounds
-Werror=implicit-fallthrough
-Werror=all
-Werror=extra
-Werror=missing-declarations
-Werror=missing-field-initializers
-Werror=reorder
-Werror=shadow
-Werror=sign-compare
-Werror=switch
-Werror=uninitialized
-Werror=unused-function
-Werror=unused-result
-Werror=unused-variable
-Wextra
-Wmissing-declarations
-Werror=unused
-Wno-attributes
-Wno-invalid-offsetof
-Wno-unused-parameter
$<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
$<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
)
if (ARCHITECTURE_x86_64)

View File

@@ -206,20 +206,11 @@ if (MSVC)
/we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data
/we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/we4456 # Declaration of 'identifier' hides previous local declaration
/we4457 # Declaration of 'identifier' hides function parameter
/we4458 # Declaration of 'identifier' hides class member
/we4459 # Declaration of 'identifier' hides global declaration
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
)
else()
target_compile_options(audio_core PRIVATE
-Werror=conversion
-Werror=ignored-qualifiers
-Werror=shadow
-Werror=unused-variable
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
-Wno-sign-conversion
)

View File

@@ -56,7 +56,7 @@ Result System::IsConfigValid(const std::string_view device_name,
return ResultSuccess;
}
Result System::Initialize(std::string& device_name, const AudioInParameter& in_params,
Result System::Initialize(std::string device_name, const AudioInParameter& in_params,
const u32 handle_, const u64 applet_resource_user_id_) {
auto result{IsConfigValid(device_name, in_params)};
if (result.IsError()) {

View File

@@ -97,7 +97,7 @@ public:
* @param applet_resource_user_id - Unused.
* @return Result code.
*/
Result Initialize(std::string& device_name, const AudioInParameter& in_params, u32 handle,
Result Initialize(std::string device_name, const AudioInParameter& in_params, u32 handle,
u64 applet_resource_user_id);
/**

View File

@@ -49,8 +49,8 @@ Result System::IsConfigValid(std::string_view device_name,
return Service::Audio::ERR_INVALID_CHANNEL_COUNT;
}
Result System::Initialize(std::string& device_name, const AudioOutParameter& in_params, u32 handle_,
u64& applet_resource_user_id_) {
Result System::Initialize(std::string device_name, const AudioOutParameter& in_params, u32 handle_,
u64 applet_resource_user_id_) {
auto result = IsConfigValid(device_name, in_params);
if (result.IsError()) {
return result;

View File

@@ -88,8 +88,8 @@ public:
* @param applet_resource_user_id - Unused.
* @return Result code.
*/
Result Initialize(std::string& device_name, const AudioOutParameter& in_params, u32 handle,
u64& applet_resource_user_id);
Result Initialize(std::string device_name, const AudioOutParameter& in_params, u32 handle,
u64 applet_resource_user_id);
/**
* Start this system.

View File

@@ -91,7 +91,7 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
voice_info.Initialize();
for (u32 channel = 0; channel < in_param.channel_count; channel++) {
std::memset(voice_states[channel], 0, sizeof(VoiceState));
*voice_states[channel] = {};
}
}

View File

@@ -94,7 +94,7 @@ void BiquadFilterCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor
void BiquadFilterCommand::Process(const ADSP::CommandListProcessor& processor) {
auto state_{reinterpret_cast<VoiceState::BiquadFilterState*>(state)};
if (needs_init) {
std::memset(state_, 0, sizeof(VoiceState::BiquadFilterState));
*state_ = {};
}
auto input_buffer{

View File

@@ -30,7 +30,7 @@ void MultiTapBiquadFilterCommand::Process(const ADSP::CommandListProcessor& proc
for (u32 i = 0; i < filter_tap_count; i++) {
auto state{reinterpret_cast<VoiceState::BiquadFilterState*>(states[i])};
if (needs_init[i]) {
std::memset(state, 0, sizeof(VoiceState::BiquadFilterState));
*state = {};
}
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state,

View File

@@ -156,12 +156,13 @@ if (MSVC)
)
target_compile_options(common PRIVATE
/W4
/WX
/we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
)
else()
target_compile_options(common PRIVATE
-Werror
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
)
endif()

View File

@@ -141,10 +141,6 @@ public:
constexpr BitField(BitField&&) noexcept = default;
constexpr BitField& operator=(BitField&&) noexcept = default;
[[nodiscard]] constexpr operator T() const {
return Value();
}
constexpr void Assign(const T& value) {
#ifdef _MSC_VER
storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value));
@@ -162,6 +158,17 @@ public:
return ExtractValue(storage);
}
template <typename ConvertedToType>
[[nodiscard]] constexpr ConvertedToType As() const {
static_assert(!std::is_same_v<T, ConvertedToType>,
"Unnecessary cast. Use Value() instead.");
return static_cast<ConvertedToType>(Value());
}
[[nodiscard]] constexpr operator T() const {
return Value();
}
[[nodiscard]] constexpr explicit operator bool() const {
return Value() != 0;
}

View File

@@ -21,11 +21,6 @@ constexpr size_t hardware_interference_size = std::hardware_destructive_interfer
constexpr size_t hardware_interference_size = 64;
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4324)
#endif
template <typename T, size_t capacity = 0x400>
class MPSCQueue {
public:
@@ -160,8 +155,4 @@ private:
static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible");
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
} // namespace Common

View File

@@ -3,24 +3,14 @@
#pragma once
#include <iterator>
#include <type_traits>
namespace Common {
// Check if type is like an STL container
// Check if type satisfies the ContiguousContainer named requirement.
template <typename T>
concept IsSTLContainer = requires(T t) {
typename T::value_type;
typename T::iterator;
typename T::const_iterator;
// TODO(ogniK): Replace below is std::same_as<void> when MSVC supports it.
t.begin();
t.end();
t.cbegin();
t.cend();
t.data();
t.size();
};
concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>;
// TODO: Replace with std::derived_from when the <concepts> header
// is available on all supported platforms.

View File

@@ -209,8 +209,8 @@ public:
/**
* Helper function which deduces the value type of a contiguous STL container used in ReadSpan.
* If T is not a contiguous STL container as defined by the concept IsSTLContainer, this calls
* ReadObject and T must be a trivially copyable object.
* If T is not a contiguous container as defined by the concept IsContiguousContainer, this
* calls ReadObject and T must be a trivially copyable object.
*
* See ReadSpan for more details if T is a contiguous container.
* See ReadObject for more details if T is a trivially copyable object.
@@ -223,7 +223,7 @@ public:
*/
template <typename T>
[[nodiscard]] size_t Read(T& data) const {
if constexpr (IsSTLContainer<T>) {
if constexpr (IsContiguousContainer<T>) {
using ContiguousType = typename T::value_type;
static_assert(std::is_trivially_copyable_v<ContiguousType>,
"Data type must be trivially copyable.");
@@ -235,8 +235,8 @@ public:
/**
* Helper function which deduces the value type of a contiguous STL container used in WriteSpan.
* If T is not a contiguous STL container as defined by the concept IsSTLContainer, this calls
* WriteObject and T must be a trivially copyable object.
* If T is not a contiguous STL container as defined by the concept IsContiguousContainer, this
* calls WriteObject and T must be a trivially copyable object.
*
* See WriteSpan for more details if T is a contiguous container.
* See WriteObject for more details if T is a trivially copyable object.
@@ -249,7 +249,7 @@ public:
*/
template <typename T>
[[nodiscard]] size_t Write(const T& data) const {
if constexpr (IsSTLContainer<T>) {
if constexpr (IsContiguousContainer<T>) {
using ContiguousType = typename T::value_type;
static_assert(std::is_trivially_copyable_v<ContiguousType>,
"Data type must be trivially copyable.");

View File

@@ -100,7 +100,6 @@ enum class CameraError {
enum class VibrationAmplificationType {
Linear,
Exponential,
Test,
};
// Analog properties for calibration
@@ -325,6 +324,10 @@ public:
return VibrationError::NotSupported;
}
virtual bool IsVibrationEnabled() {
return false;
}
virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
return PollingError::NotSupported;
}

View File

@@ -774,19 +774,15 @@ if (MSVC)
/we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data
/we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
)
else()
target_compile_options(core PRIVATE
-Werror=conversion
-Werror=ignored-qualifiers
$<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
-Wno-sign-conversion
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
)
endif()

View File

@@ -450,7 +450,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::S
// Frame records are two words long:
// fp+0 : pointer to previous frame record
// fp+4 : value of lr for frame
while (true) {
for (size_t i = 0; i < 256; i++) {
out.push_back({"", 0, lr, 0, ""});
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
break;

View File

@@ -517,7 +517,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S
// Frame records are two words long:
// fp+0 : pointer to previous frame record
// fp+8 : value of lr for frame
while (true) {
for (size_t i = 0; i < 256; i++) {
out.push_back({"", 0, lr, 0, ""});
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
break;

View File

@@ -384,6 +384,7 @@ struct System::Impl {
kernel.ShutdownCores();
cpu_manager.Shutdown();
debugger.reset();
services->KillNVNFlinger();
kernel.CloseServices();
services.reset();
service_manager.reset();

View File

@@ -232,8 +232,8 @@ const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const {
std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const {
const auto program_id = secure_partition->GetProgramTitleID();
const auto iter = std::find_if(
ncas.begin(), ncas.end(), [this, type, program_id](const std::shared_ptr<NCA>& nca) {
const auto iter =
std::find_if(ncas.begin(), ncas.end(), [type, program_id](const std::shared_ptr<NCA>& nca) {
return nca->GetType() == type && nca->GetTitleId() == program_id;
});
return iter == ncas.end() ? nullptr : *iter;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "common/string_util.h"
#include "common/swap.h"
#include "core/file_sys/control_metadata.h"
@@ -37,6 +38,27 @@ std::string LanguageEntry::GetDeveloperName() const {
developer_name.size());
}
constexpr std::array<Language, 18> language_to_codes = {{
Language::Japanese,
Language::AmericanEnglish,
Language::French,
Language::German,
Language::Italian,
Language::Spanish,
Language::Chinese,
Language::Korean,
Language::Dutch,
Language::Portuguese,
Language::Russian,
Language::Taiwanese,
Language::BritishEnglish,
Language::CanadianFrench,
Language::LatinAmericanSpanish,
Language::Chinese,
Language::Taiwanese,
Language::BrazilianPortuguese,
}};
NACP::NACP() = default;
NACP::NACP(VirtualFile file) {
@@ -45,9 +67,13 @@ NACP::NACP(VirtualFile file) {
NACP::~NACP() = default;
const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
if (language != Language::Default) {
return raw.language_entries.at(static_cast<u8>(language));
const LanguageEntry& NACP::GetLanguageEntry() const {
Language language = language_to_codes[Settings::values.language_index.GetValue()];
{
const auto& language_entry = raw.language_entries.at(static_cast<u8>(language));
if (!language_entry.GetApplicationName().empty())
return language_entry;
}
for (const auto& language_entry : raw.language_entries) {
@@ -55,16 +81,15 @@ const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
return language_entry;
}
// Fallback to English
return GetLanguageEntry(Language::AmericanEnglish);
return raw.language_entries.at(static_cast<u8>(Language::AmericanEnglish));
}
std::string NACP::GetApplicationName(Language language) const {
return GetLanguageEntry(language).GetApplicationName();
std::string NACP::GetApplicationName() const {
return GetLanguageEntry().GetApplicationName();
}
std::string NACP::GetDeveloperName(Language language) const {
return GetLanguageEntry(language).GetDeveloperName();
std::string NACP::GetDeveloperName() const {
return GetLanguageEntry().GetDeveloperName();
}
u64 NACP::GetTitleId() const {

View File

@@ -101,9 +101,9 @@ public:
explicit NACP(VirtualFile file);
~NACP();
const LanguageEntry& GetLanguageEntry(Language language = Language::Default) const;
std::string GetApplicationName(Language language = Language::Default) const;
std::string GetDeveloperName(Language language = Language::Default) const;
const LanguageEntry& GetLanguageEntry() const;
std::string GetApplicationName() const;
std::string GetDeveloperName() const;
u64 GetTitleId() const;
u64 GetDLCBaseTitleId() const;
std::string GetVersionString() const;

View File

@@ -127,7 +127,7 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address
}
bool ProgramMetadata::Is64BitProgram() const {
return npdm_header.has_64_bit_instructions;
return npdm_header.has_64_bit_instructions.As<bool>();
}
ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const {

View File

@@ -970,14 +970,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
Common::Input::VibrationError::None;
}
bool EmulatedController::TestVibration(std::size_t device_index) {
if (device_index >= output_devices.size()) {
return false;
}
if (!output_devices[device_index]) {
return false;
}
bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
const auto player_index = NpadIdTypeToIndex(npad_id_type);
const auto& player = Settings::values.players.GetValue()[player_index];
@@ -985,31 +978,15 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
return false;
}
const Common::Input::VibrationStatus test_vibration = {
.low_amplitude = 0.001f,
.low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency,
.high_amplitude = 0.001f,
.high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency,
.type = Common::Input::VibrationAmplificationType::Test,
};
if (device_index >= output_devices.size()) {
return false;
}
const Common::Input::VibrationStatus zero_vibration = {
.low_amplitude = DEFAULT_VIBRATION_VALUE.low_amplitude,
.low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency,
.high_amplitude = DEFAULT_VIBRATION_VALUE.high_amplitude,
.high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency,
.type = Common::Input::VibrationAmplificationType::Test,
};
if (!output_devices[device_index]) {
return false;
}
// Send a slight vibration to test for rumble support
output_devices[device_index]->SetVibration(test_vibration);
// Wait for about 15ms to ensure the controller is ready for the stop command
std::this_thread::sleep_for(std::chrono::milliseconds(15));
// Stop any vibration and return the result
return output_devices[device_index]->SetVibration(zero_vibration) ==
Common::Input::VibrationError::None;
return output_devices[device_index]->IsVibrationEnabled();
}
bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
@@ -1048,6 +1025,7 @@ bool EmulatedController::HasNfc() const {
case NpadStyleIndex::JoyconRight:
case NpadStyleIndex::JoyconDual:
case NpadStyleIndex::ProController:
case NpadStyleIndex::Handheld:
break;
default:
return false;
@@ -1158,27 +1136,27 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
switch (type) {
case NpadStyleIndex::ProController:
return supported_style_tag.fullkey;
return supported_style_tag.fullkey.As<bool>();
case NpadStyleIndex::Handheld:
return supported_style_tag.handheld;
return supported_style_tag.handheld.As<bool>();
case NpadStyleIndex::JoyconDual:
return supported_style_tag.joycon_dual;
return supported_style_tag.joycon_dual.As<bool>();
case NpadStyleIndex::JoyconLeft:
return supported_style_tag.joycon_left;
return supported_style_tag.joycon_left.As<bool>();
case NpadStyleIndex::JoyconRight:
return supported_style_tag.joycon_right;
return supported_style_tag.joycon_right.As<bool>();
case NpadStyleIndex::GameCube:
return supported_style_tag.gamecube;
return supported_style_tag.gamecube.As<bool>();
case NpadStyleIndex::Pokeball:
return supported_style_tag.palma;
return supported_style_tag.palma.As<bool>();
case NpadStyleIndex::NES:
return supported_style_tag.lark;
return supported_style_tag.lark.As<bool>();
case NpadStyleIndex::SNES:
return supported_style_tag.lucia;
return supported_style_tag.lucia.As<bool>();
case NpadStyleIndex::N64:
return supported_style_tag.lagoon;
return supported_style_tag.lagoon.As<bool>();
case NpadStyleIndex::SegaGenesis:
return supported_style_tag.lager;
return supported_style_tag.lager.As<bool>();
default:
return false;
}
@@ -1234,12 +1212,6 @@ bool EmulatedController::IsConnected(bool get_temporary_value) const {
return is_connected;
}
bool EmulatedController::IsVibrationEnabled() const {
const auto player_index = NpadIdTypeToIndex(npad_id_type);
const auto& player = Settings::values.players.GetValue()[player_index];
return player.vibration_enabled;
}
NpadIdType EmulatedController::GetNpadIdType() const {
std::scoped_lock lock{mutex};
return npad_id_type;

View File

@@ -206,9 +206,6 @@ public:
*/
bool IsConnected(bool get_temporary_value = false) const;
/// Returns true if vibration is enabled
bool IsVibrationEnabled() const;
/// Removes all callbacks created from input devices
void UnloadInput();
@@ -339,7 +336,7 @@ public:
* Sends a small vibration to the output device
* @return true if SetVibration was successfull
*/
bool TestVibration(std::size_t device_index);
bool IsVibrationEnabled(std::size_t device_index);
/**
* Sets the desired data to be polled from a controller

View File

@@ -406,7 +406,7 @@ inline s32 RequestParser::Pop() {
}
// Ignore the -Wclass-memaccess warning on memcpy for non-trivially default constructible objects.
#if defined(__GNUC__)
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
@@ -417,7 +417,7 @@ void RequestParser::PopRaw(T& value) {
std::memcpy(&value, cmdbuf + index, sizeof(T));
index += (sizeof(T) + 3) / 4; // round up to word length
}
#if defined(__GNUC__)
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
#pragma GCC diagnostic pop
#endif

View File

@@ -49,4 +49,26 @@ bool GlobalSchedulerContext::IsLocked() const {
return scheduler_lock.IsLockedByCurrentThread();
}
void GlobalSchedulerContext::RegisterDummyThreadForWakeup(KThread* thread) {
ASSERT(IsLocked());
woken_dummy_threads.insert(thread);
}
void GlobalSchedulerContext::UnregisterDummyThreadForWakeup(KThread* thread) {
ASSERT(IsLocked());
woken_dummy_threads.erase(thread);
}
void GlobalSchedulerContext::WakeupWaitingDummyThreads() {
ASSERT(IsLocked());
for (auto* thread : woken_dummy_threads) {
thread->DummyThreadEndWait();
}
woken_dummy_threads.clear();
}
} // namespace Kernel

View File

@@ -4,6 +4,7 @@
#pragma once
#include <atomic>
#include <set>
#include <vector>
#include "common/common_types.h"
@@ -58,6 +59,10 @@ public:
/// Returns true if the global scheduler lock is acquired
bool IsLocked() const;
void UnregisterDummyThreadForWakeup(KThread* thread);
void RegisterDummyThreadForWakeup(KThread* thread);
void WakeupWaitingDummyThreads();
[[nodiscard]] LockType& SchedulerLock() {
return scheduler_lock;
}
@@ -76,6 +81,9 @@ private:
KSchedulerPriorityQueue priority_queue;
LockType scheduler_lock;
/// Lists dummy threads pending wakeup on lock release
std::set<KThread*> woken_dummy_threads;
/// Lists all thread ids that aren't deleted/etc.
std::vector<KThread*> thread_list;
std::mutex global_list_guard;

View File

@@ -304,7 +304,7 @@ public:
*/
template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>>
std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const {
if constexpr (Common::IsSTLContainer<T>) {
if constexpr (Common::IsContiguousContainer<T>) {
using ContiguousType = typename T::value_type;
static_assert(std::is_trivially_copyable_v<ContiguousType>,
"Container to WriteBuffer must contain trivially copyable objects");

View File

@@ -81,8 +81,8 @@ void KScheduler::RescheduleCurrentHLEThread(KernelCore& kernel) {
// HACK: we cannot schedule from this thread, it is not a core thread
ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
// Special case to ensure dummy threads that are waiting block
GetCurrentThread(kernel).IfDummyThreadTryWait();
// Ensure dummy threads that are waiting block.
GetCurrentThread(kernel).DummyThreadBeginWait();
ASSERT(GetCurrentThread(kernel).GetState() != ThreadState::Waiting);
GetCurrentThread(kernel).EnableDispatch();
@@ -314,6 +314,16 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
idle_cores &= ~(1ULL << core_id);
}
// HACK: any waiting dummy threads can wake up now.
kernel.GlobalSchedulerContext().WakeupWaitingDummyThreads();
// HACK: if we are a dummy thread, and we need to go sleep, indicate
// that for when the lock is released.
KThread* const cur_thread = GetCurrentThreadPointer(kernel);
if (cur_thread->IsDummyThread() && cur_thread->GetState() != ThreadState::Runnable) {
cur_thread->RequestDummyThreadWait();
}
return cores_needing_scheduling;
}
@@ -531,11 +541,23 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, Threa
GetPriorityQueue(kernel).Remove(thread);
IncrementScheduledCount(thread);
SetSchedulerUpdateNeeded(kernel);
if (thread->IsDummyThread()) {
// HACK: if this is a dummy thread, it should no longer wake up when the
// scheduler lock is released.
kernel.GlobalSchedulerContext().UnregisterDummyThreadForWakeup(thread);
}
} else if (cur_state == ThreadState::Runnable) {
// If we're now runnable, then we weren't previously, and we should add.
GetPriorityQueue(kernel).PushBack(thread);
IncrementScheduledCount(thread);
SetSchedulerUpdateNeeded(kernel);
if (thread->IsDummyThread()) {
// HACK: if this is a dummy thread, it should wake up when the scheduler
// lock is released.
kernel.GlobalSchedulerContext().RegisterDummyThreadForWakeup(thread);
}
}
}

View File

@@ -3,6 +3,8 @@
#pragma once
#include <array>
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_memory_block.h"
@@ -52,8 +54,7 @@ public:
};
public:
explicit SessionMappings(KernelCore& kernel_)
: kernel(kernel_), m_mappings(nullptr), m_num_send(), m_num_recv(), m_num_exch() {}
explicit SessionMappings(KernelCore& kernel_) : kernel(kernel_) {}
void Initialize() {}
void Finalize();
@@ -149,17 +150,15 @@ public:
private:
KernelCore& kernel;
Mapping m_static_mappings[NumStaticMappings];
Mapping* m_mappings;
u8 m_num_send;
u8 m_num_recv;
u8 m_num_exch;
std::array<Mapping, NumStaticMappings> m_static_mappings;
Mapping* m_mappings{};
u8 m_num_send{};
u8 m_num_recv{};
u8 m_num_exch{};
};
public:
explicit KSessionRequest(KernelCore& kernel_)
: KAutoObject(kernel_), m_mappings(kernel_), m_thread(nullptr), m_server(nullptr),
m_event(nullptr) {}
explicit KSessionRequest(KernelCore& kernel_) : KAutoObject(kernel_), m_mappings(kernel_) {}
static KSessionRequest* Create(KernelCore& kernel) {
KSessionRequest* req = KSessionRequest::Allocate(kernel);
@@ -281,7 +280,7 @@ public:
private:
// NOTE: This is public and virtual in Nintendo's kernel.
void Finalize() {
void Finalize() override {
m_mappings.Finalize();
if (m_thread) {
@@ -297,11 +296,11 @@ private:
private:
SessionMappings m_mappings;
KThread* m_thread;
KProcess* m_server;
KEvent* m_event;
uintptr_t m_address;
size_t m_size;
KThread* m_thread{};
KProcess* m_server{};
KEvent* m_event{};
uintptr_t m_address{};
size_t m_size{};
};
} // namespace Kernel

View File

@@ -148,7 +148,9 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
physical_affinity_mask.SetAffinity(phys_core, true);
// Set the thread state.
thread_state = (type == ThreadType::Main) ? ThreadState::Runnable : ThreadState::Initialized;
thread_state = (type == ThreadType::Main || type == ThreadType::Dummy)
? ThreadState::Runnable
: ThreadState::Initialized;
// Set TLS address.
tls_address = 0;
@@ -1174,30 +1176,29 @@ Result KThread::Sleep(s64 timeout) {
R_SUCCEED();
}
void KThread::IfDummyThreadTryWait() {
if (!IsDummyThread()) {
return;
}
void KThread::RequestDummyThreadWait() {
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
ASSERT(this->IsDummyThread());
if (GetState() != ThreadState::Waiting) {
return;
}
ASSERT(!kernel.IsPhantomModeForSingleCore());
// Block until we are no longer waiting.
std::unique_lock lk(dummy_wait_lock);
dummy_wait_cv.wait(
lk, [&] { return GetState() != ThreadState::Waiting || kernel.IsShuttingDown(); });
// We will block when the scheduler lock is released.
dummy_thread_runnable.store(false);
}
void KThread::IfDummyThreadEndWait() {
if (!IsDummyThread()) {
return;
}
void KThread::DummyThreadBeginWait() {
ASSERT(this->IsDummyThread());
ASSERT(!kernel.IsPhantomModeForSingleCore());
// Block until runnable is no longer false.
dummy_thread_runnable.wait(false);
}
void KThread::DummyThreadEndWait() {
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
ASSERT(this->IsDummyThread());
// Wake up the waiting thread.
dummy_wait_cv.notify_one();
dummy_thread_runnable.store(true);
dummy_thread_runnable.notify_one();
}
void KThread::BeginWait(KThreadQueue* queue) {
@@ -1231,9 +1232,6 @@ void KThread::EndWait(Result wait_result_) {
}
wait_queue->EndWait(this, wait_result_);
// Special case for dummy threads to wakeup if necessary.
IfDummyThreadEndWait();
}
}

View File

@@ -643,8 +643,9 @@ public:
// therefore will not block on guest kernel synchronization primitives. These methods handle
// blocking as needed.
void IfDummyThreadTryWait();
void IfDummyThreadEndWait();
void RequestDummyThreadWait();
void DummyThreadBeginWait();
void DummyThreadEndWait();
[[nodiscard]] uintptr_t GetArgument() const {
return argument;
@@ -777,8 +778,7 @@ private:
bool is_single_core{};
ThreadType thread_type{};
StepState step_state{};
std::mutex dummy_wait_lock;
std::condition_variable dummy_wait_cv;
std::atomic<bool> dummy_thread_runnable{true};
// For debugging
std::vector<KSynchronizationObject*> wait_objects_for_debugging;

View File

@@ -48,8 +48,8 @@ namespace Kernel {
struct KernelCore::Impl {
explicit Impl(Core::System& system_, KernelCore& kernel_)
: time_manager{system_},
service_threads_manager{1, "ServiceThreadsManager"}, system{system_} {}
: time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"},
service_thread_barrier{2}, system{system_} {}
void SetMulticore(bool is_multi) {
is_multicore = is_multi;
@@ -737,7 +737,12 @@ struct KernelCore::Impl {
}
void ClearServiceThreads() {
service_threads_manager.QueueWork([this]() { service_threads.clear(); });
service_threads_manager.QueueWork([this] {
service_threads.clear();
default_service_thread.reset();
service_thread_barrier.Sync();
});
service_thread_barrier.Sync();
}
std::mutex server_objects_lock;
@@ -802,6 +807,7 @@ struct KernelCore::Impl {
std::unordered_set<std::shared_ptr<ServiceThread>> service_threads;
std::weak_ptr<ServiceThread> default_service_thread;
Common::ThreadWorker service_threads_manager;
Common::Barrier service_thread_barrier;
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};

View File

@@ -751,8 +751,8 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
}
system.GetReporter().SaveSvcBreakReport(
static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger, info1,
info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger.As<bool>(),
info1, info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
if (!break_reason.signal_debugger) {
LOG_CRITICAL(

View File

@@ -164,7 +164,7 @@ protected:
u32_le size;
u32_le library_version;
u32_le theme_color;
u8 play_startup_sound;
bool play_startup_sound;
u64_le system_tick;
};
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");

View File

@@ -17,7 +17,7 @@ using namespace AudioCore::AudioIn;
class IAudioIn final : public ServiceFramework<IAudioIn> {
public:
explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
std::string& device_name, const AudioInParameter& in_params, u32 handle,
const std::string& device_name, const AudioInParameter& in_params, u32 handle,
u64 applet_resource_user_id)
: ServiceFramework{system_, "IAudioIn"},
service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")},

View File

@@ -24,7 +24,7 @@ using namespace AudioCore::AudioOut;
class IAudioOut final : public ServiceFramework<IAudioOut> {
public:
explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
size_t session_id, std::string& device_name,
size_t session_id, const std::string& device_name,
const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id)
: ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew},
service_context{system_, "IAudioOut"}, event{service_context.CreateEvent(

View File

@@ -745,8 +745,9 @@ void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
}
void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
ASSERT(max_length < supported_npad_id_types.size());
std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
const auto copy_amount = supported_npad_id_types.size() * sizeof(u32);
ASSERT(max_length <= copy_amount);
std::memcpy(data, supported_npad_id_types.data(), copy_amount);
}
std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {
@@ -867,7 +868,7 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
return false;
}
if (!controller.device->IsVibrationEnabled()) {
if (!controller.device->IsVibrationEnabled(device_index)) {
if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f ||
controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) {
// Send an empty vibration to stop any vibrations.
@@ -1000,7 +1001,7 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npa
}
controller.vibration[device_index].device_mounted =
controller.device->TestVibration(device_index);
controller.device->IsVibrationEnabled(device_index);
}
void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
@@ -1501,25 +1502,25 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller
Core::HID::NpadStyleTag style = GetSupportedStyleSet();
switch (controller) {
case Core::HID::NpadStyleIndex::ProController:
return style.fullkey;
return style.fullkey.As<bool>();
case Core::HID::NpadStyleIndex::JoyconDual:
return style.joycon_dual;
return style.joycon_dual.As<bool>();
case Core::HID::NpadStyleIndex::JoyconLeft:
return style.joycon_left;
return style.joycon_left.As<bool>();
case Core::HID::NpadStyleIndex::JoyconRight:
return style.joycon_right;
return style.joycon_right.As<bool>();
case Core::HID::NpadStyleIndex::GameCube:
return style.gamecube;
return style.gamecube.As<bool>();
case Core::HID::NpadStyleIndex::Pokeball:
return style.palma;
return style.palma.As<bool>();
case Core::HID::NpadStyleIndex::NES:
return style.lark;
return style.lark.As<bool>();
case Core::HID::NpadStyleIndex::SNES:
return style.lucia;
return style.lucia.As<bool>();
case Core::HID::NpadStyleIndex::N64:
return style.lagoon;
return style.lagoon.As<bool>();
case Core::HID::NpadStyleIndex::SegaGenesis:
return style.lager;
return style.lager.As<bool>();
default:
return false;
}

View File

@@ -9,6 +9,7 @@
#include <mbedtls/hmac_drbg.h>
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "core/hle/service/mii/mii_manager.h"
@@ -279,7 +280,7 @@ bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) {
Common::FS::FileType::BinaryFile};
if (!keys_file.IsOpen()) {
LOG_ERROR(Service_NFP, "No keys detected");
LOG_ERROR(Service_NFP, "Failed to open key file");
return false;
}
@@ -295,6 +296,11 @@ bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) {
return true;
}
bool IsKeyAvailable() {
const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
return Common::FS::Exists(yuzu_keys_dir / "key_retail.bin");
}
bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data) {
InternalKey locked_secret{};
InternalKey unfixed_info{};

View File

@@ -91,6 +91,9 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
/// Loads both amiibo keys from key_retail.bin
bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info);
/// Returns true if key_retail.bin exist
bool IsKeyAvailable();
/// Decodes encripted amiibo data returns true if output is valid
bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data);

View File

@@ -17,6 +17,7 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/mii/types.h"
#include "core/hle/service/nfp/amiibo_crypto.h"
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nfp/nfp_device.h"
@@ -233,6 +234,14 @@ Result NfpDevice::Mount(MountTarget mount_target_) {
return NotAnAmiibo;
}
// Mark amiibos as read only when keys are missing
if (!AmiiboCrypto::IsKeyAvailable()) {
LOG_ERROR(Service_NFP, "No keys detected");
device_state = DeviceState::TagMounted;
mount_target = MountTarget::Rom;
return ResultSuccess;
}
if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
return CorruptedData;

View File

@@ -8,7 +8,6 @@
#include "common/common_funcs.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/mii/types.h"
#include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h"

View File

@@ -17,11 +17,6 @@ enum class ServiceType : u32 {
System,
};
enum class State : u32 {
NonInitialized,
Initialized,
};
enum class DeviceState : u32 {
Initialized,
SearchingForTag,

View File

@@ -6,12 +6,9 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/nfp/nfp_device.h"
#include "core/hle/service/nfp/nfp_result.h"
#include "core/hle/service/nfp/nfp_user.h"

View File

@@ -4,8 +4,7 @@
#pragma once
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h"
namespace Service::NFP {
class NfpDevice;
@@ -15,6 +14,11 @@ public:
explicit IUser(Core::System& system_);
private:
enum class State : u32 {
NonInitialized,
Initialized,
};
void Initialize(Kernel::HLERequestContext& ctx);
void Finalize(Kernel::HLERequestContext& ctx);
void ListDevices(Kernel::HLERequestContext& ctx);

View File

@@ -53,7 +53,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
}
Module::Module(Core::System& system)
: service_context{system, "nvdrv"}, events_interface{*this}, container{system.Host1x()} {
: container{system.Host1x()}, service_context{system, "nvdrv"}, events_interface{*this} {
builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) {
std::shared_ptr<Devices::nvdevice> device =
std::make_shared<Devices::nvhost_as_gpu>(system, *this, container);

View File

@@ -97,6 +97,9 @@ private:
friend class EventInterface;
friend class Service::NVFlinger::NVFlinger;
/// Manages syncpoints on the host
NvCore::Container container;
/// Id to use for the next open file descriptor.
DeviceFD next_fd = 1;
@@ -108,9 +111,6 @@ private:
EventInterface events_interface;
/// Manages syncpoints on the host
NvCore::Container container;
std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders;
};

View File

@@ -102,15 +102,19 @@ NVFlinger::~NVFlinger() {
system.CoreTiming().UnscheduleEvent(single_composition_event, {});
}
ShutdownLayers();
if (nvdrv) {
nvdrv->Close(disp_fd);
}
}
void NVFlinger::ShutdownLayers() {
for (auto& display : displays) {
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
display.GetLayer(layer).Core().NotifyShutdown();
}
}
if (nvdrv) {
nvdrv->Close(disp_fd);
}
}
void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {

View File

@@ -48,6 +48,8 @@ public:
explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
~NVFlinger();
void ShutdownLayers();
/// Sets the NVDrv module instance to use to send buffers to the GPU.
void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);

View File

@@ -303,4 +303,8 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
Services::~Services() = default;
void Services::KillNVNFlinger() {
nv_flinger->ShutdownLayers();
}
} // namespace Service

View File

@@ -238,6 +238,8 @@ public:
explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
~Services();
void KillNVNFlinger();
private:
std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server;
std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;

View File

@@ -233,18 +233,17 @@ struct Memory::Impl {
current_vaddr, src_addr, size);
std::memset(dest_buffer, 0, copy_amount);
},
[&dest_buffer](const std::size_t copy_amount, const u8* const src_ptr) {
[&](const std::size_t copy_amount, const u8* const src_ptr) {
std::memcpy(dest_buffer, src_ptr, copy_amount);
},
[&system = system, &dest_buffer](const VAddr current_vaddr,
const std::size_t copy_amount,
const u8* const host_ptr) {
[&](const VAddr current_vaddr, const std::size_t copy_amount,
const u8* const host_ptr) {
if constexpr (!UNSAFE) {
system.GPU().FlushRegion(current_vaddr, copy_amount);
}
std::memcpy(dest_buffer, host_ptr, copy_amount);
},
[&dest_buffer](const std::size_t copy_amount) {
[&](const std::size_t copy_amount) {
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
});
}
@@ -267,17 +266,16 @@ struct Memory::Impl {
"Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, dest_addr, size);
},
[&src_buffer](const std::size_t copy_amount, u8* const dest_ptr) {
[&](const std::size_t copy_amount, u8* const dest_ptr) {
std::memcpy(dest_ptr, src_buffer, copy_amount);
},
[&system = system, &src_buffer](const VAddr current_vaddr,
const std::size_t copy_amount, u8* const host_ptr) {
[&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) {
if constexpr (!UNSAFE) {
system.GPU().InvalidateRegion(current_vaddr, copy_amount);
}
std::memcpy(host_ptr, src_buffer, copy_amount);
},
[&src_buffer](const std::size_t copy_amount) {
[&](const std::size_t copy_amount) {
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
});
}
@@ -301,8 +299,7 @@ struct Memory::Impl {
[](const std::size_t copy_amount, u8* const dest_ptr) {
std::memset(dest_ptr, 0, copy_amount);
},
[&system = system](const VAddr current_vaddr, const std::size_t copy_amount,
u8* const host_ptr) {
[&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) {
system.GPU().InvalidateRegion(current_vaddr, copy_amount);
std::memset(host_ptr, 0, copy_amount);
},
@@ -313,22 +310,20 @@ struct Memory::Impl {
const std::size_t size) {
WalkBlock(
process, dest_addr, size,
[this, &process, &dest_addr, &src_addr, size](const std::size_t copy_amount,
const VAddr current_vaddr) {
[&](const std::size_t copy_amount, const VAddr current_vaddr) {
LOG_ERROR(HW_Memory,
"Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, src_addr, size);
ZeroBlock(process, dest_addr, copy_amount);
},
[this, &process, &dest_addr](const std::size_t copy_amount, const u8* const src_ptr) {
[&](const std::size_t copy_amount, const u8* const src_ptr) {
WriteBlockImpl<false>(process, dest_addr, src_ptr, copy_amount);
},
[this, &system = system, &process, &dest_addr](
const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) {
[&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) {
system.GPU().FlushRegion(current_vaddr, copy_amount);
WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount);
},
[&dest_addr, &src_addr](const std::size_t copy_amount) {
[&](const std::size_t copy_amount) {
dest_addr += static_cast<VAddr>(copy_amount);
src_addr += static_cast<VAddr>(copy_amount);
});
@@ -575,7 +570,7 @@ struct Memory::Impl {
[vaddr]() {
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, vaddr);
},
[&system = system, vaddr]() { system.GPU().FlushRegion(vaddr, sizeof(T)); });
[&]() { system.GPU().FlushRegion(vaddr, sizeof(T)); });
if (ptr) {
std::memcpy(&result, ptr, sizeof(T));
}
@@ -599,7 +594,7 @@ struct Memory::Impl {
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8,
vaddr, static_cast<u64>(data));
},
[&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); });
[&]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); });
if (ptr) {
std::memcpy(ptr, &data, sizeof(T));
}
@@ -613,7 +608,7 @@ struct Memory::Impl {
LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}",
sizeof(T) * 8, vaddr, static_cast<u64>(data));
},
[&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); });
[&]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); });
if (ptr) {
const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
@@ -628,7 +623,7 @@ struct Memory::Impl {
LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}",
vaddr, static_cast<u64>(data[1]), static_cast<u64>(data[0]));
},
[&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(u128)); });
[&]() { system.GPU().InvalidateRegion(vaddr, sizeof(u128)); });
if (ptr) {
const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);

View File

@@ -39,21 +39,14 @@ add_library(input_common STATIC
if (MSVC)
target_compile_options(input_common PRIVATE
/W4
/WX
/we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data
/we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data
/we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
)
else()
target_compile_options(input_common PRIVATE
-Werror
-Werror=conversion
-Werror=ignored-qualifiers
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
-Werror=unused-variable
)
endif()

View File

@@ -324,7 +324,7 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) {
return true;
}
Common::Input::VibrationError GCAdapter::SetRumble(
Common::Input::VibrationError GCAdapter::SetVibration(
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f;
const auto processed_amplitude =
@@ -338,6 +338,10 @@ Common::Input::VibrationError GCAdapter::SetRumble(
return Common::Input::VibrationError::None;
}
bool GCAdapter::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
return rumble_enabled;
}
void GCAdapter::UpdateVibrations() {
// Use 8 states to keep the switching between on/off fast enough for
// a human to feel different vibration strenght

View File

@@ -25,9 +25,11 @@ public:
explicit GCAdapter(std::string input_engine_);
~GCAdapter() override;
Common::Input::VibrationError SetRumble(
Common::Input::VibrationError SetVibration(
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
bool IsVibrationEnabled(const PadIdentifier& identifier) override;
/// Used for automapping features
std::vector<Common::ParamPackage> GetInputDevices() const override;
ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;

View File

@@ -40,8 +40,8 @@ public:
void EnableMotion() {
if (sdl_controller) {
SDL_GameController* controller = sdl_controller.get();
has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL);
has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO);
has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE;
has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE;
if (has_accel) {
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
}
@@ -114,6 +114,20 @@ public:
}
return false;
}
void EnableVibration(bool is_enabled) {
has_vibration = is_enabled;
is_vibration_tested = true;
}
bool HasVibration() const {
return has_vibration;
}
bool IsVibrationTested() const {
return is_vibration_tested;
}
/**
* The Pad identifier of the joystick
*/
@@ -236,6 +250,8 @@ private:
u64 last_motion_update{};
bool has_gyro{false};
bool has_accel{false};
bool has_vibration{false};
bool is_vibration_tested{false};
BasicMotion motion;
};
@@ -517,7 +533,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
return devices;
}
Common::Input::VibrationError SDLDriver::SetRumble(
Common::Input::VibrationError SDLDriver::SetVibration(
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
const auto joystick =
GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
@@ -546,13 +562,6 @@ Common::Input::VibrationError SDLDriver::SetRumble(
.type = Common::Input::VibrationAmplificationType::Exponential,
};
if (vibration.type == Common::Input::VibrationAmplificationType::Test) {
if (!joystick->RumblePlay(new_vibration)) {
return Common::Input::VibrationError::Unknown;
}
return Common::Input::VibrationError::None;
}
vibration_queue.Push(VibrationRequest{
.identifier = identifier,
.vibration = new_vibration,
@@ -561,6 +570,45 @@ Common::Input::VibrationError SDLDriver::SetRumble(
return Common::Input::VibrationError::None;
}
bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) {
const auto joystick =
GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
constexpr Common::Input::VibrationStatus test_vibration{
.low_amplitude = 1,
.low_frequency = 160.0f,
.high_amplitude = 1,
.high_frequency = 320.0f,
.type = Common::Input::VibrationAmplificationType::Exponential,
};
constexpr Common::Input::VibrationStatus zero_vibration{
.low_amplitude = 0,
.low_frequency = 160.0f,
.high_amplitude = 0,
.high_frequency = 320.0f,
.type = Common::Input::VibrationAmplificationType::Exponential,
};
if (joystick->IsVibrationTested()) {
return joystick->HasVibration();
}
// First vibration might fail
joystick->RumblePlay(test_vibration);
// Wait for about 15ms to ensure the controller is ready for the stop command
std::this_thread::sleep_for(std::chrono::milliseconds(15));
if (!joystick->RumblePlay(zero_vibration)) {
joystick->EnableVibration(false);
return false;
}
joystick->EnableVibration(true);
return true;
}
void SDLDriver::SendVibrations() {
while (!vibration_queue.Empty()) {
VibrationRequest request;

View File

@@ -61,9 +61,11 @@ public:
bool IsStickInverted(const Common::ParamPackage& params) override;
Common::Input::VibrationError SetRumble(
Common::Input::VibrationError SetVibration(
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
bool IsVibrationEnabled(const PadIdentifier& identifier) override;
private:
struct VibrationRequest {
PadIdentifier identifier;

View File

@@ -108,12 +108,17 @@ public:
[[maybe_unused]] const Common::Input::LedStatus& led_status) {}
// Sets rumble to a controller
virtual Common::Input::VibrationError SetRumble(
virtual Common::Input::VibrationError SetVibration(
[[maybe_unused]] const PadIdentifier& identifier,
[[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
return Common::Input::VibrationError::NotSupported;
}
// Returns true if device supports vibrations
virtual bool IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
return false;
}
// Sets polling mode to a controller
virtual Common::Input::PollingError SetPollingMode(
[[maybe_unused]] const PadIdentifier& identifier,

View File

@@ -763,7 +763,11 @@ public:
Common::Input::VibrationError SetVibration(
const Common::Input::VibrationStatus& vibration_status) override {
return input_engine->SetRumble(identifier, vibration_status);
return input_engine->SetVibration(identifier, vibration_status);
}
bool IsVibrationEnabled() override {
return input_engine->IsVibrationEnabled(identifier);
}
Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override {
@@ -797,8 +801,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateButtonDevice(
const auto button_id = params.Get("button", 0);
const auto keyboard_key = params.Get("code", 0);
const auto toggle = params.Get("toggle", false);
const auto inverted = params.Get("inverted", false);
const auto toggle = params.Get("toggle", false) != 0;
const auto inverted = params.Get("inverted", false) != 0;
input_engine->PreSetController(identifier);
input_engine->PreSetButton(identifier, button_id);
input_engine->PreSetButton(identifier, keyboard_key);
@@ -820,8 +824,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateHatButtonDevice(
const auto button_id = params.Get("hat", 0);
const auto direction = input_engine->GetHatButtonId(params.Get("direction", ""));
const auto toggle = params.Get("toggle", false);
const auto inverted = params.Get("inverted", false);
const auto toggle = params.Get("toggle", false) != 0;
const auto inverted = params.Get("inverted", false) != 0;
input_engine->PreSetController(identifier);
input_engine->PreSetHatButton(identifier, button_id);
@@ -879,7 +883,7 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateAnalogDevice(
.threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f),
.offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f),
.inverted = params.Get("invert", "+") == "-",
.toggle = static_cast<bool>(params.Get("toggle", false)),
.toggle = params.Get("toggle", false) != 0,
};
input_engine->PreSetController(identifier);
input_engine->PreSetAxis(identifier, axis);
@@ -895,8 +899,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTriggerDevice(
};
const auto button = params.Get("button", 0);
const auto toggle = params.Get("toggle", false);
const auto inverted = params.Get("inverted", false);
const auto toggle = params.Get("toggle", false) != 0;
const auto inverted = params.Get("inverted", false) != 0;
const auto axis = params.Get("axis", 0);
const Common::Input::AnalogProperties properties = {
@@ -926,8 +930,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(
};
const auto button = params.Get("button", 0);
const auto toggle = params.Get("toggle", false);
const auto inverted = params.Get("inverted", false);
const auto toggle = params.Get("toggle", false) != 0;
const auto inverted = params.Get("inverted", false) != 0;
const auto axis_x = params.Get("axis_x", 0);
const Common::Input::AnalogProperties properties_x = {

View File

@@ -241,24 +241,14 @@ target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit)
if (MSVC)
target_compile_options(shader_recompiler PRIVATE
/W4
/WX
/we4018 # 'expression' : signed/unsigned mismatch
/we4244 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
/we4245 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
/we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
/we4305 # 'context' : truncation from 'type1' to 'type2'
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
/we4826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior.
)
else()
target_compile_options(shader_recompiler PRIVATE
-Werror
-Werror=conversion
-Werror=ignored-qualifiers
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
-Werror=unused-variable
# Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
# And this in turns limits the size of a std::array.

View File

@@ -5,10 +5,6 @@
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
#include "shader_recompiler/frontend/ir/value.h"
#ifdef _MSC_VER
#pragma warning(disable : 4100)
#endif
namespace Shader::Backend::GLASM {
#define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__)

View File

@@ -7,10 +7,6 @@
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
#include "shader_recompiler/frontend/ir/value.h"
#ifdef _MSC_VER
#pragma warning(disable : 4100)
#endif
namespace Shader::Backend::GLSL {
void EmitGetRegister(EmitContext& ctx) {

View File

@@ -325,11 +325,6 @@ void Inst::AddPhiOperand(Block* predecessor, const Value& value) {
phi_args.emplace_back(predecessor, value);
}
void Inst::ErasePhiOperand(size_t index) {
const auto operand_it{phi_args.begin() + static_cast<ptrdiff_t>(index)};
phi_args.erase(operand_it);
}
void Inst::OrderPhiArgs() {
if (op != Opcode::Phi) {
throw LogicError("{} is not a Phi instruction", op);

View File

@@ -178,13 +178,9 @@ public:
/// Get a pointer to the block of a phi argument.
[[nodiscard]] Block* PhiBlock(size_t index) const;
/// Add phi operand to a phi instruction.
void AddPhiOperand(Block* predecessor, const Value& value);
// Erase the phi operand at the given index.
void ErasePhiOperand(size_t index);
/// Orders the Phi arguments from farthest away to nearest.
void OrderPhiArgs();

View File

@@ -137,28 +137,35 @@ bool IsLegacyAttribute(IR::Attribute attribute) {
}
std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings(
const VaryingState& state, std::queue<IR::Attribute> ununsed_generics) {
const VaryingState& state, std::queue<IR::Attribute> unused_generics,
const std::map<IR::Attribute, IR::Attribute>& previous_stage_mapping) {
std::map<IR::Attribute, IR::Attribute> mapping;
auto update_mapping = [&mapping, &unused_generics, previous_stage_mapping](IR::Attribute attr,
size_t count) {
if (previous_stage_mapping.find(attr) != previous_stage_mapping.end()) {
for (size_t i = 0; i < count; ++i) {
mapping.insert({attr + i, previous_stage_mapping.at(attr + i)});
}
} else {
for (size_t i = 0; i < count; ++i) {
mapping.insert({attr + i, unused_generics.front() + i});
}
unused_generics.pop();
}
};
for (size_t index = 0; index < 4; ++index) {
auto attr = IR::Attribute::ColorFrontDiffuseR + index * 4;
if (state.AnyComponent(attr)) {
for (size_t i = 0; i < 4; ++i) {
mapping.insert({attr + i, ununsed_generics.front() + i});
}
ununsed_generics.pop();
update_mapping(attr, 4);
}
}
if (state[IR::Attribute::FogCoordinate]) {
mapping.insert({IR::Attribute::FogCoordinate, ununsed_generics.front()});
ununsed_generics.pop();
update_mapping(IR::Attribute::FogCoordinate, 1);
}
for (size_t index = 0; index < IR::NUM_FIXEDFNCTEXTURE; ++index) {
auto attr = IR::Attribute::FixedFncTexture0S + index * 4;
if (state.AnyComponent(attr)) {
for (size_t i = 0; i < 4; ++i) {
mapping.insert({attr + i, ununsed_generics.front() + i});
}
ununsed_generics.pop();
update_mapping(attr, 4);
}
}
return mapping;
@@ -265,21 +272,22 @@ IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b
void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) {
auto& stores = program.info.stores;
if (stores.Legacy()) {
std::queue<IR::Attribute> ununsed_output_generics{};
std::queue<IR::Attribute> unused_output_generics{};
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
if (!stores.Generic(index)) {
ununsed_output_generics.push(IR::Attribute::Generic0X + index * 4);
unused_output_generics.push(IR::Attribute::Generic0X + index * 4);
}
}
auto mappings = GenerateLegacyToGenericMappings(stores, ununsed_output_generics);
program.info.legacy_stores_mapping =
GenerateLegacyToGenericMappings(stores, unused_output_generics, {});
for (IR::Block* const block : program.post_order_blocks) {
for (IR::Inst& inst : block->Instructions()) {
switch (inst.GetOpcode()) {
case IR::Opcode::SetAttribute: {
const auto attr = inst.Arg(0).Attribute();
if (IsLegacyAttribute(attr)) {
stores.Set(mappings[attr], true);
inst.SetArg(0, Shader::IR::Value(mappings[attr]));
stores.Set(program.info.legacy_stores_mapping[attr], true);
inst.SetArg(0, Shader::IR::Value(program.info.legacy_stores_mapping[attr]));
}
break;
}
@@ -292,15 +300,16 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run
auto& loads = program.info.loads;
if (loads.Legacy()) {
std::queue<IR::Attribute> ununsed_input_generics{};
std::queue<IR::Attribute> unused_input_generics{};
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
const AttributeType input_type{runtime_info.generic_input_types[index]};
if (!runtime_info.previous_stage_stores.Generic(index) || !loads.Generic(index) ||
input_type == AttributeType::Disabled) {
ununsed_input_generics.push(IR::Attribute::Generic0X + index * 4);
unused_input_generics.push(IR::Attribute::Generic0X + index * 4);
}
}
auto mappings = GenerateLegacyToGenericMappings(loads, ununsed_input_generics);
auto mappings = GenerateLegacyToGenericMappings(
loads, unused_input_generics, runtime_info.previous_stage_legacy_stores_mapping);
for (IR::Block* const block : program.post_order_blocks) {
for (IR::Inst& inst : block->Instructions()) {
switch (inst.GetOpcode()) {

View File

@@ -1,104 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <boost/container/small_vector.hpp>
#include "shader_recompiler/frontend/ir/basic_block.h"
#include "shader_recompiler/frontend/ir/value.h"
#include "shader_recompiler/ir_opt/passes.h"
namespace Shader::Optimization {
namespace {
template <bool TEST_USES>
void DeadInstElimination(IR::Block* const block) {
// We iterate over the instructions in reverse order.
// This is because removing an instruction reduces the number of uses for earlier instructions.
auto it{block->end()};
while (it != block->begin()) {
--it;
if constexpr (TEST_USES) {
if (it->HasUses() || it->MayHaveSideEffects()) {
continue;
}
}
it->Invalidate();
it = block->Instructions().erase(it);
}
}
void DeletedPhiArgElimination(IR::Program& program, std::span<const IR::Block*> dead_blocks) {
for (IR::Block* const block : program.blocks) {
for (IR::Inst& phi : *block) {
if (!IR::IsPhi(phi)) {
continue;
}
for (size_t i = 0; i < phi.NumArgs(); ++i) {
if (std::ranges::find(dead_blocks, phi.PhiBlock(i)) == dead_blocks.end()) {
continue;
}
// Phi operand at this index is an unreachable block
phi.ErasePhiOperand(i);
--i;
}
}
}
}
void DeadBranchElimination(IR::Program& program) {
boost::container::small_vector<const IR::Block*, 3> dead_blocks;
const auto begin_it{program.syntax_list.begin()};
for (auto node_it = begin_it; node_it != program.syntax_list.end(); ++node_it) {
if (node_it->type != IR::AbstractSyntaxNode::Type::If) {
continue;
}
IR::Inst* const cond_ref{node_it->data.if_node.cond.Inst()};
const IR::U1 cond{cond_ref->Arg(0)};
if (!cond.IsImmediate()) {
continue;
}
if (cond.U1()) {
continue;
}
// False immediate condition. Remove condition ref, erase the entire branch.
cond_ref->Invalidate();
// Account for nested if-statements within the if(false) branch
u32 nested_ifs{1u};
while (node_it->type != IR::AbstractSyntaxNode::Type::EndIf || nested_ifs > 0) {
node_it = program.syntax_list.erase(node_it);
switch (node_it->type) {
case IR::AbstractSyntaxNode::Type::If:
++nested_ifs;
break;
case IR::AbstractSyntaxNode::Type::EndIf:
--nested_ifs;
break;
case IR::AbstractSyntaxNode::Type::Block: {
IR::Block* const block{node_it->data.block};
DeadInstElimination<false>(block);
dead_blocks.push_back(block);
break;
}
default:
break;
}
}
// Erase EndIf node of the if(false) branch
node_it = program.syntax_list.erase(node_it);
// Account for loop increment
--node_it;
}
if (!dead_blocks.empty()) {
DeletedPhiArgElimination(program, std::span(dead_blocks.data(), dead_blocks.size()));
}
}
} // namespace
void DeadCodeEliminationPass(IR::Program& program) {
DeadBranchElimination(program);
// We iterate over the instructions in reverse order.
// This is because removing an instruction reduces the number of uses for earlier instructions.
for (IR::Block* const block : program.post_order_blocks) {
DeadInstElimination<true>(block);
auto it{block->end()};
while (it != block->begin()) {
--it;
if (!it->HasUses() && !it->MayHaveSideEffects()) {
it->Invalidate();
it = block->Instructions().erase(it);
}
}
}
}

View File

@@ -4,6 +4,7 @@
#pragma once
#include <array>
#include <map>
#include <optional>
#include <vector>
@@ -60,6 +61,7 @@ struct TransformFeedbackVarying {
struct RuntimeInfo {
std::array<AttributeType, 32> generic_input_types{};
VaryingState previous_stage_stores;
std::map<IR::Attribute, IR::Attribute> previous_stage_legacy_stores_mapping;
bool convert_depth_mode{};
bool force_early_z{};

View File

@@ -5,6 +5,7 @@
#include <array>
#include <bitset>
#include <map>
#include "common/common_types.h"
#include "shader_recompiler/frontend/ir/type.h"
@@ -127,6 +128,8 @@ struct Info {
VaryingState stores;
VaryingState passthrough;
std::map<IR::Attribute, IR::Attribute> legacy_stores_mapping;
bool loads_indexed_attributes{};
std::array<bool, 8> stores_frag_color{};

View File

@@ -44,7 +44,7 @@ public:
[[nodiscard]] unsigned Count() const noexcept {
unsigned count = 0;
for (const auto [index, value] : page_table) {
for (const auto& [index, value] : page_table) {
count += value;
}
return count;

View File

@@ -279,14 +279,8 @@ if (MSVC)
else()
target_compile_options(video_core PRIVATE
-Werror=conversion
-Wno-error=sign-conversion
-Werror=pessimizing-move
-Werror=redundant-move
-Werror=type-limits
$<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
-Wno-sign-conversion
)
endif()

View File

@@ -401,9 +401,7 @@ void Maxwell3D::ProcessQueryGet() {
switch (regs.report_semaphore.query.operation) {
case Regs::ReportSemaphore::Operation::Release:
if (regs.report_semaphore.query.release ==
Regs::ReportSemaphore::Release::AfterAllPreceedingWrites ||
regs.report_semaphore.query.short_query != 0) {
if (regs.report_semaphore.query.short_query != 0) {
const GPUVAddr sequence_address{regs.report_semaphore.Address()};
const u32 payload = regs.report_semaphore.payload;
std::function<void()> operation([this, sequence_address, payload] {
@@ -417,11 +415,10 @@ void Maxwell3D::ProcessQueryGet() {
};
const GPUVAddr sequence_address{regs.report_semaphore.Address()};
const u32 payload = regs.report_semaphore.payload;
std::function<void()> operation([this, sequence_address, payload] {
[this, sequence_address, payload] {
memory_manager.Write<u64>(sequence_address + sizeof(u64), system.GPU().GetTicks());
memory_manager.Write<u64>(sequence_address, payload);
});
rasterizer->SyncOperation(std::move(operation));
}();
}
break;
case Regs::ReportSemaphore::Operation::Acquire:
@@ -497,11 +494,11 @@ void Maxwell3D::ProcessCounterReset() {
void Maxwell3D::ProcessSyncPoint() {
const u32 sync_point = regs.sync_info.sync_point.Value();
const auto condition = regs.sync_info.condition.Value();
[[maybe_unused]] const u32 cache_flush = regs.sync_info.clean_l2.Value();
if (condition == Regs::SyncInfo::Condition::RopWritesDone) {
rasterizer->SignalSyncPoint(sync_point);
const u32 cache_flush = regs.sync_info.clean_l2.Value();
if (cache_flush != 0) {
rasterizer->InvalidateGPUCache();
}
rasterizer->SignalSyncPoint(sync_point);
}
std::optional<u64> Maxwell3D::GetQueryResult() {

View File

@@ -75,11 +75,10 @@ void Puller::ProcessSemaphoreTriggerMethod() {
if (op == GpuSemaphoreOperation::WriteLong) {
const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()};
const u32 payload = regs.semaphore_sequence;
std::function<void()> operation([this, sequence_address, payload] {
[this, sequence_address, payload] {
memory_manager.Write<u64>(sequence_address + sizeof(u64), gpu.GetTicks());
memory_manager.Write<u64>(sequence_address, payload);
});
rasterizer->SignalFence(std::move(operation));
}();
} else {
do {
const u32 word{memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress())};

View File

@@ -133,7 +133,7 @@ inline void MemoryManager::SetBigPageContinous(size_t big_page_index, bool value
template <MemoryManager::EntryType entry_type>
GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size,
PTEKind kind) {
u64 remaining_size{size};
[[maybe_unused]] u64 remaining_size{size};
if constexpr (entry_type == EntryType::Mapped) {
page_table.ReserveRange(gpu_addr, size);
}
@@ -159,7 +159,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp
template <MemoryManager::EntryType entry_type>
GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr,
size_t size, PTEKind kind) {
u64 remaining_size{size};
[[maybe_unused]] u64 remaining_size{size};
for (u64 offset{}; offset < size; offset += big_page_size) {
const GPUVAddr current_gpu_addr = gpu_addr + offset;
[[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr);

View File

@@ -63,6 +63,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key,
Shader::RuntimeInfo info;
if (previous_program) {
info.previous_stage_stores = previous_program->info.stores;
info.previous_stage_legacy_stores_mapping = previous_program->info.legacy_stores_mapping;
} else {
// Mark all stores as available for vertex shaders
info.previous_stage_stores.mask.set();

View File

@@ -134,6 +134,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
Shader::RuntimeInfo info;
if (previous_program) {
info.previous_stage_stores = previous_program->info.stores;
info.previous_stage_legacy_stores_mapping = previous_program->info.legacy_stores_mapping;
if (previous_program->is_geometry_passthrough) {
info.previous_stage_stores.mask |= previous_program->info.passthrough.mask;
}

View File

@@ -144,7 +144,6 @@ private:
using FuncType = TypedCommand<T>;
static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large");
recorded_counts++;
command_offset = Common::AlignUp(command_offset, alignof(FuncType));
if (command_offset > sizeof(data) - sizeof(FuncType)) {
return false;
@@ -166,7 +165,7 @@ private:
}
bool Empty() const {
return recorded_counts == 0;
return command_offset == 0;
}
bool HasSubmit() const {
@@ -177,7 +176,6 @@ private:
Command* first = nullptr;
Command* last = nullptr;
size_t recorded_counts = 0;
size_t command_offset = 0;
bool submit = false;
alignas(std::max_align_t) std::array<u8, 0x8000> data{};

View File

@@ -150,6 +150,8 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
return PixelFormat::D24_UNORM_S8_UINT;
case Hash(TextureFormat::D32S8, FLOAT, UINT, UNORM, UNORM, LINEAR):
return PixelFormat::D32_FLOAT_S8_UINT;
case Hash(TextureFormat::R32_B24G8, FLOAT, UINT, UNORM, UNORM, LINEAR):
return PixelFormat::D32_FLOAT_S8_UINT;
case Hash(TextureFormat::BC1_RGBA, UNORM, LINEAR):
return PixelFormat::BC1_RGBA_UNORM;
case Hash(TextureFormat::BC1_RGBA, UNORM, SRGB):

View File

@@ -442,7 +442,7 @@ void TextureCache<P>::WriteMemory(VAddr cpu_addr, size_t size) {
template <class P>
void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) {
std::vector<ImageId> images;
ForEachImageInRegion(cpu_addr, size, [this, &images](ImageId image_id, ImageBase& image) {
ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) {
if (!image.IsSafeDownload()) {
return;
}
@@ -1502,9 +1502,9 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
image.flags &= ~ImageFlagBits::BadOverlap;
lru_cache.Free(image.lru_index);
const auto& clear_page_table =
[this, image_id](u64 page,
std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>&
selected_page_table) {
[image_id](u64 page,
std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>&
selected_page_table) {
const auto page_it = selected_page_table.find(page);
if (page_it == selected_page_table.end()) {
ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << YUZU_PAGEBITS);

View File

@@ -1661,8 +1661,8 @@ void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height,
for (u32 z = 0; z < depth; ++z) {
const u32 depth_offset = z * height * width * 4;
for (u32 y_index = 0; y_index < rows; ++y_index) {
auto decompress_stride = [data, width, height, depth, block_width, block_height, output,
rows, cols, z, depth_offset, y_index] {
auto decompress_stride = [data, width, height, block_width, block_height, output, rows,
cols, z, depth_offset, y_index] {
const u32 y = y_index * block_height;
for (u32 x_index = 0; x_index < cols; ++x_index) {
const u32 block_index = (z * rows * cols) + (y_index * cols) + x_index;

View File

@@ -21,7 +21,7 @@ constexpr u32 pdep(u32 value) {
u32 m = mask;
for (u32 bit = 1; m; bit += bit) {
if (value & bit)
result |= m & -m;
result |= m & (~m + 1);
m &= m - 1;
}
return result;

View File

@@ -268,7 +268,7 @@ bool MultiplayerState::OnCloseRoom() {
return true;
}
// Save ban list
UISettings::values.multiplayer_ban_list = std::move(room->GetBanList());
UISettings::values.multiplayer_ban_list = room->GetBanList();
room->Destroy();
announce_multiplayer_session->Stop();

View File

@@ -49,7 +49,7 @@ bool CheckEnvVars(bool* is_child) {
*is_child = true;
return false;
} else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) {
std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n",
std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n",
IS_CHILD_ENV_VAR, GetLastError());
return true;
}
@@ -62,7 +62,7 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka
// Set the startup variable for child processes
const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT);
if (!env_var_set) {
std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n",
std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n",
STARTUP_CHECK_ENV_VAR, GetLastError());
return false;
}
@@ -81,22 +81,22 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka
DWORD exit_code = STILL_ACTIVE;
const int err = GetExitCodeProcess(process_info.hProcess, &exit_code);
if (err == 0) {
std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError());
std::fprintf(stderr, "GetExitCodeProcess failed with error %lu\n", GetLastError());
}
// Vulkan is broken if the child crashed (return value is not zero)
*has_broken_vulkan = (exit_code != 0);
if (CloseHandle(process_info.hProcess) == 0) {
std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError());
std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError());
}
if (CloseHandle(process_info.hThread) == 0) {
std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError());
std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError());
}
}
if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) {
std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %d\n",
std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %lu\n",
STARTUP_CHECK_ENV_VAR, GetLastError());
}
@@ -135,7 +135,8 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) {
startup_info.cb = sizeof(startup_info);
char p_name[255];
std::strncpy(p_name, arg0, 255);
std::strncpy(p_name, arg0, 254);
p_name[254] = '\0';
const bool process_created = CreateProcessA(nullptr, // lpApplicationName
p_name, // lpCommandLine
@@ -149,7 +150,7 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) {
pi // lpProcessInformation
);
if (!process_created) {
std::fprintf(stderr, "CreateProcessA failed with error %d\n", GetLastError());
std::fprintf(stderr, "CreateProcessA failed with error %lu\n", GetLastError());
return false;
}