Compare commits

..

75 Commits

Author SHA1 Message Date
german77
e4c63d432d wall_clock: use standard wall clock if rtsc frequency is too low 2022-01-27 17:07:52 -06:00
bunnei
2136ebccd6 Merge pull request #7761 from v1993/patch-8
Improve FFmpeg cmake file
2022-01-22 23:43:14 -08:00
bunnei
5b57ee66ce Merge pull request #7716 from german77/volume
yuzu: Add volume hotkeys
2022-01-22 02:25:59 -08:00
Valeri
f68be36159 Improve FFmpeg cmake file
* Fix compilation if CUDA_INCLUDE_DIRS is empty/contains multiple paths
* Pass CMAKE_{C,CXX}_COMPILER_LAUNCHER to ffmpeg compiler
2022-01-22 12:56:25 +03:00
bunnei
8433edacb3 Merge pull request #7735 from german77/udp_battery
input_common: Report battery for UDP controllers
2022-01-22 01:28:14 -08:00
bunnei
68c8a1b170 Merge pull request #7737 from bunnei/fix-dummy-thread-leak
Various fixes to HLE service thread management
2022-01-21 22:34:47 -08:00
bunnei
cef7649bed Merge pull request #7752 from Morph1984/SetCpuOverclockEnabled
service: apm: Stub ISession SetCpuOverclockEnabled
2022-01-21 17:13:52 -08:00
bunnei
615fb40416 hle: kernel: KThread: Ensure host (dummy) threads block on locking.
- But do not enter the priority queue, as otherwise they will be scheduled.
- Allows dummy threads to use guest synchronization primitives.
2022-01-21 17:12:06 -08:00
bunnei
d990f043bd Merge pull request #7756 from lioncash/service
service: Update function tables
2022-01-21 14:26:05 -08:00
Lioncash
12bf8ca929 service/wlan: Update function tables 2022-01-21 16:35:51 -05:00
Lioncash
8dd6dc9a29 service/usb: Update function tables 2022-01-21 16:31:57 -05:00
Lioncash
43039d95ac service/set: Update function tables 2022-01-21 16:26:12 -05:00
Lioncash
7ba6f68a8d service/ns: Update function tables 2022-01-21 16:21:35 -05:00
Lioncash
19c11e2fd2 service/nim: Update unknown function table entries 2022-01-21 16:17:40 -05:00
Lioncash
888bc10c17 service/friend: Update unknown function table entries 2022-01-21 16:08:46 -05:00
Lioncash
54150f5afa service/filsystem: Update fsp-srv function table 2022-01-21 16:07:01 -05:00
Lioncash
3da43ad2a9 service/btm: Update function tables 2022-01-21 15:59:41 -05:00
Lioncash
0f7337c522 service/audio: Update audctl unknown function names 2022-01-21 15:50:38 -05:00
Lioncash
29e3636e0a service/am: Update omm function tables 2022-01-21 15:40:08 -05:00
Lioncash
a271cf89cf service/acc: Update unknown function names
Switchbrew has the function names now.
2022-01-21 15:33:22 -05:00
bunnei
88d9b55b14 Merge pull request #7755 from v1993/someone-in-here-lacks-system-wide-theming
Use Default Colorful theme by default outside of Windows
2022-01-21 11:51:29 -08:00
bunnei
03cf308c16 Merge pull request #7731 from v1993/xfb-varying-check-fix
shader_recompiler: fix potential OOB access
2022-01-21 10:45:56 -08:00
v1993
d63d8bf7f9 Use Default Colorful theme by default outside of Windows
On OSes with system-wide theming this allows yuzu to follow system style, regardless of its exact coloration, working well with both light and dark system themes. Dark /Colorful, on the other hand, forces dark theme regardless of user preferences set in system settings, making for a poor default.

Use Colorful variation to keep in line with icon style of patron-voted Dark Colorful.
2022-01-21 20:57:00 +03:00
Morph
a396473201 service: apm: Stub ISession SetCpuOverclockEnabled
Since we don't currently support CPU overclocking within the emulated system, this can be stubbed for now, like APM IsCpuOverclockEnabled.

- Used by Gravity Rider Zero
2022-01-20 21:07:26 -05:00
bunnei
ef7c50b276 Merge pull request #7695 from Morph1984/is-pow2
common: bit_util: Add IsPow2 helper function
2022-01-20 18:06:11 -08:00
bunnei
f6815086a1 hle: kernel: Remove redundant tracking of dummy threads.
- These are already tracked by kernel's registered_objects member.
2022-01-20 17:08:00 -08:00
bunnei
91ff6d4cb3 hle: kernel: KThread: DummyThread can be waited, ensure wait_queue is not nullptr. 2022-01-20 17:08:00 -08:00
bunnei
46a620f9d7 hle: kernel: KThread: Decrease DummyThread priority to ensure it is never scheduled. 2022-01-20 17:08:00 -08:00
bunnei
0b37e7cb39 hle: kernel: service_thread: Ensure dummy thread is closed & destroyed on thread exit. 2022-01-20 17:08:00 -08:00
bunnei
384e24d3e9 hle: kernel: KServerSession: Remove hack for CompleteSyncRequest.
- This does not appear to be necessary anymore.
2022-01-20 17:08:00 -08:00
bunnei
ad53dc22fd hle: kernel: KServerSession: Simplify CompleteSyncRequest EndWait.
- Considering is_thread_waiting is never set, so we can remove IsThreadWaiting.
- KThread::EndWait will take the scheduler lock, so we can remove the redundant lock.
2022-01-20 17:08:00 -08:00
bunnei
5ffec69dc7 hle: kernel: KThread: Ensure dummy threads never call EndWait.
- These are only used by host threads for locking and will never have a wait_queue.
2022-01-20 17:08:00 -08:00
bunnei
11a380c3da hle: kernel: KScheduler: Ensure dummy threads are never scheduled.
- These are only used by host threads for locking.
2022-01-20 17:08:00 -08:00
bunnei
f6cbb14dce hle: kernel: KThread: Rename thread_type_for_debugging -> thread_type.
- This will be used to ensure that we do not schedule dummy threads.
2022-01-20 17:08:00 -08:00
bunnei
e781f6e767 Merge pull request #7710 from german77/just-shake-it
core/hid: Increment shake force
2022-01-20 16:53:22 -08:00
Mai M
55ef89a9c7 Merge pull request #7749 from jbeich/ffmpeg5
video_core: unbreak build with FFmpeg 5.0
2022-01-20 13:56:32 -05:00
Jan Beich
d24a4b79d4 video_core: constify AVCodec for ffmpeg >= 5.0
src/video_core/command_classes/codecs/codec.cpp:177:16: error: assigning to 'AVCodec *' from 'const AVCodec *' discards qualifiers
    av_codec = avcodec_find_decoder(codec);
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~
2022-01-20 11:09:21 +00:00
Morph
dc471700ca Merge pull request #7726 from german77/clamp
service/hid: Initialize applet_resource on SetNpadAnalogStickUseCenterClamp
2022-01-19 14:31:15 -08:00
Fernando S
490df43f34 Merge pull request #7747 from DadSchoorse/fix-anv-64bit-atomic-stype
vulkan_device: Fix sType for VkPhysicalDeviceShaderAtomicInt64Features
2022-01-19 23:01:53 +01:00
german77
8fa0416fee service/hid: Initialize applet_resource on SetNpadAnalogStickUseCenterClamp 2022-01-19 14:20:31 -06:00
Georg Lehmann
d15814d39f vulkan_device: Fix sType for VkPhysicalDeviceShaderAtomicInt64Features 2022-01-19 19:48:46 +01:00
bunnei
b5e83bcc7b Merge pull request #7701 from bunnei/clear-mem-pages
Kernel Memory Updates (Part 3): Clear KMemoryManager pages & other fixes
2022-01-18 21:20:42 -08:00
bunnei
fc3eb72359 Merge pull request #7715 from gidoly/patch-4
Xbox controller default name nit pick
2022-01-18 21:14:30 -08:00
bunnei
eceee8e5f4 Merge pull request #7725 from german77/mouse_in_motion
input_common: Reintroduce motion from mouse and use button names
2022-01-18 18:16:27 -08:00
bunnei
101d86897b Merge pull request #7712 from bunnei/fix-thread-exit
Accurately implement thread exit
2022-01-17 18:08:24 -08:00
bunnei
1dbb9e353e Merge pull request #7724 from ameerj/astc_new_nv
astc_decoder: Combine FastReplicate functions to work around new NV driver bug
2022-01-17 16:48:04 -08:00
bunnei
5eb0b65590 Merge pull request #7732 from v1993/patch-7
kernel: remove no-op code
2022-01-17 15:37:16 -08:00
v1993
a943600019 shader_recompiler: fix potential OOB access
Found by static analysis with PVS-Studio. Original check wasn't actually checking for OOB and would segfault in case of it.
2022-01-17 21:50:51 +03:00
Mai M
45ac3f414e Merge pull request #7730 from v1993/patch-6
input_common: nitpick about SetHatButton usage
2022-01-17 13:43:34 -05:00
Mai M
b92198b7f8 Merge pull request #7729 from v1993/patch-5
input_common: fix copy-paste error
2022-01-17 13:43:21 -05:00
Mai M
cf4893410b Merge pull request #7728 from v1993/patch-4
hid: fix std::transform call
2022-01-17 13:43:11 -05:00
Mai M
345bcd4cdf Merge pull request #7727 from v1993/patch-3
hid: Correct assignment source for rotations
2022-01-17 13:42:57 -05:00
Valeri
84786dde00 hle: remove no-op code
Found by static analysis with PVS-Studio. Nobody seems to really know what was it doing there.
2022-01-17 13:51:12 +03:00
bunnei
ca2d904770 Merge pull request #7719 from gidoly/patch-6
Change default theme to Dark colorful
2022-01-17 01:04:47 -08:00
Valeri
3431e0acf5 input_common: nitpick about SetHatButton usage 2022-01-17 12:04:38 +03:00
Valeri
a99f84f4b2 input_common: fix copy-paste error
Found by static analysis with PVS-Studio.
2022-01-17 11:31:38 +03:00
Valeri
8eddafd9d0 hid: fix std::transform call
Found by static analysis with PVS-Studio.
2022-01-17 10:47:38 +03:00
Morph
78e233c460 uisettings: Add enumeration type for themes
Eliminates the usage of a magic number to indicate the default index of the themes array,
2022-01-17 02:46:30 -05:00
gidoly
789af19c60 config: Change default theme to Dark Colorful 2022-01-17 02:41:53 -05:00
Valeri
c624edceba Correct assignment source for rotations
Found by static analysis with PVS-Studio
2022-01-17 10:40:41 +03:00
german77
9eab07f863 input_common: Reintroduce motion from mouse and use button names 2022-01-16 20:37:34 -06:00
ameerj
a5bff8e9b3 astc_decoder: Combine FastReplicate functions to work around new NV driver bug
The new Nvidia drivers have a bug where the FastReplicateTo6 function produces a lookup into the REPLICATE_TO_8 table rather than the REPLICATE_TO_6 table.

This seems to be an optimization gone wrong. Combining the logic of the FastReplicate functions seems to address the bug.
2022-01-16 16:13:20 -05:00
german77
850896a52b audio/stream: Adjust volume scale factor 2022-01-15 20:28:37 -06:00
german77
c8b3a12856 yuzu: Add volume up/down hotkeys 2022-01-15 20:28:37 -06:00
gidoly
92d676d788 Xbox controller default name nit pick
Discord User moon lacer pointed us that official name is 'Xbox' not 'XBox'
2022-01-16 05:59:31 +09:00
german77
419f427a01 yuzu: Remove speed limit hotkeys 2022-01-15 13:44:45 -06:00
bunnei
b54cbc985e hle: kernel: k_memory_manager: Clear pages on allocation & free.
- Heap pages should be zero'd.
- Also explicitly passed along heap allocation option.
2022-01-14 21:16:33 -08:00
bunnei
f499c8177e core: hle: kernel: KThread: Integrate with KWorkerTask and implement DoWorkerTaskImpl.
- This is used to terminate a thread asynchronously after it has been exited.
- This fixes a crash that can occur in Pokemon Sword/Shield because a thread is incorrectly closed on svcExitThread, then, the thread is destroyed on svcCloseHandle while it is still scheduled.
- Instead, we now wait for the thread to no longer be scheduled on all cores before destroying it from KWorkerTaskManager, which is accurate to HOS behavior.
2022-01-14 16:44:14 -08:00
bunnei
d8b3f665db core: hle: kernel: KProcess: Integrate with KWorkerTask and add unimplemented DoWorkerTaskImpl. 2022-01-14 16:44:14 -08:00
bunnei
03884b7ea6 core: hle: kernel: KThread: Replace Suspend with UpdateState & various updates.
- This makes our implementations of these more closely match HOS.
2022-01-14 16:44:14 -08:00
bunnei
c905044e1b core: hle: kernel: Instantiate a kernel instance of KWorkerTaskManager. 2022-01-14 16:44:14 -08:00
bunnei
bf32fcc817 core: hle: kernel: Add KWorkerTask and KWorkerTaskManager.
- These primitives are used to dispatch asynchronous kernel tasks from KThread and KProcess.
2022-01-14 16:43:59 -08:00
bunnei
f6de57c1a5 common: fiber: YieldTo: Avoid hard crash on nullptr previous_fiber.
- When the emulator crashes to desktop below, we don't even get this captured in a log, making such issues harder to debug.
2022-01-14 16:17:19 -08:00
Narr the Reg
5ce5432830 core/hid: Increment shake force
With the current settings 2p mode in pokemon let's go wasn't showing up.  By making the shake more violent we can make it appear without any effort using the keyboard
2022-01-14 11:11:20 -06:00
Morph
d92b5fc435 common: bit_util: Add IsPow2 helper function
Makes use of std::has_single_bit() to check whether the value is a power of 2.
2022-01-11 16:01:12 -05:00
58 changed files with 615 additions and 229 deletions

View File

@@ -95,7 +95,8 @@ if (NOT WIN32)
# ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress
# here we handle the hard-linking senario where CUDA is linked during compilation
if (CUDA_FOUND)
list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS})
# This line causes build error if CUDA_INCLUDE_DIRS is anything but a single non-empty value
#list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS})
@@ -119,6 +120,8 @@ if (NOT WIN32)
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
# `--disable-vdpau` is needed to avoid linking issues
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER})
add_custom_command(
OUTPUT
${FFmpeg_MAKEFILE}
@@ -137,12 +140,14 @@ if (NOT WIN32)
--enable-decoder=h264
--enable-decoder=vp8
--enable-decoder=vp9
--cc="${CMAKE_C_COMPILER}"
--cxx="${CMAKE_CXX_COMPILER}"
--cc="${FFmpeg_CC}"
--cxx="${FFmpeg_CXX}"
${FFmpeg_HWACCEL_FLAGS}
WORKING_DIRECTORY
${FFmpeg_BUILD_DIR}
)
unset(FFmpeg_CC)
unset(FFmpeg_CXX)
unset(FFmpeg_HWACCEL_FLAGS)
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child

View File

@@ -79,8 +79,8 @@ static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
return;
}
// Implementation of a volume slider with a dynamic range of 60 dB
const float volume_scale_factor = volume == 0 ? 0 : std::exp(6.90775f * volume) * 0.001f;
// Perceived volume is not the same as the volume level
const float volume_scale_factor = (0.85f * ((volume * volume) - volume)) + volume;
for (auto& sample : samples) {
sample = static_cast<s16>(sample * volume_scale_factor);
}

View File

@@ -45,6 +45,12 @@ template <typename T>
return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL));
}
template <typename T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool IsPow2(T value) {
return std::has_single_bit(value);
}
template <typename T>
requires std::is_integral_v<T>
[[nodiscard]] T NextPow2(T value) {

View File

@@ -124,7 +124,10 @@ void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) {
// "from" might no longer be valid if the thread was killed
if (auto from = weak_from.lock()) {
ASSERT(from->impl->previous_fiber != nullptr);
if (from->impl->previous_fiber == nullptr) {
ASSERT_MSG(false, "previous_fiber is nullptr!");
return;
}
from->impl->previous_fiber->impl->context = transfer.fctx;
from->impl->previous_fiber->impl->guard.unlock();
from->impl->previous_fiber.reset();

View File

@@ -209,6 +209,13 @@ enum class ButtonNames {
Triangle,
Share,
Options,
// Mouse buttons
ButtonMouseWheel,
ButtonBackward,
ButtonForward,
ButtonTask,
ButtonExtra,
};
// Callback data consisting of an input type and the equivalent data status

View File

@@ -72,7 +72,9 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
if (caps.invariant_tsc) {
rtsc_frequency = EstimateRDTSCFrequency();
}
if (rtsc_frequency == 0) {
// Fallback to StandardWallClock if rtsc period is higher than a nano second
if (rtsc_frequency <= 1000000000) {
return std::make_unique<StandardWallClock>(emulated_cpu_frequency,
emulated_clock_frequency);
} else {

View File

@@ -247,6 +247,9 @@ add_library(core STATIC
hle/kernel/k_trace.h
hle/kernel/k_transfer_memory.cpp
hle/kernel/k_transfer_memory.h
hle/kernel/k_worker_task.h
hle/kernel/k_worker_task_manager.cpp
hle/kernel/k_worker_task_manager.h
hle/kernel/k_writable_event.cpp
hle/kernel/k_writable_event.h
hle/kernel/kernel.cpp

View File

@@ -158,7 +158,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
auto& motion = console.motion_state;
motion.accel = emulated.GetAcceleration();
motion.gyro = emulated.GetGyroscope();
motion.rotation = emulated.GetGyroscope();
motion.rotation = emulated.GetRotations();
motion.orientation = emulated.GetOrientation();
motion.quaternion = emulated.GetQuaternion();
motion.gyro_bias = emulated.GetGyroBias();

View File

@@ -145,7 +145,7 @@ void EmulatedController::LoadDevices() {
motion_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>);
std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(),
Common::Input::CreateDevice<Common::Input::InputDevice>);
std::transform(battery_params.begin(), battery_params.begin(), battery_devices.end(),
std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(),
Common::Input::CreateDevice<Common::Input::InputDevice>);
std::transform(output_params.begin(), output_params.end(), output_devices.begin(),
Common::Input::CreateDevice<Common::Input::OutputDevice>);

View File

@@ -114,7 +114,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
if (TransformToButton(callback).value) {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<s16> distribution(-1000, 1000);
std::uniform_int_distribution<s16> distribution(-5000, 5000);
status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;

View File

@@ -341,10 +341,6 @@ public:
return *thread;
}
bool IsThreadWaiting() const {
return is_thread_waiting;
}
private:
friend class IPC::ResponseBuilder;
@@ -379,7 +375,6 @@ private:
u32 domain_offset{};
std::shared_ptr<SessionRequestManager> manager;
bool is_thread_waiting{};
KernelCore& kernel;
Core::Memory::Memory& memory;

View File

@@ -8,12 +8,16 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_page_linked_list.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
KMemoryManager::KMemoryManager(Core::System& system_) : system{system_} {}
std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) {
const auto size{end_address - start_address};
@@ -81,7 +85,7 @@ VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size
}
ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir) {
Direction dir, u32 heap_fill_value) {
ASSERT(page_list.GetNumPages() == 0);
// Early return if we're allocating no pages
@@ -139,6 +143,12 @@ ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_
}
}
// Clear allocated memory.
for (const auto& it : page_list.Nodes()) {
std::memset(system.DeviceMemory().GetPointer(it.GetAddress()), heap_fill_value,
it.GetSize());
}
// Only succeed if we allocated as many pages as we wanted
if (num_pages) {
return ResultOutOfMemory;
@@ -146,11 +156,12 @@ ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_
// We succeeded!
group_guard.Cancel();
return ResultSuccess;
}
ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir) {
Direction dir, u32 heap_fill_value) {
// Early return if we're freeing no pages
if (!num_pages) {
return ResultSuccess;

View File

@@ -12,6 +12,10 @@
#include "core/hle/kernel/k_page_heap.h"
#include "core/hle/result.h"
namespace Core {
class System;
}
namespace Kernel {
class KPageLinkedList;
@@ -42,7 +46,7 @@ public:
Mask = (0xF << Shift),
};
KMemoryManager() = default;
explicit KMemoryManager(Core::System& system_);
constexpr std::size_t GetSize(Pool pool) const {
return managers[static_cast<std::size_t>(pool)].GetSize();
@@ -51,10 +55,10 @@ public:
void InitializeManager(Pool pool, u64 start_address, u64 end_address);
VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir = Direction::FromFront);
ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir = Direction::FromFront);
ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir,
u32 heap_fill_value = 0);
ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir,
u32 heap_fill_value = 0);
static constexpr std::size_t MaxManagerCount = 10;
@@ -129,6 +133,7 @@ private:
};
private:
Core::System& system;
std::array<std::mutex, static_cast<std::size_t>(Pool::Count)> pool_locks;
std::array<Impl, MaxManagerCount> managers;
};

View File

@@ -289,8 +289,8 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
}
KPageLinkedList page_linked_list;
CASCADE_CODE(
system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool));
CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool,
allocation_option));
CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup));
block_manager->Update(addr, num_pages, state, perm);
@@ -457,8 +457,8 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
KPageLinkedList page_linked_list;
CASCADE_CODE(
system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool));
CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages,
memory_pool, allocation_option));
// We succeeded, so commit the memory reservation.
memory_reservation.Commit();
@@ -541,7 +541,8 @@ ResultCode KPageTable::UnmapMemory(VAddr addr, std::size_t size) {
}
const std::size_t num_pages{size / PageSize};
system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool);
system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool,
allocation_option);
block_manager->Update(addr, num_pages, KMemoryState::Free);
@@ -960,7 +961,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
// Allocate pages for the heap extension.
KPageLinkedList page_linked_list;
R_TRY(system.Kernel().MemoryManager().Allocate(page_linked_list, allocation_size / PageSize,
memory_pool));
memory_pool, allocation_option));
// Map the pages.
{
@@ -1027,8 +1028,8 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
} else {
KPageLinkedList page_group;
CASCADE_CODE(
system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool));
CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages,
memory_pool, allocation_option));
CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup));
}

View File

@@ -303,6 +303,7 @@ private:
bool is_aslr_enabled{};
KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application};
KMemoryManager::Direction allocation_option{KMemoryManager::Direction::FromFront};
Common::PageTable page_table_impl;

View File

@@ -45,6 +45,7 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
{ t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
{ t.GetPriority() } -> Common::ConvertibleTo<s32>;
{ t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
};
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
@@ -349,24 +350,49 @@ public:
// Mutators.
constexpr void PushBack(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->PushBack(member->GetPriority(), member);
}
constexpr void Remove(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->Remove(member->GetPriority(), member);
}
constexpr void MoveToScheduledFront(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
}
constexpr KThread* MoveToScheduledBack(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return {};
}
return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
member);
}
// First class fancy operations.
constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
ASSERT(IsValidPriority(prev_priority));
// Remove the member from the queues.
@@ -383,6 +409,11 @@ public:
constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity,
Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
// Get the new information.
const s32 priority = member->GetPriority();
const AffinityMaskType& new_affinity = member->GetAffinityMask();
@@ -412,6 +443,11 @@ public:
}
constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
// Get the new information.
const s32 new_core = member->GetActiveCore();
const s32 priority = member->GetPriority();

View File

@@ -149,6 +149,10 @@ ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::st
return ResultSuccess;
}
void KProcess::DoWorkerTaskImpl() {
UNIMPLEMENTED();
}
KResourceLimit* KProcess::GetResourceLimit() const {
return resource_limit;
}
@@ -477,7 +481,7 @@ void KProcess::Finalize() {
}
// Perform inherited finalization.
KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize();
}
/**

View File

@@ -15,6 +15,7 @@
#include "core/hle/kernel/k_condition_variable.h"
#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_worker_task.h"
#include "core/hle/kernel/process_capability.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
@@ -62,8 +63,7 @@ enum class ProcessStatus {
DebugBreak,
};
class KProcess final
: public KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject> {
class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> {
KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
public:
@@ -345,6 +345,8 @@ public:
bool IsSignaled() const override;
void DoWorkerTaskImpl();
void PinCurrentThread(s32 core_id);
void UnpinCurrentThread(s32 core_id);
void UnpinThread(KThread* thread);

View File

@@ -49,8 +49,6 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
if (!must_context_switch || core != current_core) {
auto& phys_core = kernel.PhysicalCore(core);
phys_core.Interrupt();
} else {
must_context_switch = true;
}
cores_pending_reschedule &= ~(1ULL << core);
}
@@ -408,6 +406,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli
} else {
RescheduleCores(kernel, cores_needing_scheduling);
}
// Special case to ensure dummy threads that are waiting block.
current_thread->IfDummyThreadTryWait();
}
u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
@@ -741,6 +742,12 @@ void KScheduler::ScheduleImpl() {
next_thread = idle_thread;
}
// We never want to schedule a dummy thread, as these are only used by host threads for locking.
if (next_thread->GetThreadType() == ThreadType::Dummy) {
ASSERT_MSG(false, "Dummy threads should never be scheduled!");
next_thread = idle_thread;
}
// If we're not actually switching thread, there's nothing to do.
if (next_thread == current_thread.load()) {
previous_thread->EnableDispatch();

View File

@@ -8,7 +8,6 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
@@ -123,20 +122,10 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
// In the event that something fails here, stub a result to prevent the game from crashing.
// This is a work-around in the event that somehow we process a service request after the
// session has been closed by the game. This has been observed to happen rarely in Pokemon
// Sword/Shield and is likely a result of us using host threads/scheduling for services.
// TODO(bunnei): Find a better solution here.
auto error_guard = SCOPE_GUARD({ CompleteSyncRequest(*context); });
// Ensure we have a session request handler
if (manager->HasSessionRequestHandler(*context)) {
if (auto strong_ptr = manager->GetServiceThread().lock()) {
strong_ptr->QueueSyncRequest(*parent, std::move(context));
// We succeeded.
error_guard.Cancel();
} else {
ASSERT_MSG(false, "strong_ptr is nullptr!");
}
@@ -171,13 +160,8 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {
convert_to_domain = false;
}
// Some service requests require the thread to block
{
KScopedSchedulerLock lock(kernel);
if (!context.IsThreadWaiting()) {
context.GetThread().EndWait(result);
}
}
// The calling thread is waiting for this request to complete, so wake it up.
context.GetThread().EndWait(result);
return result;
}

View File

@@ -30,6 +30,7 @@
#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_queue.h"
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/time_manager.h"
@@ -105,7 +106,7 @@ KThread::~KThread() = default;
ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio,
s32 virt_core, KProcess* owner, ThreadType type) {
// Assert parameters are valid.
ASSERT((type == ThreadType::Main) ||
ASSERT((type == ThreadType::Main) || (type == ThreadType::Dummy) ||
(Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority));
ASSERT((owner != nullptr) || (type != ThreadType::User));
ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>()));
@@ -139,7 +140,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
break;
}
thread_type_for_debugging = type;
thread_type = type;
// Set the ideal core ID and affinity mask.
virtual_ideal_core_id = virt_core;
@@ -261,7 +262,7 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint
}
ResultCode KThread::InitializeDummyThread(KThread* thread) {
return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy);
return thread->Initialize({}, {}, {}, DummyThreadPriority, 3, {}, ThreadType::Dummy);
}
ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
@@ -332,7 +333,7 @@ void KThread::Finalize() {
}
// Perform inherited finalization.
KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize();
KSynchronizationObject::Finalize();
}
bool KThread::IsSignaled() const {
@@ -376,11 +377,28 @@ void KThread::StartTermination() {
// Register terminated dpc flag.
RegisterDpc(DpcFlag::Terminated);
}
void KThread::FinishTermination() {
// Ensure that the thread is not executing on any core.
if (parent != nullptr) {
for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) {
KThread* core_thread{};
do {
core_thread = kernel.Scheduler(i).GetCurrentThread();
} while (core_thread == this);
}
}
// Close the thread.
this->Close();
}
void KThread::DoWorkerTaskImpl() {
// Finish the termination that was begun by Exit().
this->FinishTermination();
}
void KThread::Pin(s32 current_core) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
@@ -417,12 +435,7 @@ void KThread::Pin(s32 current_core) {
static_cast<u32>(ThreadState::SuspendShift)));
// Update our state.
const ThreadState old_state = thread_state;
thread_state = static_cast<ThreadState>(GetSuspendFlags() |
static_cast<u32>(old_state & ThreadState::Mask));
if (thread_state != old_state) {
KScheduler::OnThreadStateChanged(kernel, this, old_state);
}
UpdateState();
}
// TODO(bunnei): Update our SVC access permissions.
@@ -463,20 +476,13 @@ void KThread::Unpin() {
}
// Allow performing thread suspension (if termination hasn't been requested).
{
if (!IsTerminationRequested()) {
// Update our allow flags.
if (!IsTerminationRequested()) {
suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) +
static_cast<u32>(ThreadState::SuspendShift)));
}
suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) +
static_cast<u32>(ThreadState::SuspendShift)));
// Update our state.
const ThreadState old_state = thread_state;
thread_state = static_cast<ThreadState>(GetSuspendFlags() |
static_cast<u32>(old_state & ThreadState::Mask));
if (thread_state != old_state) {
KScheduler::OnThreadStateChanged(kernel, this, old_state);
}
UpdateState();
}
// TODO(bunnei): Update our SVC access permissions.
@@ -689,12 +695,7 @@ void KThread::Resume(SuspendType type) {
~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)));
// Update our state.
const ThreadState old_state = thread_state;
thread_state = static_cast<ThreadState>(GetSuspendFlags() |
static_cast<u32>(old_state & ThreadState::Mask));
if (thread_state != old_state) {
KScheduler::OnThreadStateChanged(kernel, this, old_state);
}
this->UpdateState();
}
void KThread::WaitCancel() {
@@ -721,19 +722,22 @@ void KThread::TrySuspend() {
ASSERT(GetNumKernelWaiters() == 0);
// Perform the suspend.
Suspend();
this->UpdateState();
}
void KThread::Suspend() {
void KThread::UpdateState() {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
ASSERT(IsSuspendRequested());
// Set our suspend flags in state.
const auto old_state = thread_state;
thread_state = static_cast<ThreadState>(GetSuspendFlags()) | (old_state & ThreadState::Mask);
const auto new_state =
static_cast<ThreadState>(this->GetSuspendFlags()) | (old_state & ThreadState::Mask);
thread_state = new_state;
// Note the state change in scheduler.
KScheduler::OnThreadStateChanged(kernel, this, old_state);
if (new_state != old_state) {
KScheduler::OnThreadStateChanged(kernel, this, old_state);
}
}
void KThread::Continue() {
@@ -998,13 +1002,16 @@ ResultCode KThread::Run() {
// If the current thread has been asked to suspend, suspend it and retry.
if (GetCurrentThread(kernel).IsSuspended()) {
GetCurrentThread(kernel).Suspend();
GetCurrentThread(kernel).UpdateState();
continue;
}
// If we're not a kernel thread and we've been asked to suspend, suspend ourselves.
if (IsUserThread() && IsSuspended()) {
Suspend();
if (KProcess* owner = this->GetOwnerProcess(); owner != nullptr) {
if (IsUserThread() && IsSuspended()) {
this->UpdateState();
}
owner->IncrementThreadCount();
}
// Set our state and finish.
@@ -1029,11 +1036,18 @@ void KThread::Exit() {
{
KScopedSchedulerLock sl{kernel};
// Disallow all suspension.
suspend_allowed_flags = 0;
this->UpdateState();
// Disallow all suspension.
suspend_allowed_flags = 0;
// Start termination.
StartTermination();
// Register the thread as a work task.
KWorkerTaskManager::AddTask(kernel, KWorkerTaskManager::WorkerType::Exit, this);
}
}
@@ -1061,12 +1075,46 @@ ResultCode KThread::Sleep(s64 timeout) {
return ResultSuccess;
}
void KThread::IfDummyThreadTryWait() {
if (!IsDummyThread()) {
return;
}
if (GetState() != ThreadState::Waiting) {
return;
}
// Block until we can grab the lock.
KScopedSpinLock lk{dummy_wait_lock};
}
void KThread::IfDummyThreadBeginWait() {
if (!IsDummyThread()) {
return;
}
// Ensure the thread will block when IfDummyThreadTryWait is called.
dummy_wait_lock.Lock();
}
void KThread::IfDummyThreadEndWait() {
if (!IsDummyThread()) {
return;
}
// Ensure the thread will no longer block.
dummy_wait_lock.Unlock();
}
void KThread::BeginWait(KThreadQueue* queue) {
// Set our state as waiting.
SetState(ThreadState::Waiting);
// Set our wait queue.
wait_queue = queue;
// Special case for dummy threads to ensure they block.
IfDummyThreadBeginWait();
}
void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) {
@@ -1085,7 +1133,16 @@ void KThread::EndWait(ResultCode wait_result_) {
// If we're waiting, notify our queue that we're available.
if (GetState() == ThreadState::Waiting) {
if (wait_queue == nullptr) {
// This should never happen, but avoid a hard crash below to get this logged.
ASSERT_MSG(false, "wait_queue is nullptr!");
return;
}
wait_queue->EndWait(this, wait_result_);
// Special case for dummy threads to wakeup if necessary.
IfDummyThreadEndWait();
}
}

View File

@@ -19,6 +19,7 @@
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_worker_task.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_common.h"
#include "core/hle/kernel/svc_types.h"
@@ -100,7 +101,7 @@ enum class ThreadWaitReasonForDebugging : u32 {
[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>,
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,
public boost::intrusive::list_base_hook<> {
KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
@@ -111,6 +112,7 @@ private:
public:
static constexpr s32 DefaultThreadPriority = 44;
static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1;
static constexpr s32 DummyThreadPriority = Svc::LowestThreadPriority + 2;
explicit KThread(KernelCore& kernel_);
~KThread() override;
@@ -192,9 +194,9 @@ public:
void TrySuspend();
void Continue();
void UpdateState();
void Suspend();
void Continue();
constexpr void SetSyncedIndex(s32 index) {
synced_index = index;
@@ -385,6 +387,8 @@ public:
void OnTimer();
void DoWorkerTaskImpl();
static void PostDestroy(uintptr_t arg);
[[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread);
@@ -550,8 +554,12 @@ public:
return wait_reason_for_debugging;
}
[[nodiscard]] ThreadType GetThreadTypeForDebugging() const {
return thread_type_for_debugging;
[[nodiscard]] ThreadType GetThreadType() const {
return thread_type;
}
[[nodiscard]] bool IsDummyThread() const {
return GetThreadType() == ThreadType::Dummy;
}
void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) {
@@ -628,6 +636,14 @@ public:
return condvar_key;
}
// Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and
// therefore will not block on guest kernel synchronization primitives. These methods handle
// blocking as needed.
void IfDummyThreadTryWait();
void IfDummyThreadBeginWait();
void IfDummyThreadEndWait();
private:
static constexpr size_t PriorityInheritanceCountMax = 10;
union SyncObjectBuffer {
@@ -679,6 +695,8 @@ private:
void StartTermination();
void FinishTermination();
[[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
s32 prio, s32 virt_core, KProcess* owner, ThreadType type);
@@ -744,16 +762,17 @@ private:
bool resource_limit_release_hint{};
StackParameters stack_parameters{};
KSpinLock context_guard{};
KSpinLock dummy_wait_lock{};
// For emulation
std::shared_ptr<Common::Fiber> host_context{};
bool is_single_core{};
ThreadType thread_type{};
// For debugging
std::vector<KSynchronizationObject*> wait_objects_for_debugging;
VAddr mutex_wait_address_for_debugging{};
ThreadWaitReasonForDebugging wait_reason_for_debugging{};
ThreadType thread_type_for_debugging{};
public:
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;

View File

@@ -0,0 +1,18 @@
// Copyright 2022 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/kernel/k_synchronization_object.h"
namespace Kernel {
class KWorkerTask : public KSynchronizationObject {
public:
explicit KWorkerTask(KernelCore& kernel_);
void DoWorkerTask();
};
} // namespace Kernel

View File

@@ -0,0 +1,42 @@
// Copyright 2022 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_worker_task.h"
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
namespace Kernel {
KWorkerTask::KWorkerTask(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
void KWorkerTask::DoWorkerTask() {
if (auto* const thread = this->DynamicCast<KThread*>(); thread != nullptr) {
return thread->DoWorkerTaskImpl();
} else {
auto* const process = this->DynamicCast<KProcess*>();
ASSERT(process != nullptr);
return process->DoWorkerTaskImpl();
}
}
KWorkerTaskManager::KWorkerTaskManager() : m_waiting_thread(1, "yuzu:KWorkerTaskManager") {}
void KWorkerTaskManager::AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task) {
ASSERT(type <= WorkerType::Count);
kernel.WorkerTaskManager().AddTask(kernel, task);
}
void KWorkerTaskManager::AddTask(KernelCore& kernel, KWorkerTask* task) {
KScopedSchedulerLock sl(kernel);
m_waiting_thread.QueueWork([task]() {
// Do the task.
task->DoWorkerTask();
});
}
} // namespace Kernel

View File

@@ -0,0 +1,33 @@
// Copyright 2022 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "common/thread_worker.h"
namespace Kernel {
class KernelCore;
class KWorkerTask;
class KWorkerTaskManager final {
public:
enum class WorkerType : u32 {
Exit,
Count,
};
KWorkerTaskManager();
static void AddTask(KernelCore& kernel_, WorkerType type, KWorkerTask* task);
private:
void AddTask(KernelCore& kernel, KWorkerTask* task);
private:
Common::ThreadWorker m_waiting_thread;
};
} // namespace Kernel

View File

@@ -37,6 +37,7 @@
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_slab_heap.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/service_thread.h"
@@ -300,12 +301,10 @@ struct KernelCore::Impl {
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
KThread* GetHostDummyThread() {
auto make_thread = [this]() {
std::lock_guard lk(dummy_thread_lock);
auto& thread = dummy_threads.emplace_back(std::make_unique<KThread>(system.Kernel()));
KAutoObject::Create(thread.get());
ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess());
KThread* thread = KThread::Create(system.Kernel());
ASSERT(KThread::InitializeDummyThread(thread).IsSuccess());
thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
return thread.get();
return thread;
};
thread_local KThread* saved_thread = make_thread();
@@ -630,7 +629,7 @@ struct KernelCore::Impl {
const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
// Initialize memory managers
memory_manager = std::make_unique<KMemoryManager>();
memory_manager = std::make_unique<KMemoryManager>(system);
memory_manager->InitializeManager(KMemoryManager::Pool::Application,
application_pool.GetAddress(),
application_pool.GetEndAddress());
@@ -730,7 +729,6 @@ struct KernelCore::Impl {
std::mutex server_sessions_lock;
std::mutex registered_objects_lock;
std::mutex registered_in_use_objects_lock;
std::mutex dummy_thread_lock;
std::atomic<u32> next_object_id{0};
std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin};
@@ -787,9 +785,6 @@ struct KernelCore::Impl {
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
// Specifically tracked to be automatically destroyed with kernel
std::vector<std::unique_ptr<KThread>> dummy_threads;
bool is_multicore{};
std::atomic_bool is_shutting_down{};
bool is_phantom_mode_for_singlecore{};
@@ -797,6 +792,8 @@ struct KernelCore::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
KWorkerTaskManager worker_task_manager;
// System context
Core::System& system;
};
@@ -1137,6 +1134,14 @@ const Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() const {
return impl->slab_resource_counts;
}
KWorkerTaskManager& KernelCore::WorkerTaskManager() {
return impl->worker_task_manager;
}
const KWorkerTaskManager& KernelCore::WorkerTaskManager() const {
return impl->worker_task_manager;
}
bool KernelCore::IsPhantomModeForSingleCore() const {
return impl->IsPhantomModeForSingleCore();
}

View File

@@ -52,6 +52,7 @@ class KSharedMemory;
class KSharedMemoryInfo;
class KThread;
class KTransferMemory;
class KWorkerTaskManager;
class KWritableEvent;
class KCodeMemory;
class PhysicalCore;
@@ -343,6 +344,12 @@ public:
/// Gets the current slab resource counts.
const Init::KSlabResourceCounts& SlabResourceCounts() const;
/// Gets the current worker task manager, used for dispatching KThread/KProcess tasks.
KWorkerTaskManager& WorkerTaskManager();
/// Gets the current worker task manager, used for dispatching KThread/KProcess tasks.
const KWorkerTaskManager& WorkerTaskManager() const;
private:
friend class KProcess;
friend class KThread;

View File

@@ -12,6 +12,7 @@
#include "common/scope_exit.h"
#include "common/thread.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/service_thread.h"
@@ -50,6 +51,10 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
kernel.RegisterHostThread();
// Ensure the dummy thread allocated for this host thread is closed on exit.
auto* dummy_thread = kernel.GetCurrentEmuThread();
SCOPE_EXIT({ dummy_thread->Close(); });
while (true) {
std::function<void()> task;

View File

@@ -37,8 +37,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
{130, nullptr, "ActivateOpenContextRetention"},
{140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"},
{150, nullptr, "AuthenticateApplicationAsync"},
{151, nullptr, "Unknown151"},
{152, nullptr, "Unknown152"},
{151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"},
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
{190, nullptr, "GetUserLastOpenedApplication"},
{191, nullptr, "ActivateOpenContextHolder"},
{200, nullptr, "BeginUserRegistration"},

View File

@@ -37,8 +37,8 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
{130, nullptr, "ActivateOpenContextRetention"},
{140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"},
{150, nullptr, "AuthenticateApplicationAsync"},
{151, nullptr, "Unknown151"},
{152, nullptr, "Unknown152"},
{151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"},
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
{190, nullptr, "GetUserLastOpenedApplication"},
{191, nullptr, "ActivateOpenContextHolder"},
{997, nullptr, "DebugInvalidateTokenCacheForUser"},

View File

@@ -37,6 +37,7 @@ OMM::OMM(Core::System& system_) : ServiceFramework{system_, "omm"} {
{25, nullptr, "SetApplicationCecSettingsAndNotifyChanged"},
{26, nullptr, "GetOperationModeSystemInfo"},
{27, nullptr, "GetAppletFullAwakingSystemEvent"},
{28, nullptr, "CreateCradleFirmwareUpdater"},
};
// clang-format on

View File

@@ -17,7 +17,7 @@ public:
static const FunctionInfo functions[] = {
{0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},
{1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"},
{2, nullptr, "SetCpuOverclockEnabled"},
{2, &ISession::SetCpuOverclockEnabled, "SetCpuOverclockEnabled"},
};
RegisterHandlers(functions);
}
@@ -47,6 +47,18 @@ private:
rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode));
}
void SetCpuOverclockEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto cpu_overclock_enabled = rp.Pop<bool>();
LOG_WARNING(Service_APM, "(STUBBED) called, cpu_overclock_enabled={}",
cpu_overclock_enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
Controller& controller;
};

View File

@@ -41,14 +41,14 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
{27, nullptr, "SetVolumeMappingTableForDev"},
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{30, nullptr, "Unknown30"},
{31, nullptr, "Unknown31"},
{32, nullptr, "Unknown32"},
{33, nullptr, "Unknown33"},
{34, nullptr, "Unknown34"},
{10000, nullptr, "Unknown10000"},
{10001, nullptr, "Unknown10001"},
{10002, nullptr, "Unknown10002"},
{30, nullptr, "SetSpeakerAutoMuteEnabled"},
{31, nullptr, "IsSpeakerAutoMuteEnabled"},
{32, nullptr, "GetActiveOutputTarget"},
{33, nullptr, "GetTargetDeviceInfo"},
{34, nullptr, "AcquireTargetNotification"},
{10000, nullptr, "NotifyAudioOutputTargetForPlayReport"},
{10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"},
{10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"},
};
// clang-format on

View File

@@ -201,6 +201,22 @@ public:
{62, nullptr, "Unknown62"},
{63, nullptr, "Unknown63"},
{64, nullptr, "Unknown64"},
{65, nullptr, "Unknown65"},
{66, nullptr, "Unknown66"},
{67, nullptr, "Unknown67"},
{68, nullptr, "Unknown68"},
{69, nullptr, "Unknown69"},
{70, nullptr, "Unknown70"},
{71, nullptr, "Unknown71"},
{72, nullptr, "Unknown72"},
{73, nullptr, "Unknown73"},
{74, nullptr, "Unknown74"},
{75, nullptr, "Unknown75"},
{76, nullptr, "Unknown76"},
{100, nullptr, "Unknown100"},
{101, nullptr, "Unknown101"},
{110, nullptr, "Unknown102"},
{111, nullptr, "Unknown103"},
};
// clang-format on
@@ -249,6 +265,20 @@ public:
{7, nullptr, "AcquireRadioEvent"},
{8, nullptr, "AcquireGamepadPairingEvent"},
{9, nullptr, "IsGamepadPairingStarted"},
{10, nullptr, "StartAudioDeviceDiscovery"},
{11, nullptr, "StopAudioDeviceDiscovery"},
{12, nullptr, "IsDiscoveryingAudioDevice"},
{13, nullptr, "GetDiscoveredAudioDevice"},
{14, nullptr, "AcquireAudioDeviceConnectionEvent"},
{15, nullptr, "ConnectAudioDevice"},
{16, nullptr, "IsConnectingAudioDevice"},
{17, nullptr, "GetConnectedAudioDevices"},
{18, nullptr, "DisconnectAudioDevice"},
{19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
{20, nullptr, "GetPairedAudioDevices"},
{21, nullptr, "RemoveAudioDevicePairing"},
{22, nullptr, "RequestAudioDeviceConnectionRejection"},
{23, nullptr, "CancelAudioDeviceConnectionRejection"}
};
// clang-format on

View File

@@ -744,6 +744,7 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
{204, nullptr, "OpenDataFileSystemByProgramIndex"},
{205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"},
{206, nullptr, "OpenDataStorageByPath"},
{400, nullptr, "OpenDeviceOperator"},
{500, nullptr, "OpenSdCardDetectionEventNotifier"},
{501, nullptr, "OpenGameCardDetectionEventNotifier"},
@@ -796,6 +797,8 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{1014, nullptr, "OutputMultiProgramTagAccessLog"},
{1016, nullptr, "FlushAccessLogOnSdCard"},
{1017, nullptr, "OutputApplicationInfoAccessLog"},
{1018, nullptr, "SetDebugOption"},
{1019, nullptr, "UnsetDebugOption"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
{1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},

View File

@@ -27,13 +27,13 @@ public:
{10101, &IFriendService::GetFriendList, "GetFriendList"},
{10102, nullptr, "UpdateFriendInfo"},
{10110, nullptr, "GetFriendProfileImage"},
{10120, nullptr, "Unknown10120"},
{10121, nullptr, "Unknown10121"},
{10120, nullptr, "IsFriendListCacheAvailable"},
{10121, nullptr, "EnsureFriendListAvailable"},
{10200, nullptr, "SendFriendRequestForApplication"},
{10211, nullptr, "AddFacedFriendRequestForApplication"},
{10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"},
{10420, nullptr, "Unknown10420"},
{10421, nullptr, "Unknown10421"},
{10420, nullptr, "IsBlockedUserListCacheAvailable"},
{10421, nullptr, "EnsureBlockedUserListAvailable"},
{10500, nullptr, "GetProfileList"},
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
{10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
@@ -103,8 +103,8 @@ public:
{30900, nullptr, "SendFriendInvitation"},
{30910, nullptr, "ReadFriendInvitation"},
{30911, nullptr, "ReadAllFriendInvitations"},
{40100, nullptr, "Unknown40100"},
{40400, nullptr, "Unknown40400"},
{40100, nullptr, "DeleteFriendListCache"},
{40400, nullptr, "DeleteBlockedUserListCache"},
{49900, nullptr, "DeleteNetworkServiceAccountCache"},
};
// clang-format on

View File

@@ -1176,7 +1176,8 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
GetAppletResource()
->GetController<Controller_NPad>(HidController::NPad)
.SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
LOG_WARNING(Service_HID,

View File

@@ -211,6 +211,11 @@ public:
{127, nullptr, "Unknown127"},
{128, nullptr, "Unknown128"},
{129, nullptr, "Unknown129"},
{130, nullptr, "Unknown130"},
{131, nullptr, "Unknown131"},
{132, nullptr, "Unknown132"},
{133, nullptr, "Unknown133"},
{134, nullptr, "Unknown134"},
};
// clang-format on
@@ -287,6 +292,7 @@ public:
{502, nullptr, "RequestDownloadTicketForPrepurchasedContents"},
{503, nullptr, "RequestSyncTicket"},
{504, nullptr, "RequestDownloadTicketForPrepurchasedContents2"},
{505, nullptr, "RequestDownloadTicketForPrepurchasedContentsForAccount"},
};
// clang-format on

View File

@@ -158,6 +158,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{606, nullptr, "GetContentMetaStorage"},
{607, nullptr, "ListAvailableAddOnContent"},
{609, nullptr, "ListAvailabilityAssuredAddOnContent"},
{700, nullptr, "PushDownloadTaskList"},
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
@@ -289,6 +290,11 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2514, nullptr, "ClearTaskOfAsyncTaskManager"},
{2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"},
{2516, nullptr, "EnsureApplicationCertificate"},
{2517, nullptr, "CreateApplicationInstance"},
{2518, nullptr, "UpdateQualificationForDebug"},
{2519, nullptr, "IsQualificationTransitionSupported"},
{2520, nullptr, "IsQualificationTransitionSupportedByProcessId"},
{2521, nullptr, "GetRightsUserChangedEvent"},
{2800, nullptr, "GetApplicationIdOfPreomia"},
{3000, nullptr, "RegisterDeviceLockKey"},
{3001, nullptr, "UnregisterDeviceLockKey"},

View File

@@ -307,6 +307,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{202, nullptr, "SetFieldTestingFlag"},
{203, nullptr, "GetPanelCrcMode"},
{204, nullptr, "SetPanelCrcMode"},
{205, nullptr, "GetNxControllerSettingsEx"},
{206, nullptr, "SetNxControllerSettingsEx"},
};
// clang-format on

View File

@@ -17,19 +17,19 @@ public:
explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetDsEndpoint"},
{1, nullptr, "GetSetupEvent"},
{2, nullptr, "Unknown2"},
{3, nullptr, "EnableInterface"},
{4, nullptr, "DisableInterface"},
{5, nullptr, "CtrlInPostBufferAsync"},
{6, nullptr, "CtrlOutPostBufferAsync"},
{7, nullptr, "GetCtrlInCompletionEvent"},
{8, nullptr, "GetCtrlInReportData"},
{9, nullptr, "GetCtrlOutCompletionEvent"},
{10, nullptr, "GetCtrlOutReportData"},
{11, nullptr, "StallCtrl"},
{12, nullptr, "AppendConfigurationData"},
{0, nullptr, "BindDevice"},
{1, nullptr, "BindClientProcess"},
{2, nullptr, "AddInterface"},
{3, nullptr, "GetStateChangeEvent"},
{4, nullptr, "GetState"},
{5, nullptr, "ClearDeviceData"},
{6, nullptr, "AddUsbStringDescriptor"},
{7, nullptr, "DeleteUsbStringDescriptor"},
{8, nullptr, "SetUsbDeviceDescriptor"},
{9, nullptr, "SetBinaryObjectStore"},
{10, nullptr, "Enable"},
{11, nullptr, "Disable"},
{12, nullptr, "Unknown12"},
};
// clang-format on
@@ -42,19 +42,7 @@ public:
explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "BindDevice"},
{1, nullptr, "BindClientProcess"},
{2, nullptr, "GetDsInterface"},
{3, nullptr, "GetStateChangeEvent"},
{4, nullptr, "GetState"},
{5, nullptr, "ClearDeviceData"},
{6, nullptr, "AddUsbStringDescriptor"},
{7, nullptr, "DeleteUsbStringDescriptor"},
{8, nullptr, "SetUsbDeviceDescriptor"},
{9, nullptr, "SetBinaryObjectStore"},
{10, nullptr, "Enable"},
{11, nullptr, "Disable"},
{12, nullptr, "Unknown12"},
{0, nullptr, "OpenDsService"},
};
// clang-format on
@@ -120,7 +108,7 @@ public:
{5, nullptr, "DestroyInterfaceAvailableEvent"},
{6, nullptr, "GetInterfaceStateChangeEvent"},
{7, nullptr, "AcquireUsbIf"},
{8, nullptr, "Unknown8"},
{8, nullptr, "ResetDevice"},
};
// clang-format on

View File

@@ -53,6 +53,7 @@ public:
{35, nullptr, "Unknown35"},
{36, nullptr, "Unknown36"},
{37, nullptr, "Unknown37"},
{38, nullptr, "Unknown38"},
};
// clang-format on
@@ -117,7 +118,6 @@ public:
{49, nullptr, "Unknown49"},
{50, nullptr, "Unknown50"},
{51, nullptr, "Unknown51"},
{52, nullptr, "Unknown52"},
};
// clang-format on

View File

@@ -16,6 +16,7 @@ constexpr int mouse_axis_x = 0;
constexpr int mouse_axis_y = 1;
constexpr int wheel_axis_x = 2;
constexpr int wheel_axis_y = 3;
constexpr int motion_wheel_y = 4;
constexpr int touch_axis_x = 10;
constexpr int touch_axis_y = 11;
constexpr PadIdentifier identifier = {
@@ -30,8 +31,9 @@ Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_))
PreSetAxis(identifier, mouse_axis_y);
PreSetAxis(identifier, wheel_axis_x);
PreSetAxis(identifier, wheel_axis_y);
PreSetAxis(identifier, motion_wheel_y);
PreSetAxis(identifier, touch_axis_x);
PreSetAxis(identifier, touch_axis_x);
PreSetAxis(identifier, touch_axis_y);
update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); });
}
@@ -48,6 +50,8 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity);
}
SetAxis(identifier, motion_wheel_y, 0.0f);
if (mouse_panning_timout++ > 20) {
StopPanning();
}
@@ -136,6 +140,7 @@ void Mouse::MouseWheelChange(int x, int y) {
wheel_position.y += y;
SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
SetAxis(identifier, motion_wheel_y, static_cast<f32>(y) / 100.0f);
}
void Mouse::ReleaseAllButtons() {
@@ -171,13 +176,39 @@ AnalogMapping Mouse::GetAnalogMappingForDevice(
return mapping;
}
Common::Input::ButtonNames Mouse::GetUIButtonName(const Common::ParamPackage& params) const {
const auto button = static_cast<MouseButton>(params.Get("button", 0));
switch (button) {
case MouseButton::Left:
return Common::Input::ButtonNames::ButtonLeft;
case MouseButton::Right:
return Common::Input::ButtonNames::ButtonRight;
case MouseButton::Wheel:
return Common::Input::ButtonNames::ButtonMouseWheel;
case MouseButton::Backward:
return Common::Input::ButtonNames::ButtonBackward;
case MouseButton::Forward:
return Common::Input::ButtonNames::ButtonForward;
case MouseButton::Task:
return Common::Input::ButtonNames::ButtonTask;
case MouseButton::Extra:
return Common::Input::ButtonNames::ButtonExtra;
case MouseButton::Undefined:
default:
return Common::Input::ButtonNames::Undefined;
}
}
Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) const {
if (params.Has("button")) {
return Common::Input::ButtonNames::Value;
return GetUIButtonName(params);
}
if (params.Has("axis")) {
return Common::Input::ButtonNames::Value;
}
if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) {
return Common::Input::ButtonNames::Engine;
}
return Common::Input::ButtonNames::Invalid;
}

View File

@@ -69,6 +69,8 @@ private:
void UpdateThread(std::stop_token stop_token);
void StopPanning();
Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
Common::Vec2<int> mouse_origin;
Common::Vec2<int> last_mouse_position;
Common::Vec2<float> last_mouse_change;

View File

@@ -198,9 +198,9 @@ public:
if (sdl_controller) {
switch (SDL_GameControllerGetType(sdl_controller.get())) {
case SDL_CONTROLLER_TYPE_XBOX360:
return "XBox 360 Controller";
return "Xbox 360 Controller";
case SDL_CONTROLLER_TYPE_XBOXONE:
return "XBox One Controller";
return "Xbox One Controller";
case SDL_CONTROLLER_TYPE_PS3:
return "DualShock 3 Controller";
case SDL_CONTROLLER_TYPE_PS4:

View File

@@ -173,7 +173,7 @@ void InputEngine::ResetButtonState() {
SetButton(controller.first, button.first, false);
}
for (const auto& button : controller.second.hat_buttons) {
SetHatButton(controller.first, button.first, false);
SetHatButton(controller.first, button.first, 0);
}
}
}

View File

@@ -143,6 +143,19 @@ void MappingFactory::RegisterMotion(const MappingData& data) {
}
new_input.Set("port", static_cast<int>(data.pad.port));
new_input.Set("pad", static_cast<int>(data.pad.pad));
// If engine is mouse map the mouse position as 3 axis motion
if (data.engine == "mouse") {
new_input.Set("axis_x", 1);
new_input.Set("invert_x", "-");
new_input.Set("axis_y", 0);
new_input.Set("axis_z", 4);
new_input.Set("range", 1.0f);
new_input.Set("deadzone", 0.0f);
input_queue.Push(new_input);
return;
}
switch (data.type) {
case EngineInputType::Button:
case EngineInputType::HatButton:

View File

@@ -458,9 +458,10 @@ void EmitContext::DefineGenericOutput(size_t index, u32 invocations) {
std::string definition{fmt::format("layout(location={}", index)};
const u32 remainder{4 - element};
const TransformFeedbackVarying* xfb_varying{};
if (!runtime_info.xfb_varyings.empty()) {
xfb_varying = &runtime_info.xfb_varyings[base_index + element];
xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr;
const size_t xfb_varying_index{base_index + element};
if (xfb_varying_index < runtime_info.xfb_varyings.size()) {
xfb_varying = &runtime_info.xfb_varyings[xfb_varying_index];
xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr;
}
const u32 num_components{xfb_varying ? xfb_varying->components : remainder};
if (element > 0) {

View File

@@ -164,9 +164,10 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invo
while (element < 4) {
const u32 remainder{4 - element};
const TransformFeedbackVarying* xfb_varying{};
if (!ctx.runtime_info.xfb_varyings.empty()) {
xfb_varying = &ctx.runtime_info.xfb_varyings[base_attr_index + element];
xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr;
const size_t xfb_varying_index{base_attr_index + element};
if (xfb_varying_index < ctx.runtime_info.xfb_varyings.size()) {
xfb_varying = &ctx.runtime_info.xfb_varyings[xfb_varying_index];
xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr;
}
const u32 num_components{xfb_varying ? xfb_varying->components : remainder};

View File

@@ -66,7 +66,7 @@ private:
bool initialized{};
NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None};
AVCodec* av_codec{nullptr};
const AVCodec* av_codec{nullptr};
AVCodecContext* av_codec_ctx{nullptr};
AVBufferRef* av_gpu_decoder{nullptr};

View File

@@ -155,9 +155,6 @@ uint SwizzleOffset(uvec2 pos) {
// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
// is the same as [(num_bits - 1):0] and repeats all the way down.
uint Replicate(uint val, uint num_bits, uint to_bit) {
if (num_bits == 0 || to_bit == 0) {
return 0;
}
const uint v = val & uint((1 << num_bits) - 1);
uint res = v;
uint reslen = num_bits;
@@ -187,42 +184,57 @@ uint ReplicateBitTo9(uint value) {
return REPLICATE_1_BIT_TO_9_TABLE[value];
}
uint FastReplicateTo8(uint value, uint num_bits) {
switch (num_bits) {
case 1:
return REPLICATE_1_BIT_TO_8_TABLE[value];
case 2:
return REPLICATE_2_BIT_TO_8_TABLE[value];
case 3:
return REPLICATE_3_BIT_TO_8_TABLE[value];
case 4:
return REPLICATE_4_BIT_TO_8_TABLE[value];
case 5:
return REPLICATE_5_BIT_TO_8_TABLE[value];
case 6:
return REPLICATE_6_BIT_TO_8_TABLE[value];
case 7:
return REPLICATE_7_BIT_TO_8_TABLE[value];
case 8:
uint FastReplicate(uint value, uint num_bits, uint to_bit) {
if (num_bits == 0) {
return 0;
}
if (num_bits == to_bit) {
return value;
}
return Replicate(value, num_bits, 8);
if (to_bit == 6) {
switch (num_bits) {
case 1:
return REPLICATE_1_BIT_TO_6_TABLE[value];
case 2:
return REPLICATE_2_BIT_TO_6_TABLE[value];
case 3:
return REPLICATE_3_BIT_TO_6_TABLE[value];
case 4:
return REPLICATE_4_BIT_TO_6_TABLE[value];
case 5:
return REPLICATE_5_BIT_TO_6_TABLE[value];
default:
break;
}
} else { /* if (to_bit == 8) */
switch (num_bits) {
case 1:
return REPLICATE_1_BIT_TO_8_TABLE[value];
case 2:
return REPLICATE_2_BIT_TO_8_TABLE[value];
case 3:
return REPLICATE_3_BIT_TO_8_TABLE[value];
case 4:
return REPLICATE_4_BIT_TO_8_TABLE[value];
case 5:
return REPLICATE_5_BIT_TO_8_TABLE[value];
case 6:
return REPLICATE_6_BIT_TO_8_TABLE[value];
case 7:
return REPLICATE_7_BIT_TO_8_TABLE[value];
default:
break;
}
}
return Replicate(value, num_bits, to_bit);
}
uint FastReplicateTo8(uint value, uint num_bits) {
return FastReplicate(value, num_bits, 8);
}
uint FastReplicateTo6(uint value, uint num_bits) {
switch (num_bits) {
case 1:
return REPLICATE_1_BIT_TO_6_TABLE[value];
case 2:
return REPLICATE_2_BIT_TO_6_TABLE[value];
case 3:
return REPLICATE_3_BIT_TO_6_TABLE[value];
case 4:
return REPLICATE_4_BIT_TO_6_TABLE[value];
case 5:
return REPLICATE_5_BIT_TO_6_TABLE[value];
}
return Replicate(value, num_bits, 6);
return FastReplicate(value, num_bits, 6);
}
uint Div3Floor(uint v) {

View File

@@ -1038,7 +1038,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
}
if (has_ext_shader_atomic_int64) {
VkPhysicalDeviceShaderAtomicInt64Features atomic_int64;
atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES;
atomic_int64.pNext = nullptr;
features.pNext = &atomic_int64;
physical.GetFeatures2KHR(features);

View File

@@ -65,18 +65,18 @@ const std::array<int, 2> Config::default_stick_mod = {
// This must be in alphabetical order according to action name as it must have the same order as
// UISetting::values.shortcuts, which is alphabetically ordered.
// clang-format off
const std::array<UISettings::Shortcut, 21> Config::default_hotkeys{{
const std::array<UISettings::Shortcut, 20> Config::default_hotkeys{{
{QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}},
{QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}},
{QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}},
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}},
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}},
{QStringLiteral("Decrease Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("-"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("Exit Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Exit yuzu"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}},
{QStringLiteral("Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}},
{QStringLiteral("Increase Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("+"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Mute Audio"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("TAS Start/Stop"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}},
@@ -85,7 +85,6 @@ const std::array<UISettings::Shortcut, 21> Config::default_hotkeys{{
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Toggle Framerate Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut}},
}};
// clang-format on
@@ -743,7 +742,9 @@ void Config::ReadUIValues() {
qt_config->beginGroup(QStringLiteral("UI"));
UISettings::values.theme =
ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second))
ReadSetting(
QStringLiteral("theme"),
QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second))
.toString();
ReadBasicSetting(UISettings::values.enable_discord_presence);
ReadBasicSetting(UISettings::values.select_user_on_boot);
@@ -1271,7 +1272,7 @@ void Config::SaveUIValues() {
qt_config->beginGroup(QStringLiteral("UI"));
WriteSetting(QStringLiteral("theme"), UISettings::values.theme,
QString::fromUtf8(UISettings::themes[0].second));
QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second));
WriteBasicSetting(UISettings::values.enable_discord_presence);
WriteBasicSetting(UISettings::values.select_user_on_boot);

View File

@@ -46,7 +46,15 @@ public:
default_mouse_buttons;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
static const std::array<UISettings::Shortcut, 21> default_hotkeys;
static const std::array<UISettings::Shortcut, 20> default_hotkeys;
static constexpr UISettings::Theme default_theme{
#ifdef _WIN32
UISettings::Theme::DarkColorful
#else
UISettings::Theme::DefaultColorful
#endif
};
private:
void Initialize(const std::string& config_name);

View File

@@ -102,6 +102,16 @@ QString GetButtonName(Common::Input::ButtonNames button_name) {
return QObject::tr("Share");
case Common::Input::ButtonNames::Options:
return QObject::tr("Options");
case Common::Input::ButtonNames::ButtonMouseWheel:
return QObject::tr("Wheel", "Indicates the mouse wheel");
case Common::Input::ButtonNames::ButtonBackward:
return QObject::tr("Backward");
case Common::Input::ButtonNames::ButtonForward:
return QObject::tr("Forward");
case Common::Input::ButtonNames::ButtonTask:
return QObject::tr("Task");
case Common::Input::ButtonNames::ButtonExtra:
return QObject::tr("Extra");
default:
return QObject::tr("[undefined]");
}

View File

@@ -95,7 +95,7 @@ std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList(
std::size_t row = 0;
auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) {
for (std::size_t i = 0; i < threads.size(); ++i) {
if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) {
if (threads[i]->GetThreadType() == Kernel::ThreadType::User) {
item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system));
item_list.back()->row = row;
}
@@ -153,7 +153,7 @@ QString WaitTreeCallstack::GetText() const {
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
std::vector<std::unique_ptr<WaitTreeItem>> list;
if (thread.GetThreadTypeForDebugging() != Kernel::ThreadType::User) {
if (thread.GetThreadType() != Kernel::ThreadType::User) {
return list;
}

View File

@@ -1008,33 +1008,24 @@ void GMainWindow::InitializeHotkeys() {
ToggleFullscreen();
}
});
connect_shortcut(QStringLiteral("Toggle Speed Limit"), [&] {
Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue());
UpdateStatusBar();
});
constexpr u16 SPEED_LIMIT_STEP = 5;
connect_shortcut(QStringLiteral("Increase Speed Limit"), [&] {
if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP +
Settings::values.speed_limit.GetValue());
UpdateStatusBar();
}
});
connect_shortcut(QStringLiteral("Decrease Speed Limit"), [&] {
if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) {
Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() -
SPEED_LIMIT_STEP);
UpdateStatusBar();
}
});
connect_shortcut(QStringLiteral("Change Docked Mode"), [&] {
Settings::values.use_docked_mode.SetValue(!Settings::values.use_docked_mode.GetValue());
OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
Settings::values.use_docked_mode.GetValue(), *system);
dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
});
connect_shortcut(QStringLiteral("Mute Audio"),
connect_shortcut(QStringLiteral("Audio Mute/Unmute"),
[] { Settings::values.audio_muted = !Settings::values.audio_muted; });
connect_shortcut(QStringLiteral("Audio Volume Down"), [] {
const auto current_volume = static_cast<int>(Settings::values.volume.GetValue());
const auto new_volume = std::max(current_volume - 5, 0);
Settings::values.volume.SetValue(static_cast<u8>(new_volume));
});
connect_shortcut(QStringLiteral("Audio Volume Up"), [] {
const auto current_volume = static_cast<int>(Settings::values.volume.GetValue());
const auto new_volume = std::min(current_volume + 5, 100);
Settings::values.volume.SetValue(static_cast<u8>(new_volume));
});
connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] {
Settings::values.disable_fps_limit.SetValue(!Settings::values.disable_fps_limit.GetValue());
});

View File

@@ -29,6 +29,15 @@ struct Shortcut {
ContextualShortcut shortcut;
};
enum class Theme {
Default,
DefaultColorful,
Dark,
DarkColorful,
MidnightBlue,
MidnightBlueColorful,
};
using Themes = std::array<std::pair<const char*, const char*>, 6>;
extern const Themes themes;