Compare commits

...

158 Commits

Author SHA1 Message Date
Lioncash cd4aa50207 yuzu/game_list: Use non-deprecated version of QString's split() function
The previous overload of split() was deprecated in 5.14.
2022-02-01 11:41:31 -05:00
Morph 7432343214 Merge pull request #7825 from lioncash/nodisc2
common/file: Remove [[nodiscard]] from Open()
2022-02-01 02:29:36 -05:00
Lioncash 8f32bab4c9 common/file: Remove [[nodiscard]] from Open()
Since this has a void return value, there's nothing that can actually be
used.
2022-02-01 02:19:21 -05:00
Morph 26a9dc3f65 Merge pull request #7824 from lioncash/scache
video_core/shader_cache: Take std::span in RemoveShadersFromStorage()
2022-02-01 01:58:38 -05:00
Lioncash 360a97ab54 video_core/shader_cache: Remove unused algorithm include 2022-02-01 01:41:05 -05:00
Lioncash 540ed72e99 video_core/shader_cache: Take std::span in RemoveShadersFromStorage()
Same behavior, but without the need to move into the function to avoid
an allocation.
2022-02-01 01:40:41 -05:00
Mai M c81793029d Merge pull request #7822 from zhaobot/tx-update-20220201021425
Update translations (2022-02-01)
2022-01-31 22:15:09 -05:00
The yuzu Community 1e66eaf929 Update translations (2022-02-01) 2022-02-01 02:14:44 +00:00
bunnei 7ddccb55d2 Merge pull request #7821 from german77/espada_aguda
svc: Add 32 bit SynchronizePreemptionState
2022-01-31 19:13:46 -07:00
bunnei 34dc1c8bc2 Merge pull request #7805 from FernandoS27/rodrigo-failed-me
Inline2Memory: Flush before writing buffer.
2022-01-31 18:08:21 -07:00
Narr the Reg 1ed22b4613 svc: Add 32 bit SynchronizePreemptionState
Used by Espgaluda II
2022-01-31 19:02:41 -06:00
Fernando Sahmkow 8a6e6465a7 Rasterizer: Refactor inlineToMemory. 2022-02-01 01:47:28 +01:00
Fernando Sahmkow d0a5a48948 GPU: Improve syncing. 2022-01-29 23:02:04 +01:00
Fernando Sahmkow 4258d515e6 Rasterizer: Implement Inline2Memory Acceleration. 2022-01-29 22:53:27 +01:00
Fernando Sahmkow f54280dafd Inline2Memory: Flush before writting buffer. 2022-01-29 17:42:28 +01:00
Morph 11099dda2e Merge pull request #7791 from german77/wall_clock
wall_clock: Use standard wall clock if rtsc frequency is too low
2022-01-28 20:04:24 -05:00
Morph 64a68ccbb4 Merge pull request #7800 from ameerj/spirv-int64-storage
spirv_atomic: Define U32x2 storage buffers for 64-bit storage atomics
2022-01-28 20:03:50 -05:00
ameerj 4790ba7839 spirv_atomic: Define U32x2 storage buffers for 64-bit storage atomics
Some drivers do not support 64-bit atomics, and fallback to atomically modifying U32x2 vectors. This change ensures that U32x2 storage vectors are defined in the spir-v shader when 64-bit atomics are used.

Fixes a hang on some devices, notably Intel GPUs, when booting Pokemon Legends Arceus
2022-01-28 19:00:04 -05:00
Morph 1900abde13 Merge pull request #7784 from german77/ds5
input_common: Add DS5 to HD rumble list
2022-01-28 18:36:28 -05:00
Morph 60b5670577 Merge pull request #7787 from bunnei/scheduler-deadlock-fix
hle: kernel: KScheduler: Fix deadlock with core waiting for a thread lock that has migrated.
2022-01-28 18:30:29 -05:00
Morph b00406c8e4 Merge pull request #7788 from ameerj/stream-buffer-begin
buffer_cache: Reduce stream buffer allocations when expanding from the left
2022-01-28 18:30:01 -05:00
Morph 8dea7fa129 Merge pull request #7786 from ameerj/vmnmx-sel
video_minimum_maximum: Implement src operand selectors
2022-01-28 18:24:56 -05:00
Morph 2241d8c971 Merge pull request #7799 from ameerj/amd-xfb
emit_spirv: Add Xfb execution mode when transform feedback is used
2022-01-28 17:55:17 -05:00
ameerj beaf7654bb emit_spirv: Add Xfb execution mode when transform feedback is used
Fixes Transform Feedback on Vulkan AMD drivers.
2022-01-28 16:32:48 -05:00
bunnei 0dec42431f Merge pull request #7770 from german77/motion-threshold
input_common: Add option to configure gyro threshold
2022-01-27 15:44:04 -08:00
german77 e4c63d432d wall_clock: use standard wall clock if rtsc frequency is too low 2022-01-27 17:07:52 -06:00
ameerj f300a1d54b buffer_cache: Reduce stream buffer allocations when expanding from the left
The existing stream buffer optimization accounts for size increases at the end of the allocated buffer.
This adds the same optimization, increasing the size from the beginning of the buffer as well to reduce buffer allocations when expanding the same buffer from the left.
2022-01-27 15:31:43 -05:00
bunnei 3a1a3dd0db hle: kernel: KScheduler: Fix deadlock with core waiting for a thread lock that has migrated.
- Previously, it was possible for a thread migration to occur from core A to core B.
- Next, core B waits on a guest lock that must be released by a thread queued for core A.
- Meanwhile, core A is still waiting on the core B's current thread lock - resulting in a deadlock.
- Fix this by try-locking the thread lock.
- Fixes softlocks in FF8 and Pokemon Legends Arceus.
2022-01-27 12:17:14 -08:00
ameerj 74e6e3623f video_minimum_maximum: Implement src operand selectors
Used by Pokemon Legends: Arceus
2022-01-27 14:55:08 -05:00
Morph 8a244dd3d3 Merge pull request #7783 from lioncash/abi-cexpr
common/xbyak_api: Make BuildRegSet() constexpr
2022-01-27 10:29:34 -05:00
Narr the Reg fd1cef5616 input_common: Add DS5 to HD rumble list 2022-01-26 21:49:32 -06:00
bunnei adcac857f8 Merge pull request #7762 from bunnei/un-map-improve
Kernel Memory Updates (Part 4): Improve Un/MapPages, and more.
2022-01-26 17:54:20 -08:00
Lioncash f6a049337e common/xbyak_api: Make BuildRegSet() constexpr
This allows us to eliminate any static constructors that would have been
emitted due to the function not being constexpr.
2022-01-26 16:29:15 -05:00
bunnei 40050c1188 Merge pull request #7780 from lioncash/macro
video_core/macro: Move impl classes into their cpp files
2022-01-26 12:39:59 -08:00
bunnei 9bf7ad97f5 Merge pull request #7769 from german77/no-control
yuzu: Add setting to disable controller navigation
2022-01-25 20:24:42 -08:00
bunnei 5723145165 Merge pull request #7768 from Moonlacer/fsr-1.0.2
Update AMD FidelityFX Super Resolution™ to 1.0.2
2022-01-25 17:32:44 -08:00
Morph 84cc22b21b Merge pull request #7777 from lioncash/nodisc
shader_recompiler: Remove unnecessary [[nodiscard]] specifier
2022-01-25 16:16:20 -05:00
Morph c93dd45997 Merge pull request #7779 from lioncash/gpu-iface
gpu: Remove obsoleted CDmaPusher() accessors
2022-01-25 16:16:04 -05:00
Morph a1c4bca908 Merge pull request #7778 from lioncash/comma
vk_fsr: Replace comma operator with semicolon
2022-01-25 16:15:53 -05:00
Morph 432f4441b9 Merge pull request #7774 from lioncash/mapping
input_common/main: Pass MappingData by const reference in callbacks
2022-01-25 16:15:45 -05:00
Morph 306b3491c4 Merge pull request #7773 from lioncash/udp-deprecated
input_common/udp_client: Replace deprecated from_string()/to_ulong() functions
2022-01-25 16:15:27 -05:00
Morph 8dbad556ec Merge pull request #7771 from lioncash/assert
kernel/k_affinity_mask: Remove duplicated assert
2022-01-25 16:15:18 -05:00
Lioncash a8a4f37628 video_core/macro: Add missing <cstring> header
Necessary since memcpy is used.
2022-01-25 14:10:02 -05:00
Lioncash 81d1a1133d video_core/macro_interpreter: Move impl class to the cpp file
Keeps the implementation hidden from the intended API and lessens the
header dependencies on the interpreter's header.
2022-01-25 14:03:48 -05:00
Lioncash cfd9f7d25b video_core/macro_hle: Return unique_ptr directly from GetHLEProgram()
Same behavior, but less code and header dependencies.
2022-01-25 13:50:14 -05:00
Lioncash a05d9405b9 video_core/macro: Remove unused parameter from Execute()
Simplifies the function interface.
2022-01-25 13:41:38 -05:00
Lioncash 74f80299b0 video_core/macro_jit_x64: Remove unused impl class member
Reduces the size of the impl class a tiny bit.
2022-01-25 13:33:09 -05:00
Lioncash f11eefed56 video_core/macro_jit_x64: Decouple PersistentCallerSavedRegs() from impl
This doesn't depend on class state and can just be a regular function.
2022-01-25 13:31:54 -05:00
Lioncash 6b873b72ae video_core/macro_jit_x64: Move impl class into cpp file
Keeps the implementation internalized and also reduces API-facing header
dependencies.

Notably, this fully internalizes all of the xbyak externals.
2022-01-25 13:31:46 -05:00
Lioncash a3c81745b1 video_core/macro_hle: Move impl class into cpp file
Given it's intended to be an internal implementation class, we can move
it into the cpp file to ensure that.

This also lets us move some header dependencies into the cpp file as
well.
2022-01-25 13:15:48 -05:00
Lioncash d8486a9968 gpu: Tidy up forward declarations
Over time a few forward declarations became unnecessary, so we can
remove these to tidy up the header a little bit.
2022-01-25 13:05:39 -05:00
Lioncash 9b38c8ef08 gpu: Remove obsoleted CDMAPusher() accessors
These were obsoleted in 2c47f8aa18 but
were accidentally overlooked.
2022-01-25 12:53:56 -05:00
Lioncash e7af84670d vk_fsr: Replace comma operator with semicolon
Generally, we should be ending statements with a semicolon not a comma

Resolves a clang diagnostic.
2022-01-25 12:42:27 -05:00
Lioncash b46ec4efea shader_recompiler: Remove unnecessary [[nodiscard]]
Since ConvertLegacyToGeneric has a void return value, there's nothing
that is actually returned by the function.
2022-01-25 12:16:09 -05:00
bunnei 4f9f55ec21 Merge pull request #7765 from bunnei/update-thread-count
hle: kernel: KThread: Improve Increment/Decrement RunningThreadCount.
2022-01-24 18:58:48 -08:00
bunnei 3442365127 Merge pull request #7760 from german77/inverted_keyboard
yuzu: Add modifiers for keyboard
2022-01-24 15:41:49 -08:00
Lioncash 651358d0b6 input_common/input_engine: Ensure PadIdentifier UUIDs have a valid initial state
The default constructor of a UUID instance doesn't initialize the
underlying array.
2022-01-24 11:57:48 -05:00
Lioncash 187c9d7e33 input_common/input_mapping: Simplify UUID validity checks
Makes the checks a little more intuitive to read and doesn't construct
an extra UUID instance
2022-01-24 11:49:52 -05:00
Lioncash 0849be094e input_common/input_mapping: Add missing includes
Ensures that the class always sees the types it needs.
2022-01-24 11:49:31 -05:00
Lioncash 8bb39750a1 input_common/input_mapping: Remove const from return value
Top-level const on a return by value can inhibit move semantics, and is
unnecessary.
2022-01-24 11:39:20 -05:00
Lioncash 12e7d3b254 input_common/input_mapping: Default constructor 2022-01-24 11:37:48 -05:00
Lioncash 51dd3da11c input_common/main: Pass MappingData by const reference in callbacks
Avoids creating unnecessary 168 byte copies per callback invocation.
2022-01-24 11:31:43 -05:00
Lioncash 87eb3cb083 input_common/udp_client: Replace deprecated from_string()/to_ulong() functions
These are deprecated and make_address variants and to_uint() should be used instead.
2022-01-24 11:14:30 -05:00
Lioncash b084a9bf0a input_common/udp_client: Prevent unnecessary string copies
We can also remove some redundant const on the return values, since
these don't do anything
2022-01-24 10:58:25 -05:00
Lioncash 2f12caccf9 kernel/k_affinity_mask: Remove duplicated assert
This is already checked inside GetCoreBit()
2022-01-24 10:35:22 -05:00
german77 ebf19616f4 input_common: Add option to configure gyro threshold 2022-01-23 21:54:33 -06:00
german77 b998aa5504 yuzu: Add setting to disable controller navigation 2022-01-23 21:08:49 -06:00
Moonlacer fdde08bd01 Update FSR to 1.0.2
Updates yuzu's FSR implementation to 1.0.2
2022-01-23 14:38:48 -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 59add00d4a hle: kernel: KThread: Improve Increment/Decrement RunningThreadCount.
- Previously implementation was incorrect, and would occasionally underflow.
2022-01-22 21:09:45 -08:00
bunnei e791da9791 core: hle: kernel: KPageTable: Various improvements to MapPages and UnmapPages. 2022-01-22 20:51:34 -08:00
bunnei 07add23251 core: hle: kernel: KPageTable: MapProcessCode: Various cleanup. 2022-01-22 20:51:34 -08:00
bunnei ee25e0a40b core: hle: kernel: KPageTable: ReserveTransferMemory: Various cleanup. 2022-01-22 20:51:34 -08:00
bunnei 0cee5e1af8 core: hle: kernel: KPageTable: ResetTransferMemory: Various cleanup. 2022-01-22 20:51:34 -08:00
bunnei ffcaf5af90 core: hle: kernel: KPageTable: SetMemoryAttribute: Various cleanup. 2022-01-22 20:51:34 -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 2935c9d8de core: hle: kernel: KPageTable: Assert valid address on GetPhysicalAddr. 2022-01-22 01:33:26 -08:00
bunnei 264bb5abf7 core: hle: kernel: KPageTable: Operate: Assert lock ownership. 2022-01-22 01:33:26 -08:00
bunnei 0137f2e6e1 core: hle: kernel: KPageTable: SetHeapSize: Cleanup & take physical memory lock. 2022-01-22 01:33:26 -08:00
bunnei 6d8e498f76 core: hle: kernel: Refactor Un/MapPhysicalMemory to remove unnecessary methods. 2022-01-22 01:33:26 -08:00
bunnei b8b1b58f36 core: hle: kernel: Rename Un/Map to Un/MapMeory. 2022-01-22 01:33:26 -08: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
Narr the Reg 7d133fd37e yuzu: Add modifiers for keyboard 2022-01-21 20:41:50 -06: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
Narr the Reg 36144a5690 input_common: Report battery for UDP controllers 2022-01-17 13:30:15 -06: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 480b03b645 Merge pull request #7713 from gidoly/patch-3
Change default name for playstation controllers
2022-01-15 02:39:58 -08:00
bunnei 5eda606952 Merge pull request #7711 from bunnei/fix-service-thread-race-v2
hle: kernel: Fix service_threads access to be thread safe V2.
2022-01-14 22:22:39 -08:00
gidoly 7978ea4e8c Change default name for ps controllers
Minor nitpick
Code is from narr
2022-01-15 10:29:42 +09: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
bunnei cc112f971e hle: kernel: Fix service_threads access to be thread safe V2.
- PR #7699 attempted to fix CreateServiceThread and ReleaseServiceThread to be thread safe, but inadvertently introduced a possible dead-lock.
- With this PR, we use a worker thread to manage the service thread list, allowing it only to be accessed by a single thread, and guaranteeing threads will not destroy themselves.
- Fixes a rare crash in Pokemon Sword/Shield, I've now run this game for ~12 hours non-stop and am quite confident this is a good solution for this issue.
2022-01-14 16:02:57 -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
130 changed files with 23922 additions and 8004 deletions
+461 -315
View File
File diff suppressed because it is too large Load Diff
+492 -346
View File
File diff suppressed because it is too large Load Diff
+506 -360
View File
File diff suppressed because it is too large Load Diff
+489 -343
View File
File diff suppressed because it is too large Load Diff
+456 -310
View File
File diff suppressed because it is too large Load Diff
+6221
View File
File diff suppressed because it is too large Load Diff
+521 -375
View File
File diff suppressed because it is too large Load Diff
+6218
View File
File diff suppressed because it is too large Load Diff
+482 -336
View File
File diff suppressed because it is too large Load Diff
+486 -340
View File
File diff suppressed because it is too large Load Diff
+566 -420
View File
File diff suppressed because it is too large Load Diff
+557 -411
View File
File diff suppressed because it is too large Load Diff
+547 -400
View File
File diff suppressed because it is too large Load Diff
+690 -534
View File
File diff suppressed because it is too large Load Diff
+463 -317
View File
File diff suppressed because it is too large Load Diff
+530 -384
View File
File diff suppressed because it is too large Load Diff
+461 -315
View File
File diff suppressed because it is too large Load Diff
+556 -410
View File
File diff suppressed because it is too large Load Diff
+461 -315
View File
File diff suppressed because it is too large Load Diff
+559 -413
View File
File diff suppressed because it is too large Load Diff
+456 -310
View File
File diff suppressed because it is too large Load Diff
+463 -317
View File
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -747,12 +747,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AF2 peakC=AF2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AF1 hitMinR=mn4R*ARcpF1(AF1_(4.0)*mx4R);
AF1 hitMinG=mn4G*ARcpF1(AF1_(4.0)*mx4G);
AF1 hitMinB=mn4B*ARcpF1(AF1_(4.0)*mx4B);
AF1 hitMaxR=(peakC.x-mx4R)*ARcpF1(AF1_(4.0)*mn4R+peakC.y);
AF1 hitMaxG=(peakC.x-mx4G)*ARcpF1(AF1_(4.0)*mn4G+peakC.y);
AF1 hitMaxB=(peakC.x-mx4B)*ARcpF1(AF1_(4.0)*mn4B+peakC.y);
AF1 hitMinR=min(mn4R,eR)*ARcpF1(AF1_(4.0)*mx4R);
AF1 hitMinG=min(mn4G,eG)*ARcpF1(AF1_(4.0)*mx4G);
AF1 hitMinB=min(mn4B,eB)*ARcpF1(AF1_(4.0)*mx4B);
AF1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpF1(AF1_(4.0)*mn4R+peakC.y);
AF1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpF1(AF1_(4.0)*mn4G+peakC.y);
AF1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpF1(AF1_(4.0)*mn4B+peakC.y);
AF1 lobeR=max(-hitMinR,hitMaxR);
AF1 lobeG=max(-hitMinG,hitMaxG);
AF1 lobeB=max(-hitMinB,hitMaxB);
@@ -845,12 +845,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AH2 peakC=AH2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AH1 hitMinR=mn4R*ARcpH1(AH1_(4.0)*mx4R);
AH1 hitMinG=mn4G*ARcpH1(AH1_(4.0)*mx4G);
AH1 hitMinB=mn4B*ARcpH1(AH1_(4.0)*mx4B);
AH1 hitMaxR=(peakC.x-mx4R)*ARcpH1(AH1_(4.0)*mn4R+peakC.y);
AH1 hitMaxG=(peakC.x-mx4G)*ARcpH1(AH1_(4.0)*mn4G+peakC.y);
AH1 hitMaxB=(peakC.x-mx4B)*ARcpH1(AH1_(4.0)*mn4B+peakC.y);
AH1 hitMinR=min(mn4R,eR)*ARcpH1(AH1_(4.0)*mx4R);
AH1 hitMinG=min(mn4G,eG)*ARcpH1(AH1_(4.0)*mx4G);
AH1 hitMinB=min(mn4B,eB)*ARcpH1(AH1_(4.0)*mx4B);
AH1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH1(AH1_(4.0)*mn4R+peakC.y);
AH1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH1(AH1_(4.0)*mn4G+peakC.y);
AH1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH1(AH1_(4.0)*mn4B+peakC.y);
AH1 lobeR=max(-hitMinR,hitMaxR);
AH1 lobeG=max(-hitMinG,hitMaxG);
AH1 lobeB=max(-hitMinB,hitMaxB);
@@ -963,12 +963,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AH2 peakC=AH2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AH2 hitMinR=mn4R*ARcpH2(AH2_(4.0)*mx4R);
AH2 hitMinG=mn4G*ARcpH2(AH2_(4.0)*mx4G);
AH2 hitMinB=mn4B*ARcpH2(AH2_(4.0)*mx4B);
AH2 hitMaxR=(peakC.x-mx4R)*ARcpH2(AH2_(4.0)*mn4R+peakC.y);
AH2 hitMaxG=(peakC.x-mx4G)*ARcpH2(AH2_(4.0)*mn4G+peakC.y);
AH2 hitMaxB=(peakC.x-mx4B)*ARcpH2(AH2_(4.0)*mn4B+peakC.y);
AH2 hitMinR=min(mn4R,eR)*ARcpH2(AH2_(4.0)*mx4R);
AH2 hitMinG=min(mn4G,eG)*ARcpH2(AH2_(4.0)*mx4G);
AH2 hitMinB=min(mn4B,eB)*ARcpH2(AH2_(4.0)*mx4B);
AH2 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH2(AH2_(4.0)*mn4R+peakC.y);
AH2 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH2(AH2_(4.0)*mn4G+peakC.y);
AH2 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH2(AH2_(4.0)*mn4B+peakC.y);
AH2 lobeR=max(-hitMinR,hitMaxR);
AH2 lobeG=max(-hitMinG,hitMaxG);
AH2 lobeB=max(-hitMinB,hitMaxB);
+8 -3
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
+2 -2
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);
}
+6
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) {
+4 -1
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();
+2 -3
View File
@@ -188,9 +188,8 @@ public:
#ifdef _WIN32
template <typename Path>
[[nodiscard]] void Open(const Path& path, FileAccessMode mode,
FileType type = FileType::BinaryFile,
FileShareFlag flag = FileShareFlag::ShareReadOnly) {
void Open(const Path& path, FileAccessMode mode, FileType type = FileType::BinaryFile,
FileShareFlag flag = FileShareFlag::ShareReadOnly) {
using ValueType = typename Path::value_type;
if constexpr (IsChar<ValueType>) {
Open(ToU8String(path), mode, type, flag);
+7
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
+1
View File
@@ -554,6 +554,7 @@ struct Values {
Setting<bool> use_docked_mode{true, "use_docked_mode"};
BasicSetting<bool> enable_raw_input{false, "enable_raw_input"};
BasicSetting<bool> controller_navigation{true, "controller_navigation"};
Setting<bool> vibration_enabled{true, "vibration_enabled"};
Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
+3 -1
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 {
+8 -8
View File
@@ -37,12 +37,12 @@ constexpr Xbyak::Reg IndexToReg(size_t reg_index) {
}
}
inline std::bitset<32> BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
std::bitset<32> bits;
constexpr std::bitset<32> BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
size_t bits = 0;
for (const Xbyak::Reg& reg : regs) {
bits[RegToIndex(reg)] = true;
bits |= size_t{1} << RegToIndex(reg);
}
return bits;
return {bits};
}
constexpr inline std::bitset<32> ABI_ALL_GPRS(0x0000FFFF);
@@ -57,7 +57,7 @@ constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
constexpr inline std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
@@ -74,7 +74,7 @@ const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
Xbyak::util::xmm5,
});
const std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({
constexpr inline std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rsi,
@@ -108,7 +108,7 @@ constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
constexpr inline std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
@@ -137,7 +137,7 @@ const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
Xbyak::util::xmm15,
});
const std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({
constexpr inline std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rbp,
+3
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
+1 -1
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();
+2 -1
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>);
@@ -749,6 +749,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
raw_status.gyro.y.value,
raw_status.gyro.z.value,
});
emulated.SetGyroThreshold(raw_status.gyro.x.properties.threshold);
emulated.UpdateRotation(raw_status.delta_timestamp);
emulated.UpdateOrientation(raw_status.delta_timestamp);
force_update_motion = raw_status.force_update;
+1 -1
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;
+2 -2
View File
@@ -10,7 +10,7 @@ namespace Core::HID {
MotionInput::MotionInput() {
// Initialize PID constants with default values
SetPID(0.3f, 0.005f, 0.0f);
SetGyroThreshold(0.00005f);
SetGyroThreshold(0.007f);
}
void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) {
@@ -31,7 +31,7 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
}
if (gyro.Length2() < gyro_threshold) {
if (gyro.Length() < gyro_threshold) {
gyro = {};
} else {
only_accelerometer = false;
-5
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;
-2
View File
@@ -31,8 +31,6 @@ public:
}
constexpr void SetAffinity(s32 core, bool set) {
ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
if (set) {
this->mask |= GetCoreBit(core);
} else {
+100 -104
View File
@@ -276,22 +276,23 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_
ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryState state,
KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};
const u64 size{num_pages * PageSize};
if (!CanContain(addr, size, state)) {
return ResultInvalidCurrentMemory;
}
// Validate the mapping request.
R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
if (IsRegionMapped(addr, size)) {
return ResultInvalidCurrentMemory;
}
// Lock the table.
std::lock_guard lock{page_table_lock};
// Verify that the destination memory is unmapped.
R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, KMemoryState::Free,
KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::None, KMemoryAttribute::None));
KPageLinkedList page_linked_list;
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));
R_TRY(system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool,
allocation_option));
R_TRY(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup));
block_manager->Update(addr, num_pages, state, perm);
@@ -395,39 +396,12 @@ ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
return ResultSuccess;
}
void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) {
auto node{page_linked_list.Nodes().begin()};
PAddr map_addr{node->GetAddress()};
std::size_t src_num_pages{node->GetNumPages()};
block_manager->IterateForRange(start, end, [&](const KMemoryInfo& info) {
if (info.state != KMemoryState::Free) {
return;
}
std::size_t dst_num_pages{GetSizeInRange(info, start, end) / PageSize};
VAddr dst_addr{GetAddressInRange(info, start)};
while (dst_num_pages) {
if (!src_num_pages) {
node = std::next(node);
map_addr = node->GetAddress();
src_num_pages = node->GetNumPages();
}
const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)};
Operate(dst_addr, num_pages, KMemoryPermission::UserReadWrite, OperationType::Map,
map_addr);
dst_addr += num_pages * PageSize;
map_addr += num_pages * PageSize;
src_num_pages -= num_pages;
dst_num_pages -= num_pages;
}
});
}
ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
// Lock the physical memory lock.
std::lock_guard phys_lk(map_physical_memory_lock);
// Lock the table.
std::lock_guard lock{page_table_lock};
std::size_t mapped_size{};
@@ -463,7 +437,35 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
// We succeeded, so commit the memory reservation.
memory_reservation.Commit();
MapPhysicalMemory(page_linked_list, addr, end_addr);
// Map the memory.
auto node{page_linked_list.Nodes().begin()};
PAddr map_addr{node->GetAddress()};
std::size_t src_num_pages{node->GetNumPages()};
block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) {
if (info.state != KMemoryState::Free) {
return;
}
std::size_t dst_num_pages{GetSizeInRange(info, addr, end_addr) / PageSize};
VAddr dst_addr{GetAddressInRange(info, addr)};
while (dst_num_pages) {
if (!src_num_pages) {
node = std::next(node);
map_addr = node->GetAddress();
src_num_pages = node->GetNumPages();
}
const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)};
Operate(dst_addr, num_pages, KMemoryPermission::UserReadWrite, OperationType::Map,
map_addr);
dst_addr += num_pages * PageSize;
map_addr += num_pages * PageSize;
src_num_pages -= num_pages;
dst_num_pages -= num_pages;
}
});
mapped_physical_memory_size += remaining_size;
@@ -503,23 +505,8 @@ ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
return ResultSuccess;
}
CASCADE_CODE(UnmapMemory(addr, size));
auto process{system.Kernel().CurrentProcess()};
process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size);
mapped_physical_memory_size -= mapped_size;
return ResultSuccess;
}
ResultCode KPageTable::UnmapMemory(VAddr addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
const VAddr end_addr{addr + size};
ResultCode result{ResultSuccess};
KPageLinkedList page_linked_list;
// Unmap each region within the range
KPageLinkedList page_linked_list;
block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) {
if (info.state == KMemoryState::Normal) {
const std::size_t block_size{GetSizeInRange(info, addr, end_addr)};
@@ -535,7 +522,6 @@ ResultCode KPageTable::UnmapMemory(VAddr addr, std::size_t size) {
}
}
});
if (result.IsError()) {
return result;
}
@@ -546,10 +532,14 @@ ResultCode KPageTable::UnmapMemory(VAddr addr, std::size_t size) {
block_manager->Update(addr, num_pages, KMemoryState::Free);
auto process{system.Kernel().CurrentProcess()};
process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size);
mapped_physical_memory_size -= mapped_size;
return ResultSuccess;
}
ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
KMemoryState src_state{};
@@ -588,7 +578,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
return ResultSuccess;
}
ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
KMemoryState src_state{};
@@ -652,24 +642,26 @@ ResultCode KPageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_l
return ResultSuccess;
}
ResultCode KPageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};
ResultCode KPageTable::MapPages(VAddr address, KPageLinkedList& page_linked_list,
KMemoryState state, KMemoryPermission perm) {
// Check that the map is in range.
const std::size_t num_pages{page_linked_list.GetNumPages()};
const std::size_t size{num_pages * PageSize};
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
if (!CanContain(addr, size, state)) {
return ResultInvalidCurrentMemory;
}
// Lock the table.
std::lock_guard lock{page_table_lock};
if (IsRegionMapped(addr, num_pages * PageSize)) {
return ResultInvalidCurrentMemory;
}
// Check the memory state.
R_TRY(this->CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::None, KMemoryAttribute::None));
CASCADE_CODE(MapPages(addr, page_linked_list, perm));
// Map the pages.
R_TRY(MapPages(address, page_linked_list, perm));
block_manager->Update(addr, num_pages, state, perm);
// Update the blocks.
block_manager->Update(address, num_pages, state, perm);
return ResultSuccess;
}
@@ -693,21 +685,23 @@ ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked
ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
KMemoryState state) {
std::lock_guard lock{page_table_lock};
// Check that the unmap is in range.
const std::size_t num_pages{page_linked_list.GetNumPages()};
const std::size_t size{num_pages * PageSize};
R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
if (!CanContain(addr, size, state)) {
return ResultInvalidCurrentMemory;
}
// Lock the table.
std::lock_guard lock{page_table_lock};
if (IsRegionMapped(addr, num_pages * PageSize)) {
return ResultInvalidCurrentMemory;
}
// Check the memory state.
R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, state, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::All,
KMemoryAttribute::None));
CASCADE_CODE(UnmapPages(addr, page_linked_list));
// Perform the unmap.
R_TRY(UnmapPages(addr, page_linked_list));
// Update the blocks.
block_manager->Update(addr, num_pages, state, KMemoryPermission::None);
return ResultSuccess;
@@ -765,7 +759,6 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
// Ensure cache coherency, if we're setting pages as executable.
if (is_x) {
// Memory execution state is changing, invalidate CPU cache range
system.InvalidateCpuInstructionCacheRange(addr, size);
}
@@ -793,12 +786,12 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo
KMemoryState state{};
KMemoryAttribute attribute{};
CASCADE_CODE(CheckMemoryState(
&state, nullptr, &attribute, nullptr, addr, size,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All,
KMemoryPermission::UserReadWrite, KMemoryAttribute::Mask, KMemoryAttribute::None,
KMemoryAttribute::IpcAndDeviceMapped));
R_TRY(CheckMemoryState(&state, nullptr, &attribute, nullptr, addr, size,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryPermission::All, KMemoryPermission::UserReadWrite,
KMemoryAttribute::Mask, KMemoryAttribute::None,
KMemoryAttribute::IpcAndDeviceMapped));
block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked);
@@ -810,12 +803,11 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
KMemoryState state{};
CASCADE_CODE(
CheckMemoryState(&state, nullptr, nullptr, nullptr, addr, size,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask,
KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
R_TRY(CheckMemoryState(&state, nullptr, nullptr, nullptr, addr, size,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask,
KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
block_manager->Update(addr, size / PageSize, state, KMemoryPermission::UserReadWrite);
return ResultSuccess;
@@ -871,8 +863,9 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask
AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
// Determine the new attribute.
const auto new_attr = ((old_attr & static_cast<KMemoryAttribute>(~mask)) |
static_cast<KMemoryAttribute>(attr & mask));
const KMemoryAttribute new_attr =
static_cast<KMemoryAttribute>(((old_attr & static_cast<KMemoryAttribute>(~mask)) |
static_cast<KMemoryAttribute>(attr & mask)));
// Perform operation.
this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh);
@@ -896,6 +889,9 @@ ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
}
ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
// Lock the physical memory lock.
std::lock_guard phys_lk(map_physical_memory_lock);
// Try to perform a reduction in heap, instead of an extension.
VAddr cur_address{};
std::size_t allocation_size{};
@@ -1025,12 +1021,12 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
}
if (is_map_only) {
CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
R_TRY(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, allocation_option));
CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup));
R_TRY(system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool,
allocation_option));
R_TRY(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup));
}
block_manager->Update(addr, needed_num_pages, state, perm);
@@ -1186,7 +1182,7 @@ VAddr KPageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_page
ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group,
OperationType operation) {
std::lock_guard lock{page_table_lock};
ASSERT(this->IsLockedByCurrentThread());
ASSERT(Common::IsAligned(addr, PageSize));
ASSERT(num_pages > 0);
@@ -1211,7 +1207,7 @@ ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLin
ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
OperationType operation, PAddr map_addr) {
std::lock_guard lock{page_table_lock};
ASSERT(this->IsLockedByCurrentThread());
ASSERT(num_pages > 0);
ASSERT(Common::IsAligned(addr, PageSize));
+6 -5
View File
@@ -37,9 +37,8 @@ public:
VAddr src_addr);
ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size);
ResultCode UnmapMemory(VAddr addr, std::size_t size);
ResultCode Map(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
KMemoryPermission perm);
ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
@@ -88,7 +87,6 @@ private:
ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
KMemoryPermission perm);
ResultCode UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list);
void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end);
bool IsRegionMapped(VAddr address, u64 size);
bool IsRegionContiguous(VAddr addr, u64 size) const;
void AddRegionToPages(VAddr start, std::size_t num_pages, KPageLinkedList& page_linked_list);
@@ -148,6 +146,7 @@ private:
}
std::recursive_mutex page_table_lock;
std::mutex map_physical_memory_lock;
std::unique_ptr<KMemoryBlockManager> block_manager;
public:
@@ -249,7 +248,9 @@ public:
return !IsOutsideASLRRegion(address, size);
}
constexpr PAddr GetPhysicalAddr(VAddr addr) {
return page_table_impl.backing_addr[addr >> PageBits] + addr;
const auto backing_addr = page_table_impl.backing_addr[addr >> PageBits];
ASSERT(backing_addr);
return backing_addr + addr;
}
constexpr bool Contains(VAddr addr) const {
return address_space_start <= addr && addr <= address_space_end - 1;
+37 -1
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>
@@ -257,7 +258,7 @@ private:
private:
constexpr void ClearAffinityBit(u64& affinity, s32 core) {
affinity &= ~(u64(1) << core);
affinity &= ~(UINT64_C(1) << core);
}
constexpr s32 GetNextCore(u64& affinity) {
@@ -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();
+20 -12
View File
@@ -146,27 +146,35 @@ ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::st
// Open a reference to the resource limit.
process->resource_limit->Open();
// Clear remaining fields.
process->num_running_threads = 0;
process->is_signaled = false;
process->exception_thread = nullptr;
process->is_suspended = false;
process->schedule_count = 0;
return ResultSuccess;
}
void KProcess::DoWorkerTaskImpl() {
UNIMPLEMENTED();
}
KResourceLimit* KProcess::GetResourceLimit() const {
return resource_limit;
}
void KProcess::IncrementThreadCount() {
ASSERT(num_threads >= 0);
num_created_threads++;
if (const auto count = ++num_threads; count > peak_num_threads) {
peak_num_threads = count;
}
void KProcess::IncrementRunningThreadCount() {
ASSERT(num_running_threads.load() >= 0);
++num_running_threads;
}
void KProcess::DecrementThreadCount() {
ASSERT(num_threads > 0);
void KProcess::DecrementRunningThreadCount() {
ASSERT(num_running_threads.load() > 0);
if (const auto count = --num_threads; count == 0) {
LOG_WARNING(Kernel, "Process termination is not fully implemented.");
if (const auto prev = num_running_threads--; prev == 1) {
// TODO(bunnei): Process termination to be implemented when multiprocess is supported.
UNIMPLEMENTED_MSG("KProcess termination is not implemennted!");
}
}
@@ -477,7 +485,7 @@ void KProcess::Finalize() {
}
// Perform inherited finalization.
KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize();
}
/**
+7 -7
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:
@@ -235,8 +235,8 @@ public:
++schedule_count;
}
void IncrementThreadCount();
void DecrementThreadCount();
void IncrementRunningThreadCount();
void DecrementRunningThreadCount();
void SetRunningThread(s32 core, KThread* thread, u64 idle_count) {
running_threads[core] = thread;
@@ -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);
@@ -471,9 +473,7 @@ private:
bool is_suspended{};
bool is_initialized{};
std::atomic<s32> num_created_threads{};
std::atomic<u16> num_threads{};
u16 peak_num_threads{};
std::atomic<u16> num_running_threads{};
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{};
std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{};
+32 -24
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) {
@@ -709,23 +710,19 @@ void KScheduler::Unload(KThread* thread) {
}
void KScheduler::Reload(KThread* thread) {
LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread ? thread->GetName() : "nullptr");
LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread->GetName());
if (thread) {
ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable.");
Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
cpu_core.LoadContext(thread->GetContext32());
cpu_core.LoadContext(thread->GetContext64());
cpu_core.SetTlsAddress(thread->GetTLSAddress());
cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
cpu_core.ClearExclusiveState();
}
Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
cpu_core.LoadContext(thread->GetContext32());
cpu_core.LoadContext(thread->GetContext64());
cpu_core.SetTlsAddress(thread->GetTLSAddress());
cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
cpu_core.ClearExclusiveState();
}
void KScheduler::SwitchContextStep2() {
// Load context of new thread
Reload(current_thread.load());
Reload(GetCurrentThread());
RescheduleCurrentCore();
}
@@ -734,13 +731,23 @@ void KScheduler::ScheduleImpl() {
KThread* previous_thread = GetCurrentThread();
KThread* next_thread = state.highest_priority_thread;
state.needs_scheduling = false;
state.needs_scheduling.store(false);
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
if (next_thread == nullptr) {
next_thread = idle_thread;
}
if (next_thread->GetCurrentCore() != core_id) {
next_thread->SetCurrentCore(core_id);
}
// 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();
@@ -748,14 +755,8 @@ void KScheduler::ScheduleImpl() {
return;
}
if (next_thread->GetCurrentCore() != core_id) {
next_thread->SetCurrentCore(core_id);
}
current_thread.store(next_thread);
// Update the CPU time tracking variables.
KProcess* const previous_process = system.Kernel().CurrentProcess();
UpdateLastContextSwitchTime(previous_thread, previous_process);
// Save context for previous thread
@@ -763,6 +764,10 @@ void KScheduler::ScheduleImpl() {
std::shared_ptr<Common::Fiber>* old_context;
old_context = &previous_thread->GetHostContext();
// Set the new thread.
current_thread.store(next_thread);
guard.Unlock();
Common::Fiber::YieldTo(*old_context, *switch_fiber);
@@ -790,8 +795,8 @@ void KScheduler::SwitchToCurrent() {
do {
auto next_thread = current_thread.load();
if (next_thread != nullptr) {
next_thread->context_guard.Lock();
if (next_thread->GetRawState() != ThreadState::Runnable) {
const auto locked = next_thread->context_guard.TryLock();
if (state.needs_scheduling.load()) {
next_thread->context_guard.Unlock();
break;
}
@@ -799,6 +804,9 @@ void KScheduler::SwitchToCurrent() {
next_thread->context_guard.Unlock();
break;
}
if (!locked) {
continue;
}
}
auto thread = next_thread ? next_thread : idle_thread;
Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext());
+2 -18
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;
}
+94 -42
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;
@@ -214,7 +215,6 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
parent = owner;
parent->Open();
parent->IncrementThreadCount();
}
// Initialize thread context.
@@ -261,7 +261,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) {
@@ -326,13 +326,8 @@ void KThread::Finalize() {
}
}
// Decrement the parent process's thread count.
if (parent != nullptr) {
parent->DecrementThreadCount();
}
// Perform inherited finalization.
KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize();
KSynchronizationObject::Finalize();
}
bool KThread::IsSignaled() const {
@@ -376,11 +371,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 +429,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 +470,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 +689,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 +716,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 +996,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->IncrementRunningThreadCount();
}
// Set our state and finish.
@@ -1019,21 +1020,29 @@ ResultCode KThread::Run() {
void KThread::Exit() {
ASSERT(this == GetCurrentThreadPointer(kernel));
// Release the thread resource hint from parent.
// Release the thread resource hint, running thread count from parent.
if (parent != nullptr) {
parent->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 0, 1);
resource_limit_release_hint = true;
parent->DecrementRunningThreadCount();
}
// Perform termination.
{
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 +1070,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 +1128,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();
}
}
+25 -6
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;
+18
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
@@ -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
@@ -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
+25 -21
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"
@@ -51,7 +52,8 @@ namespace Kernel {
struct KernelCore::Impl {
explicit Impl(Core::System& system_, KernelCore& kernel_)
: time_manager{system_}, object_list_container{kernel_}, system{system_} {}
: time_manager{system_}, object_list_container{kernel_},
service_threads_manager{1, "yuzu:ServiceThreadsManager"}, system{system_} {}
void SetMulticore(bool is_multi) {
is_multicore = is_multi;
@@ -299,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();
@@ -707,32 +707,28 @@ struct KernelCore::Impl {
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel,
const std::string& name) {
auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, 1, name);
{
std::lock_guard lk(service_threads_lock);
service_threads.emplace(service_thread);
}
service_threads_manager.QueueWork(
[this, service_thread]() { service_threads.emplace(service_thread); });
return service_thread;
}
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
auto strong_ptr = service_thread.lock();
{
std::lock_guard lk(service_threads_lock);
service_threads.erase(strong_ptr);
if (auto strong_ptr = service_thread.lock()) {
service_threads_manager.QueueWork(
[this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); });
}
}
void ClearServiceThreads() {
std::lock_guard lk(service_threads_lock);
service_threads.clear();
service_threads_manager.QueueWork([this]() { service_threads.clear(); });
}
std::mutex server_ports_lock;
std::mutex server_sessions_lock;
std::mutex registered_objects_lock;
std::mutex registered_in_use_objects_lock;
std::mutex dummy_thread_lock;
std::mutex service_threads_lock;
std::atomic<u32> next_object_id{0};
std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin};
@@ -783,14 +779,12 @@ struct KernelCore::Impl {
// Threads used for services
std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
Common::ThreadWorker service_threads_manager;
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
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{};
@@ -798,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;
};
@@ -1138,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();
}
+7
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;
+5
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;
+3 -3
View File
@@ -230,7 +230,7 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr
return result;
}
return page_table.Map(dst_addr, src_addr, size);
return page_table.MapMemory(dst_addr, src_addr, size);
}
static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
@@ -249,7 +249,7 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad
return result;
}
return page_table.Unmap(dst_addr, src_addr, size);
return page_table.UnmapMemory(dst_addr, src_addr, size);
}
static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
@@ -2613,7 +2613,7 @@ static const FunctionDef SVC_Table_32[] = {
{0x33, SvcWrap32<GetThreadContext32>, "GetThreadContext32"},
{0x34, SvcWrap32<WaitForAddress32>, "WaitForAddress32"},
{0x35, SvcWrap32<SignalToAddress32>, "SignalToAddress32"},
{0x36, nullptr, "Unknown"},
{0x36, SvcWrap32<SynchronizePreemptionState>, "SynchronizePreemptionState32"},
{0x37, nullptr, "Unknown"},
{0x38, nullptr, "Unknown"},
{0x39, nullptr, "Unknown"},
+2 -2
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"},
+2 -2
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"},
+1
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
+13 -1
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;
};
+8 -8
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
+30
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
@@ -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"},
+6 -6
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
+2 -1
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,
+6
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
+6
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"},
+2
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
+15 -27
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
+1 -1
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
+33 -2
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;
}
+2
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;
+11 -4
View File
@@ -109,8 +109,9 @@ public:
bool HasHDRumble() const {
if (sdl_controller) {
return (SDL_GameControllerGetType(sdl_controller.get()) ==
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO);
const auto type = SDL_GameControllerGetType(sdl_controller.get());
return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ||
(type == SDL_CONTROLLER_TYPE_PS5);
}
return false;
}
@@ -198,9 +199,15 @@ 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:
return "DualShock 4 Controller";
case SDL_CONTROLLER_TYPE_PS5:
return "DualSense Controller";
default:
break;
}
+25 -4
View File
@@ -192,6 +192,25 @@ std::size_t UDPClient::GetClientNumber(std::string_view host, u16 port) const {
return MAX_UDP_CLIENTS;
}
BatteryLevel UDPClient::GetBatteryLevel(Response::Battery battery) const {
switch (battery) {
case Response::Battery::Dying:
return BatteryLevel::Empty;
case Response::Battery::Low:
return BatteryLevel::Critical;
case Response::Battery::Medium:
return BatteryLevel::Low;
case Response::Battery::High:
return BatteryLevel::Medium;
case Response::Battery::Full:
case Response::Battery::Charged:
return BatteryLevel::Full;
case Response::Battery::Charging:
default:
return BatteryLevel::Charging;
}
}
void UDPClient::OnVersion([[maybe_unused]] Response::Version data) {
LOG_TRACE(Input, "Version packet received: {}", data.version);
}
@@ -299,6 +318,8 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
const int button = static_cast<int>(buttons[i]);
SetButton(identifier, button, button_status);
}
SetBattery(identifier, GetBatteryLevel(data.info.battery));
}
void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) {
@@ -318,7 +339,7 @@ void UDPClient::StartCommunication(std::size_t client, const std::string& host,
}
}
const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const {
PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const {
const std::size_t client = pad_index / PADS_PER_CLIENT;
return {
.guid = clients[client].uuid,
@@ -327,9 +348,9 @@ const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const {
};
}
const Common::UUID UDPClient::GetHostUUID(const std::string host) const {
const auto ip = boost::asio::ip::address_v4::from_string(host);
const auto hex_host = fmt::format("{:06x}", ip.to_ulong());
Common::UUID UDPClient::GetHostUUID(const std::string& host) const {
const auto ip = boost::asio::ip::make_address_v4(host);
const auto hex_host = fmt::format("{:06x}", ip.to_uint());
return Common::UUID{hex_host};
}
+6 -2
View File
@@ -15,6 +15,7 @@ namespace InputCommon::CemuhookUDP {
class Socket;
namespace Response {
enum class Battery : u8;
struct PadData;
struct PortInfo;
struct TouchPad;
@@ -137,12 +138,15 @@ private:
// Translates configuration to client number
std::size_t GetClientNumber(std::string_view host, u16 port) const;
// Translates UDP battery level to input engine battery level
BatteryLevel GetBatteryLevel(Response::Battery battery) const;
void OnVersion(Response::Version);
void OnPortInfo(Response::PortInfo);
void OnPadData(Response::PadData, std::size_t client);
void StartCommunication(std::size_t client, const std::string& host, u16 port);
const PadIdentifier GetPadIdentifier(std::size_t pad_index) const;
const Common::UUID GetHostUUID(const std::string host) const;
PadIdentifier GetPadIdentifier(std::size_t pad_index) const;
Common::UUID GetHostUUID(const std::string& host) const;
Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
+1 -1
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);
}
}
}
+2 -2
View File
@@ -16,7 +16,7 @@
// Pad Identifier of data source
struct PadIdentifier {
Common::UUID guid{};
Common::UUID guid{Common::INVALID_UUID};
std::size_t port{};
std::size_t pad{};
@@ -89,7 +89,7 @@ struct UpdateCallback {
// Triggered if data changed on the controller and the engine is on configuring mode
struct MappingCallback {
std::function<void(MappingData)> on_data;
std::function<void(const MappingData&)> on_data;
};
// Input Identifier of data source
+18 -6
View File
@@ -2,14 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#include "common/common_types.h"
#include "common/settings.h"
#include "input_common/input_engine.h"
#include "input_common/input_mapping.h"
namespace InputCommon {
MappingFactory::MappingFactory() {}
MappingFactory::MappingFactory() = default;
void MappingFactory::BeginMapping(Polling::InputType type) {
is_enabled = true;
@@ -19,7 +18,7 @@ void MappingFactory::BeginMapping(Polling::InputType type) {
second_axis = -1;
}
[[nodiscard]] const Common::ParamPackage MappingFactory::GetNextInput() {
Common::ParamPackage MappingFactory::GetNextInput() {
Common::ParamPackage input;
input_queue.Pop(input);
return input;
@@ -57,7 +56,7 @@ void MappingFactory::StopMapping() {
void MappingFactory::RegisterButton(const MappingData& data) {
Common::ParamPackage new_input;
new_input.Set("engine", data.engine);
if (data.pad.guid != Common::UUID{}) {
if (data.pad.guid.IsValid()) {
new_input.Set("guid", data.pad.guid.Format());
}
new_input.Set("port", static_cast<int>(data.pad.port));
@@ -93,7 +92,7 @@ void MappingFactory::RegisterButton(const MappingData& data) {
void MappingFactory::RegisterStick(const MappingData& data) {
Common::ParamPackage new_input;
new_input.Set("engine", data.engine);
if (data.pad.guid != Common::UUID{}) {
if (data.pad.guid.IsValid()) {
new_input.Set("guid", data.pad.guid.Format());
}
new_input.Set("port", static_cast<int>(data.pad.port));
@@ -138,11 +137,24 @@ void MappingFactory::RegisterStick(const MappingData& data) {
void MappingFactory::RegisterMotion(const MappingData& data) {
Common::ParamPackage new_input;
new_input.Set("engine", data.engine);
if (data.pad.guid != Common::UUID{}) {
if (data.pad.guid.IsValid()) {
new_input.Set("guid", data.pad.guid.Format());
}
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:
+7 -1
View File
@@ -3,8 +3,14 @@
// Refer to the license.txt file included
#pragma once
#include "common/param_package.h"
#include "common/threadsafe_queue.h"
namespace InputCommon::Polling {
enum class InputType;
}
namespace InputCommon {
class InputEngine;
struct MappingData;
@@ -20,7 +26,7 @@ public:
void BeginMapping(Polling::InputType type);
/// Returns an input event with mapping information from the input_queue
[[nodiscard]] const Common::ParamPackage GetNextInput();
[[nodiscard]] Common::ParamPackage GetNextInput();
/**
* Registers mapping input data from the driver
+9 -4
View File
@@ -504,9 +504,10 @@ private:
class InputFromMotion final : public Common::Input::InputDevice {
public:
explicit InputFromMotion(PadIdentifier identifier_, int motion_sensor_,
explicit InputFromMotion(PadIdentifier identifier_, int motion_sensor_, float gyro_threshold_,
InputEngine* input_engine_)
: identifier(identifier_), motion_sensor(motion_sensor_), input_engine(input_engine_) {
: identifier(identifier_), motion_sensor(motion_sensor_), gyro_threshold(gyro_threshold_),
input_engine(input_engine_) {
UpdateCallback engine_callback{[this]() { OnChange(); }};
const InputIdentifier input_identifier{
.identifier = identifier,
@@ -525,8 +526,9 @@ public:
const auto basic_motion = input_engine->GetMotion(identifier, motion_sensor);
Common::Input::MotionStatus status{};
const Common::Input::AnalogProperties properties = {
.deadzone = 0.001f,
.deadzone = 0.0f,
.range = 1.0f,
.threshold = gyro_threshold,
.offset = 0.0f,
};
status.accel.x = {.raw_value = basic_motion.accel_x, .properties = properties};
@@ -551,6 +553,7 @@ public:
private:
const PadIdentifier identifier;
const int motion_sensor;
const float gyro_threshold;
int callback_key;
InputEngine* input_engine;
};
@@ -873,9 +876,11 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateMotionDevice(
if (params.Has("motion")) {
const auto motion_sensor = params.Get("motion", 0);
const auto gyro_threshold = params.Get("threshold", 0.007f);
input_engine->PreSetController(identifier);
input_engine->PreSetMotion(identifier, motion_sensor);
return std::make_unique<InputFromMotion>(identifier, motion_sensor, input_engine.get());
return std::make_unique<InputFromMotion>(identifier, motion_sensor, gyro_threshold,
input_engine.get());
}
const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f);
+3 -3
View File
@@ -27,7 +27,7 @@ namespace InputCommon {
struct InputSubsystem::Impl {
void Initialize() {
mapping_factory = std::make_shared<MappingFactory>();
MappingCallback mapping_callback{[this](MappingData data) { RegisterInput(data); }};
MappingCallback mapping_callback{[this](const MappingData& data) { RegisterInput(data); }};
keyboard = std::make_shared<Keyboard>("keyboard");
keyboard->SetMappingCallback(mapping_callback);
@@ -284,7 +284,7 @@ struct InputSubsystem::Impl {
#endif
}
void RegisterInput(MappingData data) {
void RegisterInput(const MappingData& data) {
mapping_factory->RegisterInput(data);
}
@@ -394,7 +394,7 @@ void InputSubsystem::BeginMapping(Polling::InputType type) {
impl->mapping_factory->BeginMapping(type);
}
const Common::ParamPackage InputSubsystem::GetNextInput() const {
Common::ParamPackage InputSubsystem::GetNextInput() const {
return impl->mapping_factory->GetNextInput();
}
+1 -1
View File
@@ -126,7 +126,7 @@ public:
void BeginMapping(Polling::InputType type);
/// Returns an input event with mapping information.
[[nodiscard]] const Common::ParamPackage GetNextInput() const;
[[nodiscard]] Common::ParamPackage GetNextInput() const;
/// Stop polling from all backends.
void StopMapping() const;
@@ -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) {
@@ -387,6 +387,14 @@ void SetupSignedNanCapabilities(const Profile& profile, const IR::Program& progr
}
}
void SetupTransformFeedbackCapabilities(EmitContext& ctx, Id main_func) {
if (ctx.runtime_info.xfb_varyings.empty()) {
return;
}
ctx.AddCapability(spv::Capability::TransformFeedback);
ctx.AddExecutionMode(main_func, spv::ExecutionMode::Xfb);
}
void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ctx) {
if (info.uses_sampled_1d) {
ctx.AddCapability(spv::Capability::Sampled1D);
@@ -442,9 +450,6 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
if (info.uses_sample_id) {
ctx.AddCapability(spv::Capability::SampleRateShading);
}
if (!ctx.runtime_info.xfb_varyings.empty()) {
ctx.AddCapability(spv::Capability::TransformFeedback);
}
if (info.uses_derivatives) {
ctx.AddCapability(spv::Capability::DerivativeControl);
}
@@ -484,6 +489,7 @@ std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in
SetupSignedNanCapabilities(profile, program, ctx, main);
}
SetupCapabilities(profile, program.info, ctx);
SetupTransformFeedbackCapabilities(ctx, main);
PatchPhiNodes(program, ctx);
return ctx.Assemble();
}
@@ -74,7 +74,7 @@ Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value&
const auto [scope, semantics]{AtomicArgs(ctx)};
return (ctx.*atomic_func)(ctx.U64, pointer, scope, semantics, value);
}
LOG_ERROR(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2,
binding, offset, sizeof(u32[2]))};
const Id original_value{ctx.OpBitcast(ctx.U64, ctx.OpLoad(ctx.U32[2], pointer))};
@@ -267,7 +267,7 @@ Id EmitStorageAtomicExchange64(EmitContext& ctx, const IR::Value& binding, const
const auto [scope, semantics]{AtomicArgs(ctx)};
return ctx.OpAtomicExchange(ctx.U64, pointer, scope, semantics, value);
}
LOG_ERROR(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2,
binding, offset, sizeof(u32[2]))};
const Id original{ctx.OpBitcast(ctx.U64, ctx.OpLoad(ctx.U32[2], pointer))};
@@ -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};
@@ -57,16 +57,6 @@ void TranslatorVisitor::VMNMX(u64 insn) {
if (vmnmx.sat != 0) {
throw NotImplementedException("VMNMX SAT");
}
// Selectors were shown to default to 2 in unit tests
if (vmnmx.src_a_selector != 2) {
throw NotImplementedException("VMNMX Selector {}", vmnmx.src_a_selector.Value());
}
if (vmnmx.src_b_selector != 2) {
throw NotImplementedException("VMNMX Selector {}", vmnmx.src_b_selector.Value());
}
if (vmnmx.src_a_width != VideoWidth::Word) {
throw NotImplementedException("VMNMX Source Width {}", vmnmx.src_a_width.Value());
}
const bool is_b_imm{vmnmx.is_src_b_reg == 0};
const IR::U32 src_a{GetReg8(insn)};
@@ -76,10 +66,14 @@ void TranslatorVisitor::VMNMX(u64 insn) {
const VideoWidth a_width{vmnmx.src_a_width};
const VideoWidth b_width{GetVideoSourceWidth(vmnmx.src_b_width, is_b_imm)};
const u32 a_selector{static_cast<u32>(vmnmx.src_a_selector)};
// Immediate values can't have a selector
const u32 b_selector{is_b_imm ? 0U : static_cast<u32>(vmnmx.src_b_selector)};
const bool src_a_signed{vmnmx.src_a_sign != 0};
const bool src_b_signed{vmnmx.src_b_sign != 0};
const IR::U32 op_a{ExtractVideoOperandValue(ir, src_a, a_width, 0, src_a_signed)};
const IR::U32 op_b{ExtractVideoOperandValue(ir, src_b, b_width, 0, src_b_signed)};
const IR::U32 op_a{ExtractVideoOperandValue(ir, src_a, a_width, a_selector, src_a_signed)};
const IR::U32 op_b{ExtractVideoOperandValue(ir, src_b, b_width, b_selector, src_b_signed)};
// First operation's sign is only dependent on operand b's sign
const bool op_1_signed{src_b_signed};
@@ -21,7 +21,6 @@ namespace Shader::Maxwell {
[[nodiscard]] IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b,
Environment& env_vertex_b);
[[nodiscard]] void ConvertLegacyToGeneric(IR::Program& program,
const Shader::RuntimeInfo& runtime_info);
void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info);
} // namespace Shader::Maxwell
@@ -688,7 +688,7 @@ void VisitUsages(Info& info, IR::Inst& inst) {
case IR::Opcode::StorageAtomicAnd64:
case IR::Opcode::StorageAtomicOr64:
case IR::Opcode::StorageAtomicXor64:
info.used_storage_buffer_types |= IR::Type::U64;
info.used_storage_buffer_types |= IR::Type::U64 | IR::Type::U32x2;
info.uses_int64_bit_atomics = true;
break;
case IR::Opcode::BindlessImageAtomicIAdd32:
+46 -3
View File
@@ -131,6 +131,8 @@ public:
void DownloadMemory(VAddr cpu_addr, u64 size);
bool InlineMemory(VAddr dest_address, size_t copy_size, std::span<u8> inlined_buffer);
void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size);
void DisableGraphicsUniformBuffer(size_t stage, u32 index);
@@ -808,6 +810,8 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
return;
}
MICROPROFILE_SCOPE(GPU_DownloadMemory);
const bool is_accuracy_normal =
Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::Normal;
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads;
u64 total_size_bytes = 0;
@@ -819,6 +823,9 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
buffer.ForEachDownloadRangeAndClear(
cpu_addr, size, [&](u64 range_offset, u64 range_size) {
if (is_accuracy_normal) {
return;
}
const VAddr buffer_addr = buffer.CpuAddr();
const auto add_download = [&](VAddr start, VAddr end) {
const u64 new_offset = start - buffer_addr;
@@ -1417,10 +1424,8 @@ void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 s
const IntervalType base_interval{cpu_addr, cpu_addr + size};
common_ranges.add(base_interval);
const bool is_accuracy_high =
Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High;
const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue();
if (!is_async && !is_accuracy_high) {
if (!is_async) {
return;
}
uncommitted_ranges.add(base_interval);
@@ -1474,6 +1479,8 @@ typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu
// When this memory region has been joined a bunch of times, we assume it's being used
// as a stream buffer. Increase the size to skip constantly recreating buffers.
has_stream_leap = true;
begin -= PAGE_SIZE * 256;
cpu_addr = begin;
end += PAGE_SIZE * 256;
}
}
@@ -1641,6 +1648,42 @@ void BufferCache<P>::MappedUploadMemory(Buffer& buffer, u64 total_size_bytes,
runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
}
template <class P>
bool BufferCache<P>::InlineMemory(VAddr dest_address, size_t copy_size,
std::span<u8> inlined_buffer) {
const bool is_dirty = IsRegionRegistered(dest_address, copy_size);
if (!is_dirty) {
return false;
}
if (!IsRegionGpuModified(dest_address, copy_size)) {
return false;
}
const IntervalType subtract_interval{dest_address, dest_address + copy_size};
ClearDownload(subtract_interval);
common_ranges.subtract(subtract_interval);
BufferId buffer_id = FindBuffer(dest_address, static_cast<u32>(copy_size));
auto& buffer = slot_buffers[buffer_id];
SynchronizeBuffer(buffer, dest_address, static_cast<u32>(copy_size));
if constexpr (USE_MEMORY_MAPS) {
std::array copies{BufferCopy{
.src_offset = 0,
.dst_offset = buffer.Offset(dest_address),
.size = copy_size,
}};
auto upload_staging = runtime.UploadStagingBuffer(copy_size);
u8* const src_pointer = upload_staging.mapped_span.data();
std::memcpy(src_pointer, inlined_buffer.data(), copy_size);
runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
} else {
buffer.ImmediateUpload(buffer.Offset(dest_address), inlined_buffer.first(copy_size));
}
return true;
}
template <class P>
void BufferCache<P>::DownloadBufferMemory(Buffer& buffer) {
DownloadBufferMemory(buffer, buffer.CpuAddr(), buffer.SizeBytes());
@@ -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};
+6 -1
View File
@@ -7,6 +7,7 @@
#include "common/assert.h"
#include "video_core/engines/engine_upload.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/textures/decoders.h"
namespace Tegra::Engines::Upload {
@@ -16,6 +17,10 @@ State::State(MemoryManager& memory_manager_, Registers& regs_)
State::~State() = default;
void State::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_;
}
void State::ProcessExec(const bool is_linear_) {
write_offset = 0;
copy_size = regs.line_length_in * regs.line_count;
@@ -32,7 +37,7 @@ void State::ProcessData(const u32 data, const bool is_last_call) {
}
const GPUVAddr address{regs.dest.Address()};
if (is_linear) {
memory_manager.WriteBlock(address, inner_buffer.data(), copy_size);
rasterizer->AccelerateInlineToMemory(address, copy_size, inner_buffer);
} else {
UNIMPLEMENTED_IF(regs.dest.z != 0);
UNIMPLEMENTED_IF(regs.dest.depth != 1);
+8
View File
@@ -12,6 +12,10 @@ namespace Tegra {
class MemoryManager;
}
namespace VideoCore {
class RasterizerInterface;
}
namespace Tegra::Engines::Upload {
struct Registers {
@@ -60,6 +64,9 @@ public:
void ProcessExec(bool is_linear_);
void ProcessData(u32 data, bool is_last_call);
/// Binds a rasterizer to this engine.
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
private:
u32 write_offset = 0;
u32 copy_size = 0;
@@ -68,6 +75,7 @@ private:
bool is_linear = false;
Registers& regs;
MemoryManager& memory_manager;
VideoCore::RasterizerInterface* rasterizer = nullptr;
};
} // namespace Tegra::Engines::Upload
@@ -22,6 +22,7 @@ KeplerCompute::~KeplerCompute() = default;
void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_;
upload_state.BindRasterizer(rasterizer);
}
void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
+4
View File
@@ -19,6 +19,10 @@ KeplerMemory::KeplerMemory(Core::System& system_, MemoryManager& memory_manager)
KeplerMemory::~KeplerMemory() = default;
void KeplerMemory::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
upload_state.BindRasterizer(rasterizer_);
}
void KeplerMemory::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
ASSERT_MSG(method < Regs::NUM_REGS,
"Invalid KeplerMemory register, increase the size of the Regs structure");
+7
View File
@@ -22,6 +22,10 @@ namespace Tegra {
class MemoryManager;
}
namespace VideoCore {
class RasterizerInterface;
}
namespace Tegra::Engines {
/**
@@ -38,6 +42,9 @@ public:
explicit KeplerMemory(Core::System& system_, MemoryManager& memory_manager);
~KeplerMemory() override;
/// Binds a rasterizer to this engine.
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
/// Write the value to the register identified by method.
void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
+2 -1
View File
@@ -31,6 +31,7 @@ Maxwell3D::~Maxwell3D() = default;
void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_;
upload_state.BindRasterizer(rasterizer_);
}
void Maxwell3D::InitializeRegisterDefaults() {
@@ -240,7 +241,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
((method - MacroRegistersStart) >> 1) % static_cast<u32>(macro_positions.size());
// Execute the current macro.
macro_engine->Execute(*this, macro_positions[entry], parameters);
macro_engine->Execute(macro_positions[entry], parameters);
if (mme_draw.current_mode != MMEDrawMode::Undefined) {
FlushMMEInlineDraw();
}
+2 -1
View File
@@ -1557,7 +1557,8 @@ private:
static constexpr u32 null_cb_data = 0xFFFFFFFF;
struct CBDataState {
std::array<std::array<u32, 0x4000>, 16> buffer;
static constexpr size_t inline_size = 0x4000;
std::array<std::array<u32, inline_size>, 16> buffer;
u32 current{null_cb_data};
u32 id{null_cb_data};
u32 start_pos{};
+7 -1
View File
@@ -59,6 +59,7 @@ struct GPU::Impl {
maxwell_3d->BindRasterizer(rasterizer);
fermi_2d->BindRasterizer(rasterizer);
kepler_compute->BindRasterizer(rasterizer);
kepler_memory->BindRasterizer(rasterizer);
maxwell_dma->BindRasterizer(rasterizer);
}
@@ -502,8 +503,13 @@ struct GPU::Impl {
case BufferMethods::SemaphoreAddressHigh:
case BufferMethods::SemaphoreAddressLow:
case BufferMethods::SemaphoreSequence:
break;
case BufferMethods::UnkCacheFlush:
rasterizer->SyncGuestHost();
break;
case BufferMethods::WrcacheFlush:
rasterizer->SignalReference();
break;
case BufferMethods::FenceValue:
break;
case BufferMethods::RefCnt:
@@ -513,7 +519,7 @@ struct GPU::Impl {
ProcessFenceActionMethod();
break;
case BufferMethods::WaitForInterrupt:
ProcessWaitForInterruptMethod();
rasterizer->WaitForIdle();
break;
case BufferMethods::SemaphoreTrigger: {
ProcessSemaphoreTriggerMethod();
-16
View File
@@ -12,9 +12,6 @@
#include "video_core/framebuffer_config.h"
namespace Core {
namespace Frontend {
class EmuWindow;
}
class System;
} // namespace Core
@@ -25,7 +22,6 @@ class ShaderNotify;
namespace Tegra {
class DmaPusher;
class CDmaPusher;
struct CommandList;
enum class RenderTargetFormat : u32 {
@@ -88,15 +84,9 @@ enum class DepthFormat : u32 {
D32_FLOAT_S8X24_UINT = 0x19,
};
struct CommandListHeader;
class DebugContext;
namespace Engines {
class Fermi2D;
class Maxwell3D;
class MaxwellDMA;
class KeplerCompute;
class KeplerMemory;
} // namespace Engines
enum class EngineID {
@@ -190,12 +180,6 @@ public:
/// Returns a const reference to the GPU DMA pusher.
[[nodiscard]] const Tegra::DmaPusher& DmaPusher() const;
/// Returns a reference to the GPU CDMA pusher.
[[nodiscard]] Tegra::CDmaPusher& CDmaPusher();
/// Returns a const reference to the GPU CDMA pusher.
[[nodiscard]] const Tegra::CDmaPusher& CDmaPusher() const;
/// Returns a reference to the underlying renderer.
[[nodiscard]] VideoCore::RendererBase& Renderer();
+46 -34
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) {

Some files were not shown because too many files have changed in this diff Show More