Compare commits

...

242 Commits

Author SHA1 Message Date
Fernando Sahmkow 1c13c74295 Memory manager: Fix possible softlock 2023-05-04 00:15:21 +02:00
bunnei a661c547d8 Merge pull request #10088 from FernandoS27/100-gelato-flavor-test-builds-later
Y.F.C Implement Asynchronous Fence manager and Rework Query async downloads
2023-05-03 15:10:22 -07:00
bunnei 737e1ca101 Merge pull request #10117 from liamwhite/sync-register
kernel: match calls to Register and Unregister
2023-05-03 09:07:19 -07:00
liamwhite ffeb5cdd8d Merge pull request #10151 from GPUCode/no-softlocks-please
Fix softlocks when disabling async present
2023-05-03 10:54:24 -04:00
Morph 3ba95402fd Merge pull request #10146 from liamwhite/catch3
catch2: update to 3.3.1
2023-05-03 10:53:12 -04:00
Morph 8dd3baa562 Merge pull request #10144 from liamwhite/dont-turbo
vulkan: disable turbo when debugging tool is attached
2023-05-03 10:53:03 -04:00
Morph daf7936095 Merge pull request #10143 from liamwhite/fruit-company-moment
video_core: fix build on Apple Clang
2023-05-03 10:52:56 -04:00
Morph 627022bef9 Merge pull request #10124 from liamwhite/pebkac
settings: rename extended memory layout to unsafe, move from general to system
2023-05-03 10:52:45 -04:00
GPUCode f3fcc15ad5 vk_present_manager: Fix softlocks when disabling async present 2023-05-03 07:50:10 +03:00
Liam d1dd54cbfa catch2: update to 3.3.1 2023-05-02 21:27:17 -04:00
bunnei 8f43b05d6b Merge pull request #9973 from GPUCode/async-present
Implement asynchronous presentation
2023-05-02 17:54:57 -07:00
liamwhite 451b1bba26 Merge pull request #10133 from lat9nq/clang-shadow-and-fallthrough
CMakeLists: Enable more checks on Clang
2023-05-02 18:18:46 -04:00
liamwhite 494cc992eb Merge pull request #10130 from liamwhite/keys
qt: warn on inoperable keys
2023-05-02 18:17:24 -04:00
liamwhite f603dc9763 Merge pull request #10123 from Kelebek1/sample_mask
Define SampleMask as an array
2023-05-02 18:17:15 -04:00
Liam 4df49631de vulkan: disable turbo when debugging tool is attached 2023-05-02 18:14:57 -04:00
Liam e1c74cea10 video_core: fix build on Apple Clang 2023-05-02 18:05:30 -04:00
lat9nq f7292c776b CMake: Enable type limits on Clang 2023-05-02 02:07:36 -04:00
lat9nq 2007d0e4a0 CMakeLists: Enable checks on Clang
Enables shadow-uncaptured-locals and implicit-fallthrough for Clang.
implicit-fallthrough is not enabled by default in -Wall or -Wextra, and
shadow-uncaptured-local doesn't seem to be enabled by default by
-Wshadow, even though GCC has both of these by their respective cases.
2023-05-02 01:57:22 -04:00
GPUCode f403d27941 vk_present_manager: Add toggle for async presentation 2023-05-01 23:13:24 +03:00
GPUCode 1d7abac84b vk_blit_screen: Recreate FSR when frame is recreated
* Depends on the layout dimentions and thus should be recreated as well
2023-05-01 23:13:24 +03:00
GPUCode 50791cb974 renderer_vulkan: Fix crashing when updating descriptors
* During pipeline configure the function would acquire some payload space from the descriptor update queue,
  write the descriptor data on the GPU thread and give the scheduler a pointer to the beginning of said space to update it later.
  TickFrame resets the payload cursor, used to track acquires, back to the beginning of the buffer.
  This wasn't a problem before since WaitWorker was called at the end of the frame but now it is.
  If a frame writes to a cursor before the scheduler catches up, it will crash

* To fix this the payload buffer has been increased to account for the in flight frames that are allowed to exist now.
  TickFrame will switch between the payload spaces instead of resetting
2023-05-01 23:13:24 +03:00
GPUCode 2ad9acf795 renderer_vulkan: Async presentation 2023-05-01 23:13:24 +03:00
Morph 47938541c2 Merge pull request #10084 from FernandoS27/yuzu-goes-broom-broom
Y.F.C Buffer Cache Revamp
2023-05-01 11:08:02 -04:00
zhaobot 1f079d9566 Update translations (2023-05-01) (#10129)
Co-authored-by: The yuzu Community <noreply-fake@community.yuzu-emu.org>
2023-05-01 16:17:51 +02:00
liamwhite 3f4315e4c6 Merge pull request #10116 from liamwhite/deboost
kernel: remove boost intrusive lists
2023-05-01 09:27:23 -04:00
Fernando Sahmkow d6f565e5da BufferCache: Fixes and address feedback 2023-05-01 11:43:26 +02:00
Liam 7ec66db22c qt: warn on inoperable keys 2023-04-30 23:47:42 -04:00
Liam 2cd9e1ecb6 settings: rename extended memory layout to unsafe, move from general to system 2023-04-30 14:24:22 -04:00
Kelebek1 b566c98258 Define SampleMask as an array 2023-04-30 18:37:37 +01:00
bunnei 689f9a75a7 Merge pull request #10110 from Morph1984/intel-disable-compute
vk_pipeline_cache: Skip compute pipelines on Intel proprietary drivers
2023-04-29 23:02:45 -07:00
Liam b143ce8134 kernel: remove general boost lists 2023-04-29 22:11:32 -04:00
Liam 1b5c87ab6a kernel: match calls to Register and Unregister 2023-04-29 21:52:26 -04:00
Liam 2afaa7aed7 common: add intrusive list type 2023-04-29 17:46:26 -04:00
bunnei fe57f39676 Merge pull request #10082 from FernandoS27/the-testers-really-love-chocolate
Refactor Accelerate DMA and do downloads through TC.
2023-04-29 11:46:01 -07:00
Fernando Sahmkow 4bc5469f52 Texture Cache: Release stagging buffers on tick frame 2023-04-29 15:31:38 +02:00
Fernando Sahmkow f8d31d1ae1 Buffer Cache: Release stagging buffers on tick frame 2023-04-29 00:46:31 +02:00
Fernando Sahmkow fff6155bc3 Tests: Add memory tracker tests. 2023-04-29 00:46:31 +02:00
Fernando Sahmkow 80480fe3f7 Clang: format and ficx compile errors. 2023-04-29 00:46:31 +02:00
Fernando Sahmkow ed4553806a Implement Async downloads in normal and fix a few issues. 2023-04-29 00:46:31 +02:00
Fernando Sahmkow f2d3212de9 Buffer Cache rework: Setup async downloads. 2023-04-29 00:46:31 +02:00
Fernando Sahmkow a16c261131 Buffer Cache: Fully rework the buffer cache. 2023-04-29 00:46:31 +02:00
Fernando Sahmkow 58d1c7c77a Address Feedback & Clang Format 2023-04-29 00:18:21 +02:00
Fernando Sahmkow 56c9730a16 Maxwell3D: only update parameters on High 2023-04-29 00:18:21 +02:00
Fernando Sahmkow e3a2ca96bd Accelerate DMA: Use texture cache async downloads to perform the copies
to host.

WIP
2023-04-29 00:18:21 +02:00
Fernando Sahmkow 3fbee093b2 TextureCache: refactor DMA downloads to allow multiple buffers. 2023-04-29 00:18:21 +02:00
Morph cb092af3f0 vk_pipeline_cache: Skip compute pipelines on Intel proprietary drivers
Intel's SPIR-V shader compiler is broken. For now, skip compiling any compute pipelines until they fix this issue.
This is not a perfect workaround, as there are a small subset of non-compute pipelines that still cause it to crash, but this should cover the majority of crashes.
It is unfortunate that even with a test case reported 6 months ago the issue has not been fixed in favor of fixing "the most popular games and apps".
Intel, you can do better than this.
2023-04-28 17:59:36 -04:00
Fernando Sahmkow 2f15876524 QueryCache: Fix write invalidation. 2023-04-28 23:53:46 +02:00
Fernando Sahmkow 9a7c172f76 MemoryManager: Fix race conditions. 2023-04-28 23:53:02 +02:00
Fernando Sahmkow e4dc73f61e Clang format and ddress feedback 2023-04-24 12:38:47 +02:00
Fernando S 9bf19b04f6 Merge pull request #10051 from liamwhite/surface-capabilities
vulkan: pick alpha composite flags based on available values
2023-04-24 12:37:13 +02:00
Fernando S 47cd0586ee Merge pull request #10056 from vonchenplus/audout_u
core: audio: return result when audio_out initialize failed
2023-04-24 12:36:52 +02:00
Fernando S 2311fa7c84 Merge pull request #10069 from liamwhite/log
maxwell_3d: fix out of bounds array access in size estimation
2023-04-24 12:36:24 +02:00
Fernando Sahmkow e29ced29fa QueryCache: rework async downloads. 2023-04-23 22:04:14 +02:00
Fernando Sahmkow 7e76c1642c Accuracy Normal: reduce accuracy further for perf improvements in Project Lime 2023-04-23 22:03:44 +02:00
Fernando Sahmkow fca72beb2d Fence Manager: implement async fence management in a sepparate thread. 2023-04-23 04:48:50 +02:00
Liam eb7c2314f6 maxwell_3d: fix out of bounds array access in size estimation 2023-04-22 10:35:26 -04:00
Fernando S d600183583 Merge pull request #10074 from Kelebek1/fermi_blit
Account for a pre-added offset when using Corner sample mode for 2D blits
2023-04-22 12:06:00 +02:00
bunnei 0f1ff5f34e Merge pull request #10076 from german77/TryPopMyFriend
core: am: Demote TryPopFromFriendInvitationStorageChannel Log level
2023-04-21 23:15:07 -07:00
bunnei d0e6eafe23 Merge pull request #10068 from twitchax/twitchax/dr_bind_address
Allow passing `--bind-address` to dedicated room.
2023-04-21 23:13:51 -07:00
bunnei 74d203fbe3 Merge pull request #10060 from german77/no_dead
core: hid: Remove deadzone of virtual controller
2023-04-21 23:13:21 -07:00
german77 7ffc42c397 core: am: Demote TryPopFromFriendInvitationStorageChannel Log level 2023-04-21 22:35:45 -06:00
Kelebek1 4e14b64bfc Account for a pre-added offset when using Corner sample mode for 2D blits 2023-04-21 19:08:21 +01:00
bunnei 0cfeb2e8d7 Merge pull request #10057 from liamwhite/its-not-in-the-timeline
vulkan: use plain fences when timeline semaphores are not available
2023-04-19 16:50:24 -07:00
Aaron Roney 79e32127b3 Run clang-format to fix all. 2023-04-19 17:52:09 +00:00
bunnei 799579c8d2 Merge pull request #10053 from german77/nfp_full
service: nfp: Implement all interfaces
2023-04-19 10:36:28 -07:00
Aaron Roney 3e7af5fbd7 Fix formatting. 2023-04-19 16:26:49 +00:00
Aaron Roney 34d0d94df0 Allow passing bind_address to dedicated room. 2023-04-19 05:37:30 +00:00
FengChen 55a33342cc core: audio: return result when audio_out initialize failed 2023-04-16 12:31:54 +08:00
german77 70a97fb5c7 core: hid: Remove deadzone of virtual controller 2023-04-15 18:41:09 -06:00
Liam e3fb9b5e00 vulkan: use plain fences when timeline semaphores are not available 2023-04-14 22:53:37 -04:00
bunnei e0895a8581 Merge pull request #10030 from Wollnashorn/botw-amd-fix
shader_recompiler: Fix ImageGather rounding on AMD/Intel
2023-04-14 16:56:34 -07:00
Narr the Reg 07694609fb Merge pull request #10055 from v1993/patch-1
input_common: minor fix to mouse movement
2023-04-14 17:05:45 -06:00
Narr the Reg 307371e01d service: nfp: Implement debug Interface 2023-04-14 17:03:58 -06:00
Narr the Reg 00800d5289 service: nfp: Implement system interface 2023-04-14 17:03:57 -06:00
Valeri 60c4032b68 input_common: minor fix to mouse movement 2023-04-14 21:27:35 +03:00
Narr the Reg 101c0df79c service: nfp: Use an unique interface 2023-04-13 22:24:27 -06:00
Liam e37e1d24f9 vulkan: pick alpha composite flags based on available values 2023-04-13 16:38:20 -04:00
Wollnashorn c0e5ecc399 video_core: Enable ImageGather rounding fix on AMD open source drivers 2023-04-12 17:11:02 +02:00
liamwhite 54b4c84ab6 Merge pull request #10008 from vonchenplus/texture_cache
video_core: update imageinfo implement
2023-04-11 11:59:18 -04:00
liamwhite 4f77275cd5 Merge pull request #10027 from bylaws/master
Add some explicit latency to sample count reporting
2023-04-10 09:23:48 -04:00
Mai 47b80da906 Merge pull request #10035 from liamwhite/long-long
kernel: switch extended memory setting to 8GB arrangement
2023-04-10 03:04:05 -04:00
Liam baf4d1c22e kernel: move more memory to application in 8GB arrangement 2023-04-09 19:50:27 -04:00
liamwhite add4f82c33 Merge pull request #10014 from goldenx86/linuxLTO
Re-enable LTO for GCC
2023-04-08 17:55:51 -04:00
Liam abb785f269 kernel: switch extended memory setting to 8GB arrangement 2023-04-08 17:47:26 -04:00
Billy Laws 8908663f12 Use GetGlobalTimeNs as opposed to clock ticks 2023-04-08 21:54:19 +01:00
Wollnashorn 82b78cde73 shader_recompiler: Use vector arithmetic rather than component-wise in ImageGatherSubpixelOffset
Should be more efficient and better readable
2023-04-08 16:13:08 +02:00
Wollnashorn fe91066f46 video_core: Enable ImageGather with subpixel offset on Intel 2023-04-08 16:12:44 +02:00
Wollnashorn 780240e697 shader_recompiler: Add subpixel offset for correct rounding at ImageGather
On AMD a subpixel offset of 1/512 of the texel size is applied to the texture coordinates at a ImageGather call to ensure the rounding at the texel centers is done the same way as in Maxwell or other Nvidia architectures.
See https://www.reedbeta.com/blog/texture-gathers-and-coordinate-precision/ for more details why this might be necessary.

This should fix shadow artifacts at object edges in Zelda: Breath of the Wild (#9957, #6956).
2023-04-08 16:12:30 +02:00
bunnei 25c4ae6e11 Merge pull request #10022 from liamwhite/gcc-13
general: fixes for gcc 13
2023-04-08 00:09:06 -07:00
Mai 6aaa8acff9 Merge pull request #10028 from zhaobot/tx-update-20230404051754
Update translations (2023-04-04)
2023-04-04 01:51:36 -04:00
The yuzu Community 455a736250 Update translations (2023-04-04) 2023-04-04 05:18:06 +00:00
Billy Laws 0afb9631b5 Add some explicit latency to sample count reporting
Some games have very tight scheduling requirements for their audio which can't really be matched on the host, adding a constant to the reported value helps to provide some leeway.
2023-04-03 23:11:36 +01:00
liamwhite bbdfe1fab1 Merge pull request #10024 from german77/crysis
service: hid: Fix handle validation
2023-04-03 13:06:07 -04:00
liamwhite ff386e794b Merge pull request #10004 from Kelebek1/cubemap
[texture_cache] Only upload GPU-modified overlaps
2023-04-03 13:05:52 -04:00
Liam a9623d5f55 general: fixes for gcc 13 2023-04-02 19:02:04 -04:00
german77 d2ae39bf4b service: hid: Fix handle validation 2023-04-02 02:21:54 -06:00
bunnei 756f013d8a Merge pull request #10020 from merryhime/update-dynarmic
externals: Update dynarmic to 6.4.6
2023-04-01 21:57:45 -07:00
bunnei 9c94faaa2b core: arm_dynarmic_32: Update SaveContext/LoadContext. 2023-04-01 17:03:08 -07:00
bunnei 6775a6ee02 Merge pull request #9969 from bylaws/master
Audio synchronisation improvements
2023-04-01 14:34:59 -07:00
liamwhite 1ab052952d Merge pull request #10006 from german77/profile_select
service: am: Improve profile select applet
2023-04-01 09:49:22 -04:00
liamwhite b2772bcb0d Merge pull request #9997 from german77/cancel_controller
applet: controller: Implement cancel button
2023-04-01 09:49:08 -04:00
liamwhite ff4fbaf152 Merge pull request #9999 from german77/new_hid_hurra
service: hid: Implement SetNpadJoyAssignmentModeSingleWithDestination
2023-04-01 09:48:53 -04:00
liamwhite 986336b0d8 Merge pull request #10017 from jbeich/vk-246
externals: update Vulkan-Headers to v1.3.246 to fix -Werror=switch with system package
2023-04-01 09:44:52 -04:00
Merry 2ddecb9631 externals: Update dynarmic to 6.4.6 2023-04-01 12:40:20 +01:00
bunnei 0730dc6c44 Merge pull request #10005 from liamwhite/kernel-atomics
kernel: fix unbounded stack usage in atomics
2023-04-01 01:54:36 -07:00
Jan Beich 083d913eab externals: update Vulkan-Headers to v1.3.246 2023-04-01 05:38:54 +00:00
Feng Chen ff2089fdf5 video_core: Keep the definition of DimensionControl consistent with nvidia open doc 2023-03-31 12:33:07 +08:00
Matías Locatti b000af0054 Re-enable LTO for Linux
Using the tested method of only enabling it for core and video_core.

Clang is skipped, because Clang.
2023-03-30 18:47:26 -03:00
liamwhite fbf0a9c976 Merge pull request #10010 from maxdunbar/typo
Fix: 'Continous' typo
2023-03-30 10:14:11 -04:00
german77 11edba4974 applet: controller: Implement cancel button 2023-03-30 07:49:44 -06:00
german77 8e84381038 service: hid: Implement SetNpadJoyAssignmentModeSingleWithDestination
Used by Let's Get Fit
2023-03-29 22:03:49 -06:00
Max Dunbar e446f368d7 Fixes 'Continous' typo 2023-03-29 19:26:12 -07:00
Narr the Reg 668eb5b8da service: am: Improve profile select applet 2023-03-29 08:53:19 -06:00
liamwhite 8bdc51b620 Merge pull request #9505 from liamwhite/request-exit
applets: implement RequestExit
2023-03-29 09:11:34 -04:00
Liam 9efd95cda5 kernel: fix unbounded stack usage in atomics 2023-03-28 22:28:27 -04:00
liamwhite 9c96d40586 Merge pull request #10003 from german77/disconnect
service: hid: Silence warning on MergeSingleJoyAsDualJoy
2023-03-28 09:09:47 -04:00
liamwhite 40efd2ab56 Merge pull request #9982 from Morph1984/tpause
x64: Make use of waitpkg instructions for power efficient sleeps
2023-03-28 09:09:35 -04:00
Kelebek1 c68b4bee2c Only upload GPU-modified overlaps 2023-03-28 11:07:39 +01:00
Morph cdc846677c telemetry: Add waitpkg instruction 2023-03-27 17:45:22 -04:00
Morph 981bc8aa1c x64: Simplify RDTSC on non-MSVC compilers
Co-Authored-By: liamwhite <liamwhite@users.noreply.github.com>
2023-03-27 17:45:22 -04:00
Morph e1bce50d8b core_timing: Make use of MicroSleep for x64 CPUs
For CPUs that support tpause, this should result in significant CPU power savings over thread yield in this spin wait.
2023-03-27 17:45:22 -04:00
Morph 27c33ab73f x64: Add MicroSleep
MicroSleep allows the processor to pause for a "short" amount of time (in the microsecond range). This is useful for spin-waiting that does not require nanosecond precision.
This uses the new TPAUSE instruction introduced on Intel's newest processors as part of the waitpkg instructions. For CPUs that do not support waitpkg instructions, this is equivalent to yield().

Co-Authored-By: liamwhite <liamwhite@users.noreply.github.com>
2023-03-27 17:45:22 -04:00
Morph d2cfe25b07 x64: cpu_detect: Add detection of waitpkg instructions
waitpkg introduces 3 instructions, UMONITOR, UMWAIT and TPAUSE.
2023-03-27 17:45:22 -04:00
Billy Laws 530fe24768 audio_core: No longer stall when sink queue is full
Now the audout and audren update rates are tied to the sink status stalling is no longer necessary.
2023-03-27 22:01:41 +01:00
Billy Laws 237934b736 Run clang-format 2023-03-27 22:01:41 +01:00
Billy Laws ea5dd02db9 audio: Wait for samples on the emulated DSP side to avoid desyncs
Waiting on the host side is inaccurate and leads to desyncs in the event of the sink missing a deadline that require stalls to fix. By waiting for the sink to have space before even starting rendering such desyncs can be avoided.
2023-03-27 21:34:28 +01:00
liamwhite fbbf532d42 Merge pull request #10002 from german77/log
qt: Fix log softlock
2023-03-27 15:37:44 -04:00
Narr the Reg c2c7386dfd service: hid: Silence warning on MergeSingleJoyAsDualJoy 2023-03-27 13:25:15 -06:00
Narr the Reg 2fbadc7e1f qt: Fix log softlock 2023-03-27 12:18:46 -06:00
liamwhite 0661f5ccd1 Merge pull request #9984 from liamwhite/global-memory
memory: rename global memory references to application memory
2023-03-27 12:16:40 -04:00
liamwhite 3b30f5d823 Merge pull request #9995 from german77/plain
service: nfp: Add plain amiibo support
2023-03-27 12:16:24 -04:00
Billy Laws d8fc3f403b audio: Interpolate system manager sample count using host sink sample info
This avoids the need to stall if the host sink sporadically misses the deadline, in such a case the previous implementation would report them samples as being played on-time, causing the guest to send more samples and leading to a gradual buildup.
2023-03-26 22:48:57 +01:00
liamwhite 8da1a4ea22 Merge pull request #9994 from liamwhite/integer-constant
tests: mark integer literals as unsigned
2023-03-26 17:22:00 -04:00
german77 8802646730 service: nfp: Add plain amiibo support 2023-03-26 14:26:36 -06:00
Liam 1476ffd865 tests: mark integer literals as unsigned 2023-03-26 15:39:07 -04:00
Morph 568d523746 Merge pull request #9992 from liamwhite/climits
container_hash: use climits
2023-03-26 14:46:21 -04:00
Liam 7017f04ee8 container_hash: use climits 2023-03-26 10:24:33 -04:00
Morph 4b508655a4 Merge pull request #9989 from Morph1984/boost-1.79-exact
CMakeLists: Use boost 1.79.0 instead
2023-03-26 03:46:43 -04:00
Morph 49f6deecb8 video_core/macro: Make use of Common::HashValue 2023-03-25 23:52:26 -04:00
Morph f09d192aac tests: Implement tests for verifying HashValue
Values were randomly generated and the verification was done against boost 1.79.
2023-03-25 23:52:26 -04:00
Morph 9971cd1d55 common: Port boost's hash_value implementation
Ports a small subset of boost's hash_value implementation (<= 1.80.0).
2023-03-25 23:52:25 -04:00
Morph c4f5615c6b CMakeLists: Require a minimum of boost 1.79.0 2023-03-25 23:03:28 -04:00
Liam 50a59487eb qt: implement RequestExit for applets 2023-03-25 14:49:43 -04:00
Liam 950db851ea applets: implement RequestExit 2023-03-25 12:44:26 -04:00
bunnei 09da9da6fb Merge pull request #9985 from liamwhite/funny-meme
vulkan: fix scheduler chunk reserve
2023-03-24 23:40:17 -07:00
Morph 6892a0942f Merge pull request #9988 from rschlaikjer/rs-gpu-page-table-copy-elision
Pass GPU page table by reference inside TextureCache::ForEachImageInRegionGPU
2023-03-25 01:59:08 -04:00
Ross Schlaikjer f38ae8e953 Pass GPU page table by reference 2023-03-25 00:25:02 -04:00
liamwhite cfb9672093 Merge pull request #9983 from Morph1984/boost
CMakeLists: Update boost to 1.81.0
2023-03-24 10:53:30 -04:00
liamwhite 462c430c8b Merge pull request #9981 from german77/nfp_connect
nfc: Initialize device when controller is connected
2023-03-24 10:53:05 -04:00
Liam 5a2dff87bf vulkan: fix scheduler chunk reserve 2023-03-24 09:09:01 -04:00
Morph 7a8a7545f2 Merge pull request #9975 from liamwhite/more-waiting
vulkan: fix more excessive waiting in scheduler
2023-03-24 00:19:43 -04:00
Morph abe2ad7aac zstd: Use ZSTD_getFrameContentSize instead of ZSTD_getDecompressedSize 2023-03-23 22:16:20 -04:00
Morph 877e8991c7 CMakeLists: Update boost to 1.81.0 2023-03-23 20:53:39 -04:00
Morph 032e5b983c vcpkg: Update vcpkg to 2023.02.24 2023-03-23 20:53:39 -04:00
Liam 41d99aa89d memory: rename global memory references to application memory 2023-03-23 20:28:47 -04:00
liamwhite ac3927074b Merge pull request #9971 from Morph1984/q
bounded_threadsafe_queue: Use simplified impl of bounded queue
2023-03-23 10:00:31 -04:00
liamwhite c41a4baf06 Merge pull request #9964 from liamwhite/typed-address
kernel: use KTypedAddress for addresses
2023-03-23 10:00:19 -04:00
Morph 6adaa0d5e2 Merge pull request #9962 from Kelebek1/disable_srgb
[video_core] Disable SRGB border color conversion in samplers
2023-03-23 03:07:00 -04:00
Liam fb49ec19c1 kernel: use KTypedAddress for addresses 2023-03-22 09:35:16 -04:00
Morph 197d756560 bounded_threadsafe_queue: Refactor Pop
Introduces PopModes to bring waiting logic into Pop, similar to Push.
2023-03-21 22:33:58 -04:00
Morph 8c56481249 bounded_threadsafe_queue: Add producer cv to avoid busy waiting 2023-03-21 22:33:57 -04:00
Narr the Reg 6ff4bf9b1c nfc: Initialize device when controller is connected 2023-03-21 20:09:36 -06:00
bunnei dba86ee007 Merge pull request #9965 from german77/thankYouEpicBoy
config: Fix controller config from resetting
2023-03-21 17:52:25 -07:00
Morph 407dc917f1 bounded_threadsafe_queue: Deduplicate and add PushModes
Adds the PushModes Try and Wait to allow producers to specify how they want to push their data to the queue if the queue is full.
If the queue is full:
- Try will fail to push to the queue, returning false. Try only returns true if it successfully pushes to the queue. This may result in items not being pushed into the queue.
- Wait will wait until a slot is available to push to the queue, resulting in potential for deadlock if a consumer is not running.
2023-03-21 19:20:21 -04:00
Morph 15d573194c bounded_threadsafe_queue: Add TryPush 2023-03-21 19:17:38 -04:00
Morph f28ca5361f logging: Make use of bounded queue 2023-03-21 19:17:38 -04:00
Morph 306840a580 bounded_threadsafe_queue: Use simplified impl of bounded queue
Provides a simplified SPSC, MPSC, and MPMC bounded queue implementation using mutexes.
2023-03-21 19:17:32 -04:00
bunnei 3d4c113037 Merge pull request #9970 from bunnei/string-util-view
common: string_util: Use std::string_view for UTF16ToUTF8/UTF8ToUTF16W.
2023-03-19 11:10:16 -07:00
bunnei 230d118252 Merge pull request #9972 from liamwhite/ipc-trace
kernel: fix LOG_TRACE in ipc
2023-03-19 11:00:42 -07:00
Liam b9b1318bea vulkan: fix more excessive waiting in scheduler 2023-03-19 13:40:33 -04:00
Liam 43d909949e kernel: fix LOG_TRACE in ipc 2023-03-19 10:02:20 -04:00
bunnei 00d401d639 common: string_util: Use std::string_view for UTF16ToUTF8/UTF8ToUTF16W. 2023-03-18 22:42:25 -07:00
liamwhite 0e7e98e24e Merge pull request #9966 from bunnei/bounded-polyfill
common: bounded_threadsafe_queue: Use polyfill_thread.
2023-03-18 12:39:52 -04:00
bunnei 0eb3fa05e5 common: bounded_threadsafe_queue: Use polyfill_thread. 2023-03-17 23:42:17 -07:00
bunnei 889454f9bf Merge pull request #9778 from behunin/my-box-chevy
gpu_thread: Use bounded queue
2023-03-17 22:14:29 -07:00
bunnei 8bcaa8c2e4 Merge pull request #9953 from german77/amiibo_crc
service: nfp: Actually write correct crc
2023-03-17 22:13:57 -07:00
Narr the Reg c95baf92ce config: Fix controller config from resetting 2023-03-17 22:08:16 -06:00
Kelebek1 a7651168dd Disable SRGB border color conversion for now, to fix shadows in Xenoblade. 2023-03-17 04:46:38 +00:00
Narr the Reg 075a3d1172 service: nfp: Replace crc function with boost equivalent 2023-03-16 17:47:32 -06:00
liamwhite 6d76a54d37 Merge pull request #9955 from liamwhite/color-blend-equation
vulkan: disable extendedDynamicState3ColorBlendEquation on radv
2023-03-15 20:19:45 -04:00
liamwhite a04061e6ae Merge pull request #9931 from liamwhite/sched
vk_scheduler: split work queue waits and execution waits
2023-03-15 20:19:35 -04:00
Narr the Reg 7187732454 service: nfp: Close app area and recreate crc 2023-03-15 17:01:06 -06:00
Narr the Reg 5031f5b8b0 service: nfp: Convert mii colors to v3 2023-03-15 17:01:05 -06:00
Liam da83afdeaf vulkan: disable extendedDynamicState3ColorBlendEquation on radv 2023-03-15 15:55:07 -04:00
Narr the Reg 026fe2e4f4 service: nfp: Actually write correct crc 2023-03-14 23:42:41 -06:00
liamwhite 0c7149d222 Merge pull request #9933 from vonchenplus/texture_format
video_core: Update texture format
2023-03-14 11:35:37 -04:00
FengChen 11ffbee5ae video_core: Better defined ImageInfo parameters 2023-03-14 22:36:34 +08:00
bunnei 05f26e1337 Merge pull request #9951 from Morph1984/save
configure_audio: Fix output mode setting not saving
2023-03-13 18:49:14 -07:00
Morph 4c678cfbc8 configure_audio: Fix output mode setting not saving 2023-03-13 17:41:30 -04:00
liamwhite 8870fae674 Merge pull request #9939 from german77/vibration
input_common: sdl: Only send last vibration command
2023-03-13 13:45:40 -04:00
liamwhite 8348c41eab Merge pull request #9941 from german77/settings
yuzu: Move audio settings to audio section
2023-03-13 13:45:29 -04:00
liamwhite 638044820d Merge pull request #9943 from vonchenplus/gentleman
video_core: Fix inline_index and draw_texture error
2023-03-13 13:45:17 -04:00
liamwhite 1f952f6ac9 Merge pull request #9936 from liamwhite/m_this
kernel: use consistent style
2023-03-13 09:16:16 -04:00
german77 96b8a3ecac input_common: sdl: Only send last vibration command 2023-03-12 21:30:02 -06:00
Liam c352381ce9 kernel: additional style fixes to KThread, KProcess 2023-03-12 22:10:27 -04:00
Liam 9775a73d1a kernel: fix clang build 2023-03-12 22:10:27 -04:00
Liam 088c434d65 kernel: remove unnecessary finalize calls 2023-03-12 22:10:27 -04:00
Liam 9863db9db4 kernel: convert KProcess to new style 2023-03-12 22:09:27 -04:00
Liam 6bfb4c8f71 kernel: convert KThread to new style 2023-03-12 22:09:09 -04:00
Liam ac6cbb7134 kernel: prefer std::addressof 2023-03-12 22:09:09 -04:00
Liam 641783df8f kernel: convert KResourceLimit 2023-03-12 22:09:09 -04:00
Liam c0b9e93b77 kernel: remove kernel_ 2023-03-12 22:09:09 -04:00
Liam 9368e17a92 kernel: remove gratitutous attribute usage 2023-03-12 22:09:09 -04:00
Liam 91fd4e30f2 kernel/svc: convert to new style 2023-03-12 22:09:08 -04:00
Liam 57f1d8ef8d kernel: convert miscellaneous 2023-03-12 22:06:53 -04:00
Liam d1b53c8d82 kernel: conver KScopedLock, KScopedResourceReservation, KSessionRequest, KSharedMemory, KSpinLock 2023-03-12 22:06:53 -04:00
Liam 7322c99e5f kernel: convert KAbstractSchedulerLock 2023-03-12 22:06:53 -04:00
Liam 467adc1acd kernel: convert KMemoryLayout, KMemoryRegion*, KPageTableSlabHeap, KPriorityQueue 2023-03-12 22:06:53 -04:00
Liam 0483dfae1a kernel: move KMemoryLayout for NX board 2023-03-12 22:06:53 -04:00
Liam 8d1f5bfbd2 kernel: remove KLinkedList 2023-03-12 22:06:53 -04:00
Liam fdf90c6d75 kernel: convert KConditionVariable, KLightConditionVariable, KLightLock 2023-03-12 22:06:53 -04:00
Liam 097c25b164 kernel: convert KPort, KSession 2023-03-12 22:06:53 -04:00
Liam d24ab14126 kernel: convert GlobalSchedulerContext, KAddressArbiter, KScopedSchedulerLockAndSleep, KThreadQueue to new style 2023-03-12 22:06:53 -04:00
liamwhite 54c359d1e3 Merge pull request #9942 from liamwhite/speling
general: use codespell to identify spelling mistakes
2023-03-12 21:59:46 -04:00
Liam 3f261f22c9 vk_scheduler: split work queue waits and execution waits 2023-03-12 17:19:44 -04:00
Liam 600f325d87 general: fix spelling mistakes 2023-03-12 11:33:01 -04:00
FengChen 44f10c8dee video_core: Fix ogl status error when draw_texture 2023-03-12 13:33:31 +08:00
FengChen 4e42ba54e5 video_core: Invalid index_buffer flag when inline_index draw 2023-03-12 13:21:26 +08:00
Liam d155167ea2 general: use codespell to identify spelling mistakes 2023-03-11 22:08:43 -05:00
Fernando S 49643d8134 Merge pull request #9913 from ameerj/acc-dma-refactor
AccelerateDMA: Refactor Buffer/Image copy code and implement for OGL
2023-03-11 20:04:19 +01:00
liamwhite 92c89312fc Merge pull request #9923 from liamwhite/kht
kernel: add timer pointer to KThreadQueue
2023-03-10 16:19:41 -05:00
liamwhite e0bd27b674 Merge pull request #9928 from german77/super_nfp
service: nfp: Improve implementation
2023-03-10 13:55:28 -05:00
liamwhite 103380134f Merge pull request #9925 from ameerj/gl-sync-signal
OpenGL: Prefer glClientWaitSync for OGLSync objects
2023-03-10 13:55:22 -05:00
liamwhite 021af4fd00 Merge pull request #9917 from Morph1984/the-real-time
native_clock: Re-adjust the RDTSC frequency to its real frequency
2023-03-10 13:55:11 -05:00
Feng Chen c8ad039612 video_core: Update texture format 2023-03-10 21:48:50 +08:00
Narr the Reg 8d5cde6eff service: nfp: Improve implementation 2023-03-09 19:29:28 -06:00
liamwhite ec4e2d1fab Merge pull request #9916 from liamwhite/fpu
kernel: clone fpu status on CreateThread
2023-03-09 09:19:15 -05:00
liamwhite b5c0c1e163 Merge pull request #9822 from ameerj/buffcache-ssbo-addr
buffer_cache: Add logic for non-NVN storage buffer tracking
2023-03-09 09:18:39 -05:00
ameerj 03137086db OpenGL: Prefer glClientWaitSync for OGLSync objects
At least on Nvidia, glClientWaitSync with a timeout of 0 (non-blocking) is faster than glGetSynciv of GL_SYNC_STATUS.
2023-03-08 20:29:25 -05:00
Morph 67560296c6 perf_stats: Check multicore first
SpeedLimiting is SC only. Since MC is performance oriented we should check for it first to skip checking use_speed_limit.
2023-03-07 23:11:01 -05:00
Morph 1073346c7f hid: Use nanosecond timestamps instead of ticks 2023-03-07 21:17:47 -05:00
Morph 3053a62375 core: Promote CPU/GPU threads to time critical
And also demote Audren and CoreTiming to High thread priority.
2023-03-07 21:17:46 -05:00
Morph d718eab351 native_clock: Wait for 10 seconds instead of 30
It was experimentally determined to be sufficient.
2023-03-07 21:17:46 -05:00
Morph c27a626b5b native_clock: Use RealTimeClock instead of SteadyClock
We want to synchronize RDTSC to real time.
2023-03-07 21:17:46 -05:00
Morph 6f9918552c steady_clock: Introduce a real time clock 2023-03-07 21:17:46 -05:00
Morph dcd13a7566 native_clock: Re-adjust the RDTSC frequency
The RDTSC frequency reported by CPUID is not accurate to its true frequency.
We will spawn a separate thread to calculate the true RDTSC frequency after a measurement period of 30 seconds has elapsed.
2023-03-07 21:17:46 -05:00
Liam 1776448df2 kernel: add timer pointer to KThreadQueue 2023-03-07 20:51:29 -05:00
Liam 484641003c kernel: clone fpu status on CreateThread 2023-03-07 19:18:06 -05:00
ameerj 268942c8fe gl_rasterizer: Implement AccelerateDMA DmaBufferImageCopy 2023-03-06 22:57:52 -05:00
ameerj 6b9cc0ed23 Refactor AccelerateDMA code 2023-03-06 22:57:45 -05:00
Behunin 44518b225c gpu_thread: Use bounded queue 2023-03-03 18:20:56 -07:00
ameerj 2ce5bb9bd6 buffer_cache: Add logic for non-NVN storage buffer tracking 2023-02-25 16:24:21 -05:00
495 changed files with 21258 additions and 16839 deletions
+1
View File
@@ -22,6 +22,7 @@ cmake .. \
-DUSE_DISCORD_PRESENCE=ON \
-DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
-DYUZU_USE_BUNDLED_FFMPEG=ON \
-DYUZU_ENABLE_LTO=ON \
-GNinja
ninja
+1 -1
View File
@@ -40,7 +40,7 @@ def parse_imports(file_name):
def parse_imports_recursive(file_name, path_list=[]):
q = queue.Queue() # create a FIFO queue
# file_name can be a string or a list for the convience
# file_name can be a string or a list for the convenience
if isinstance(file_name, str):
q.put(file_name)
elif isinstance(file_name, list):
+6
View File
@@ -0,0 +1,6 @@
; SPDX-FileCopyrightText: 2023 yuzu Emulator Project
; SPDX-License-Identifier: GPL-2.0-or-later
[codespell]
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES
ignore-words-list = aci,allright,ba,deques,froms,hda,inout,lod,masia,nam,nax,nd,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
+17
View File
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# GitHub Action to automate the identification of common misspellings in text files.
# https://github.com/codespell-project/actions-codespell
# https://github.com/codespell-project/codespell
name: codespell
on: pull_request
permissions: {}
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
persist-credentials: false
- uses: codespell-project/actions-codespell@master
+4 -4
View File
@@ -210,7 +210,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
# =======================================================================
# Enforce the search mode of non-required packages for better and shorter failure messages
find_package(Boost 1.73.0 REQUIRED context)
find_package(Boost 1.79.0 REQUIRED context)
find_package(enet 1.3 MODULE)
find_package(fmt 9 REQUIRED)
find_package(inih 52 MODULE COMPONENTS INIReader)
@@ -222,7 +222,7 @@ find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED)
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
find_package(Vulkan 1.3.238 REQUIRED)
find_package(Vulkan 1.3.246 REQUIRED)
endif()
if (ENABLE_LIBUSB)
@@ -344,12 +344,12 @@ if(ENABLE_QT)
find_package(PkgConfig REQUIRED)
pkg_check_modules(QT_DEP_GLU QUIET glu>=9.0.0)
if (NOT QT_DEP_GLU_FOUND)
message(FATAL_ERROR "Qt bundled pacakge dependency `glu` not found. \
message(FATAL_ERROR "Qt bundled package dependency `glu` not found. \
Perhaps `libglu1-mesa-dev` needs to be installed?")
endif()
pkg_check_modules(QT_DEP_MESA QUIET dri>=20.0.8)
if (NOT QT_DEP_MESA_FOUND)
message(FATAL_ERROR "Qt bundled pacakge dependency `dri` not found. \
message(FATAL_ERROR "Qt bundled package dependency `dri` not found. \
Perhaps `mesa-common-dev` needs to be installed?")
endif()
+1 -1
View File
@@ -14,7 +14,7 @@
# FFmpeg_LIBRARIES: aggregate all the paths to the libraries
# FFmpeg_FOUND: True if all components have been found
#
# This module defines the following targets, which are prefered over variables:
# This module defines the following targets, which are preferred over variables:
#
# FFmpeg::<component>: Target to use <component> directly, with include path,
# library and dependencies set up. If you are using a static build, you are
+365 -370
View File
File diff suppressed because it is too large Load Diff
+364 -369
View File
File diff suppressed because it is too large Load Diff
+365 -370
View File
File diff suppressed because it is too large Load Diff
+368 -373
View File
File diff suppressed because it is too large Load Diff
+365 -370
View File
File diff suppressed because it is too large Load Diff
+395 -400
View File
File diff suppressed because it is too large Load Diff
+370 -375
View File
File diff suppressed because it is too large Load Diff
+364 -369
View File
File diff suppressed because it is too large Load Diff
+375 -380
View File
File diff suppressed because it is too large Load Diff
+381 -383
View File
File diff suppressed because it is too large Load Diff
+366 -371
View File
File diff suppressed because it is too large Load Diff
+365 -370
View File
File diff suppressed because it is too large Load Diff
+1409 -1372
View File
File diff suppressed because it is too large Load Diff
+366 -371
View File
File diff suppressed because it is too large Load Diff
+375 -380
View File
File diff suppressed because it is too large Load Diff
+376 -381
View File
File diff suppressed because it is too large Load Diff
+454 -422
View File
File diff suppressed because it is too large Load Diff
+397 -402
View File
File diff suppressed because it is too large Load Diff
+366 -371
View File
File diff suppressed because it is too large Load Diff
+366 -371
View File
File diff suppressed because it is too large Load Diff
+366 -371
View File
File diff suppressed because it is too large Load Diff
+366 -371
View File
File diff suppressed because it is too large Load Diff
+15 -1
View File
@@ -83,7 +83,7 @@ if (MSVC)
)
if (USE_CCACHE OR YUZU_USE_PRECOMPILED_HEADERS)
# when caching, we need to use /Z7 to downgrade debug info to use an older but more cachable format
# when caching, we need to use /Z7 to downgrade debug info to use an older but more cacheable format
# Precompiled headers are deleted if not using /Z7. See https://github.com/nanoant/CMakePCHCompiler/issues/21
add_compile_options(/Z7)
else()
@@ -113,6 +113,9 @@ else()
$<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
$<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
$<$<CXX_COMPILER_ID:Clang>:-Werror=shadow-uncaptured-local>
$<$<CXX_COMPILER_ID:Clang>:-Werror=implicit-fallthrough>
$<$<CXX_COMPILER_ID:Clang>:-Werror=type-limits>
$<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init>
$<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>
)
@@ -126,6 +129,17 @@ else()
add_compile_options("-stdlib=libc++")
endif()
# GCC bugs
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# These diagnostics would be great if they worked, but are just completely broken
# and produce bogus errors on external libraries like fmt.
add_compile_options(
-Wno-array-bounds
-Wno-stringop-overread
-Wno-stringop-overflow
)
endif()
# Set file offset size to 64 bits.
#
# On modern Unixes, this is typically already the case. The lone exception is
+1 -1
View File
@@ -58,7 +58,7 @@ public:
/**
* Get a list of audio out device names.
*
* @oaram names - Output container to write names to.
* @param names - Output container to write names to.
* @return Number of names written.
*/
u32 GetAudioOutDeviceNames(
+1 -1
View File
@@ -16,7 +16,7 @@ struct AudioBuffer {
s64 played_timestamp;
/// Game memory address for these samples.
VAddr samples;
/// Unqiue identifier for this buffer.
/// Unique identifier for this buffer.
u64 tag;
/// Size of the samples buffer.
u64 size;
+3 -4
View File
@@ -93,7 +93,7 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
stream->AppendBuffer(new_buffer, samples);
} else {
std::vector<s16> samples(buffer.size / sizeof(s16));
system.Memory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size);
system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size);
stream->AppendBuffer(new_buffer, samples);
}
}
@@ -102,7 +102,7 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
void DeviceSession::ReleaseBuffer(const AudioBuffer& buffer) const {
if (type == Sink::StreamType::In) {
auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))};
system.Memory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size);
system.ApplicationMemory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size);
}
}
@@ -121,8 +121,7 @@ u64 DeviceSession::GetPlayedSampleCount() const {
}
std::optional<std::chrono::nanoseconds> DeviceSession::ThreadFunc() {
// Add 5ms of samples at a 48K sample rate.
played_sample_count += 48'000 * INCREMENT_TIME / 1s;
played_sample_count = stream->GetExpectedPlayedSampleCount();
if (type == Sink::StreamType::Out) {
system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioOutManager, true);
} else {
+1 -1
View File
@@ -13,7 +13,7 @@
namespace AudioCore::AudioRenderer::ADSP {
ADSP::ADSP(Core::System& system_, Sink::Sink& sink_)
: system{system_}, memory{system.Memory()}, sink{sink_} {}
: system{system_}, memory{system.ApplicationMemory()}, sink{sink_} {}
ADSP::~ADSP() {
ClearCommandBuffers();
@@ -135,7 +135,7 @@ void AudioRenderer::ThreadFunc() {
static constexpr char name[]{"AudioRenderer"};
MicroProfileOnThreadCreate(name);
Common::SetCurrentThreadName(name);
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
if (mailbox->ADSPWaitMessage() != RenderMessage::AudioRenderer_InitializeOK) {
LOG_ERROR(Service_Audio,
"ADSP Audio Renderer -- Failed to receive initialize message from host!");
@@ -165,7 +165,7 @@ void AudioRenderer::ThreadFunc() {
// Check this buffer is valid, as it may not be used.
if (command_buffer.buffer != 0) {
// If there are no remaining commands (from the previous list),
// this is a new command list, initalize it.
// this is a new command list, initialize it.
if (command_buffer.remaining_command_count == 0) {
command_list_processor.Initialize(system, command_buffer.buffer,
command_buffer.size, streams[index]);
@@ -189,6 +189,8 @@ void AudioRenderer::ThreadFunc() {
max_time = std::min(command_buffer.time_limit, max_time);
command_list_processor.SetProcessTimeMax(max_time);
streams[index]->WaitFreeSpace();
// Process the command list
{
MICROPROFILE_SCOPE(Audio_Renderer);
@@ -10,6 +10,7 @@
#include "audio_core/renderer/adsp/command_buffer.h"
#include "audio_core/renderer/adsp/command_list_processor.h"
#include "common/common_types.h"
#include "common/polyfill_thread.h"
#include "common/reader_writer_queue.h"
#include "common/thread.h"
@@ -17,7 +17,7 @@ namespace AudioCore::AudioRenderer::ADSP {
void CommandListProcessor::Initialize(Core::System& system_, CpuAddr buffer, u64 size,
Sink::SinkStream* stream_) {
system = &system_;
memory = &system->Memory();
memory = &system->ApplicationMemory();
stream = stream_;
header = reinterpret_cast<CommandListHeader*>(buffer);
commands = reinterpret_cast<u8*>(buffer + sizeof(CommandListHeader));
@@ -155,7 +155,7 @@ public:
/**
* Check if a variadic command buffer is supported.
* As of Rev 5 with the added optional performance metric logging, the command
* buffer can be a variable size, so take that into account for calcualting its size.
* buffer can be a variable size, so take that into account for calculating its size.
*
* @return True if supported, otherwise false.
*/
@@ -192,7 +192,7 @@ public:
/**
* Get this effect's parameter data.
*
* @return Pointer to the parametter, must be cast to the correct type.
* @return Pointer to the parameter, must be cast to the correct type.
*/
u8* GetParameter() {
return parameter.data();
@@ -201,7 +201,7 @@ public:
/**
* Get this effect's parameter data.
*
* @return Pointer to the parametter, must be cast to the correct type.
* @return Pointer to the parameter, must be cast to the correct type.
*/
u8* GetStateBuffer() {
return state.data();
@@ -29,7 +29,7 @@ public:
*/
enum class State {
Invalid,
Aquired,
Acquired,
RequestDetach,
Detached,
RequestAttach,
+1 -1
View File
@@ -93,7 +93,7 @@ public:
* Splitter sort, traverse the splitter node graph and sort the sorted mixes from results.
*
* @param splitter_context - Splitter context for the sort.
* @return True if the sort was successful, othewise false.
* @return True if the sort was successful, otherwise false.
*/
bool TSortInfo(const SplitterContext& splitter_context);
@@ -33,7 +33,7 @@ struct PerformanceDetailVersion1 {
/* 0x0D */ PerformanceEntryType entry_type;
};
static_assert(sizeof(PerformanceDetailVersion1) == 0x10,
"PerformanceDetailVersion1 has the worng size!");
"PerformanceDetailVersion1 has the wrong size!");
struct PerformanceDetailVersion2 {
/* 0x00 */ u32 node_id;
@@ -45,6 +45,6 @@ struct PerformanceDetailVersion2 {
/* 0x14 */ char unk14[0x4];
};
static_assert(sizeof(PerformanceDetailVersion2) == 0x18,
"PerformanceDetailVersion2 has the worng size!");
"PerformanceDetailVersion2 has the wrong size!");
} // namespace AudioCore::AudioRenderer
@@ -22,7 +22,7 @@ struct PerformanceEntryVersion1 {
/* 0x0C */ PerformanceEntryType entry_type;
};
static_assert(sizeof(PerformanceEntryVersion1) == 0x10,
"PerformanceEntryVersion1 has the worng size!");
"PerformanceEntryVersion1 has the wrong size!");
struct PerformanceEntryVersion2 {
/* 0x00 */ u32 node_id;
@@ -32,6 +32,6 @@ struct PerformanceEntryVersion2 {
/* 0x0D */ char unk0D[0xB];
};
static_assert(sizeof(PerformanceEntryVersion2) == 0x18,
"PerformanceEntryVersion2 has the worng size!");
"PerformanceEntryVersion2 has the wrong size!");
} // namespace AudioCore::AudioRenderer
@@ -16,7 +16,7 @@ struct PerformanceFrameHeaderVersion1 {
/* 0x14 */ u32 frame_index;
};
static_assert(sizeof(PerformanceFrameHeaderVersion1) == 0x18,
"PerformanceFrameHeaderVersion1 has the worng size!");
"PerformanceFrameHeaderVersion1 has the wrong size!");
struct PerformanceFrameHeaderVersion2 {
/* 0x00 */ u32 magic; // "PERF"
@@ -31,6 +31,6 @@ struct PerformanceFrameHeaderVersion2 {
/* 0x25 */ char unk25[0xB];
};
static_assert(sizeof(PerformanceFrameHeaderVersion2) == 0x30,
"PerformanceFrameHeaderVersion2 has the worng size!");
"PerformanceFrameHeaderVersion2 has the wrong size!");
} // namespace AudioCore::AudioRenderer
@@ -55,7 +55,7 @@ public:
/**
* Get the total number of splitter destinations.
*
* @return Number of destiantions.
* @return Number of destinations.
*/
u32 GetDataCount() const;
@@ -87,7 +87,7 @@ public:
/**
* Update this destination.
*
* @param params - Inpout parameters to update the destination.
* @param params - Input parameters to update the destination.
*/
void Update(const InParameter& params);
@@ -126,9 +126,9 @@ private:
std::array<f32, MaxMixBuffers> prev_mix_volumes{0.0f};
/// Next destination in the mix chain
SplitterDestinationData* next{};
/// Is this destiantion in use?
/// Is this destination in use?
bool in_use{};
/// Does this destiantion need its volumes updated?
/// Does this destination need its volumes updated?
bool need_update{};
};
@@ -49,14 +49,14 @@ public:
/**
* Get the number of destinations in this splitter.
*
* @return The number of destiantions.
* @return The number of destinations.
*/
u32 GetDestinationCount() const;
/**
* Set the number of destinations in this splitter.
*
* @param count - The new number of destiantions.
* @param count - The new number of destinations.
*/
void SetDestinationCount(u32 count);
+1 -2
View File
@@ -127,8 +127,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
render_device = params.rendering_device;
execution_mode = params.execution_mode;
core.Memory().ZeroBlock(*core.ApplicationProcess(), transfer_memory->GetSourceAddress(),
transfer_memory_size);
core.ApplicationMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size);
// Note: We're not actually using the transfer memory because it's a pain to code for.
// Allocate the memory normally instead and hope the game doesn't try to read anything back
+2 -2
View File
@@ -154,7 +154,7 @@ public:
ExecutionMode GetExecutionMode() const;
/**
* Get the rendering deivce for this system.
* Get the rendering device for this system.
* This is unused.
*
* @return Rendering device for this system.
@@ -241,7 +241,7 @@ private:
std::span<u8> command_workbuffer{};
/// Size of command workbuffer
u64 command_workbuffer_size{};
/// Numebr of commands in the workbuffer
/// Number of commands in the workbuffer
u64 command_buffer_size{};
/// Manager for upsamplers
UpsamplerManager* upsampler_manager{};
+1 -18
View File
@@ -15,14 +15,9 @@ MICROPROFILE_DEFINE(Audio_RenderSystemManager, "Audio", "Render System Manager",
MP_RGB(60, 19, 97));
namespace AudioCore::AudioRenderer {
constexpr std::chrono::nanoseconds RENDER_TIME{5'000'000UL};
SystemManager::SystemManager(Core::System& core_)
: core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()},
thread_event{Core::Timing::CreateEvent(
"AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
return ThreadFunc2(time);
})} {}
: core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()} {}
SystemManager::~SystemManager() {
Stop();
@@ -33,8 +28,6 @@ bool SystemManager::InitializeUnsafe() {
if (adsp.Start()) {
active = true;
thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); });
core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), RENDER_TIME,
thread_event);
}
}
@@ -45,7 +38,6 @@ void SystemManager::Stop() {
if (!active) {
return;
}
core.CoreTiming().UnscheduleEvent(thread_event, {});
active = false;
update.store(true);
update.notify_all();
@@ -111,16 +103,7 @@ void SystemManager::ThreadFunc() {
adsp.Signal();
adsp.Wait();
update.wait(false);
update.store(false);
}
}
std::optional<std::chrono::nanoseconds> SystemManager::ThreadFunc2(s64 time) {
update.store(true);
update.notify_all();
return std::nullopt;
}
} // namespace AudioCore::AudioRenderer
+3 -10
View File
@@ -36,7 +36,7 @@ public:
/**
* Initialize the system manager, called when any system is registered.
*
* @return True if sucessfully initialized, otherwise false.
* @return True if successfully initialized, otherwise false.
*/
bool InitializeUnsafe();
@@ -50,7 +50,7 @@ public:
* The manager does not own the system, so do not free it without calling Remove.
*
* @param system - The system to add.
* @return True if succesfully added, otherwise false.
* @return True if successfully added, otherwise false.
*/
bool Add(System& system);
@@ -58,7 +58,7 @@ public:
* Remove an audio render system from the manager.
*
* @param system - The system to remove.
* @return True if succesfully removed, otherwise false.
* @return True if successfully removed, otherwise false.
*/
bool Remove(System& system);
@@ -68,11 +68,6 @@ private:
*/
void ThreadFunc();
/**
* Signalling core timing thread to run ThreadFunc.
*/
std::optional<std::chrono::nanoseconds> ThreadFunc2(s64 time);
enum class StreamState {
Filling,
Steady,
@@ -95,8 +90,6 @@ private:
ADSP::ADSP& adsp;
/// AudioRenderer mailbox for communication
ADSP::AudioRenderer_Mailbox* mailbox{};
/// Core timing event to signal main thread
std::shared_ptr<Core::Timing::EventType> thread_event;
/// Atomic for main thread to wait on
std::atomic<bool> update{};
};
+2 -2
View File
@@ -183,7 +183,7 @@ public:
void Initialize();
/**
* Does this voice ned an update?
* Does this voice need an update?
*
* @param params - Input parameters to check matching.
*
@@ -236,7 +236,7 @@ public:
*
* @param error_info - Output array of errors.
* @param wave_buffer - The wavebuffer to be updated.
* @param wave_buffer_internal - Input parametters to be used for the update.
* @param wave_buffer_internal - Input parameters to be used for the update.
* @param sample_format - Sample format of the wavebuffer.
* @param valid - Is this wavebuffer valid?
* @param pool_mapper - Used to map the wavebuffers.
-4
View File
@@ -101,8 +101,6 @@ public:
~CubebSinkStream() override {
LOG_DEBUG(Service_Audio, "Destructing cubeb stream {}", name);
Unstall();
if (!ctx) {
return;
}
@@ -143,8 +141,6 @@ public:
* Stop the sink stream.
*/
void Stop() override {
Unstall();
if (!ctx || paused) {
return;
}
-2
View File
@@ -88,7 +88,6 @@ public:
* Finalize the sink stream.
*/
void Finalize() override {
Unstall();
if (device == 0) {
return;
}
@@ -116,7 +115,6 @@ public:
* Stop the sink stream.
*/
void Stop() override {
Unstall();
if (device == 0 || paused) {
return;
}
+30 -37
View File
@@ -14,6 +14,8 @@
#include "common/fixed_point.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
namespace AudioCore::Sink {
@@ -149,10 +151,6 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
return;
}
if (queued_buffers > max_queue_size) {
Stall();
}
while (frames_written < num_frames) {
// If the playing buffer has been consumed or has no frames, we need a new one
if (playing_buffer.consumed || playing_buffer.frames == 0) {
@@ -187,10 +185,6 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
}
std::memcpy(&last_frame[0], &input_buffer[(frames_written - 1) * frame_size], frame_size_bytes);
if (queued_buffers <= max_queue_size) {
Unstall();
}
}
void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::size_t num_frames) {
@@ -198,10 +192,15 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
const std::size_t frame_size = num_channels;
const std::size_t frame_size_bytes = frame_size * sizeof(s16);
size_t frames_written{0};
size_t actual_frames_written{0};
// If we're paused or going to shut down, we don't want to consume buffers as coretiming is
// paused and we'll desync, so just play silence.
if (system.IsPaused() || system.IsShuttingDown()) {
if (system.IsShuttingDown()) {
release_cv.notify_one();
}
static constexpr std::array<s16, 6> silence{};
for (size_t i = frames_written; i < num_frames; i++) {
std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes);
@@ -209,20 +208,6 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
return;
}
// Due to many frames being queued up with nvdec (5 frames or so?), a lot of buffers also get
// queued up (30+) but not all at once, which causes constant stalling here, so just let the
// video play out without attempting to stall.
// Can hopefully remove this later with a more complete NVDEC implementation.
const auto nvdec_active{system.AudioCore().IsNVDECActive()};
// Core timing cannot be paused in single-core mode, so Stall ends up being called over and over
// and never recovers to a normal state, so just skip attempting to sync things on single-core.
if (system.IsMulticore() && !nvdec_active && queued_buffers > max_queue_size) {
Stall();
} else if (system.IsMulticore() && queued_buffers <= max_queue_size) {
Unstall();
}
while (frames_written < num_frames) {
// If the playing buffer has been consumed or has no frames, we need a new one
if (playing_buffer.consumed || playing_buffer.frames == 0) {
@@ -237,6 +222,10 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
}
// Successfully dequeued a new buffer.
queued_buffers--;
{ std::unique_lock lk{release_mutex}; }
release_cv.notify_one();
}
// Get the minimum frames available between the currently playing buffer, and the
@@ -248,6 +237,7 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
frames_available * frame_size);
frames_written += frames_available;
actual_frames_written += frames_available;
playing_buffer.frames_played += frames_available;
// If that's all the frames in the current buffer, add its samples and mark it as
@@ -260,26 +250,29 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size],
frame_size_bytes);
if (system.IsMulticore() && queued_buffers <= max_queue_size) {
Unstall();
{
std::scoped_lock lk{sample_count_lock};
last_sample_count_update_time = system.CoreTiming().GetGlobalTimeNs();
min_played_sample_count = max_played_sample_count;
max_played_sample_count += actual_frames_written;
}
}
void SinkStream::Stall() {
std::scoped_lock lk{stall_guard};
if (stalled_lock) {
return;
}
stalled_lock = system.StallApplication();
u64 SinkStream::GetExpectedPlayedSampleCount() {
std::scoped_lock lk{sample_count_lock};
auto cur_time{system.CoreTiming().GetGlobalTimeNs()};
auto time_delta{cur_time - last_sample_count_update_time};
auto exp_played_sample_count{min_played_sample_count +
(TargetSampleRate * time_delta) / std::chrono::seconds{1}};
// Add 15ms of latency in sample reporting to allow for some leeway in scheduler timings
return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3;
}
void SinkStream::Unstall() {
std::scoped_lock lk{stall_guard};
if (!stalled_lock) {
return;
}
system.UnstallApplication();
stalled_lock.unlock();
void SinkStream::WaitFreeSpace() {
std::unique_lock lk{release_mutex};
release_cv.wait(
lk, [this]() { return queued_buffers < max_queue_size || system.IsShuttingDown(); });
}
} // namespace AudioCore::Sink
+20 -9
View File
@@ -5,6 +5,7 @@
#include <array>
#include <atomic>
#include <chrono>
#include <memory>
#include <mutex>
#include <span>
@@ -14,6 +15,7 @@
#include "common/common_types.h"
#include "common/reader_writer_queue.h"
#include "common/ring_buffer.h"
#include "common/thread.h"
namespace Core {
class System;
@@ -53,9 +55,7 @@ struct SinkBuffer {
class SinkStream {
public:
explicit SinkStream(Core::System& system_, StreamType type_) : system{system_}, type{type_} {}
virtual ~SinkStream() {
Unstall();
}
virtual ~SinkStream() {}
/**
* Finalize the sink stream.
@@ -201,14 +201,16 @@ public:
void ProcessAudioOutAndRender(std::span<s16> output_buffer, std::size_t num_frames);
/**
* Stall core processes if the audio thread falls too far behind.
* Get the total number of samples expected to have been played by this stream.
*
* @return The number of samples.
*/
void Stall();
u64 GetExpectedPlayedSampleCount();
/**
* Unstall core processes.
* Waits for free space in the sample ring buffer
*/
void Unstall();
void WaitFreeSpace();
protected:
/// Core system
@@ -237,12 +239,21 @@ private:
std::atomic<u32> queued_buffers{};
/// The ring size for audio out buffers (usually 4, rarely 2 or 8)
u32 max_queue_size{};
/// Locks access to sample count tracking info
std::mutex sample_count_lock;
/// Minimum number of total samples that have been played since the last callback
u64 min_played_sample_count{};
/// Maximum number of total samples that can be played since the last callback
u64 max_played_sample_count{};
/// The time the two above tracking variables were last written to
std::chrono::nanoseconds last_sample_count_update_time{};
/// Set by the audio render/in/out system which uses this stream
f32 system_volume{1.0f};
/// Set via IAudioDevice service calls
f32 device_volume{1.0f};
std::mutex stall_guard;
std::unique_lock<std::mutex> stalled_lock;
/// Signalled when ring buffer entries are consumed
std::condition_variable release_cv;
std::mutex release_mutex;
};
using SinkStreamPtr = std::unique_ptr<SinkStream>;
+4
View File
@@ -38,6 +38,7 @@ add_library(common STATIC
common_precompiled_headers.h
common_types.h
concepts.h
container_hash.h
demangle.cpp
demangle.h
div_ceil.h
@@ -132,6 +133,7 @@ add_library(common STATIC
time_zone.h
tiny_mt.h
tree.h
typed_address.h
uint128.h
unique_function.h
uuid.cpp
@@ -158,6 +160,8 @@ if(ARCHITECTURE_x86_64)
PRIVATE
x64/cpu_detect.cpp
x64/cpu_detect.h
x64/cpu_wait.cpp
x64/cpu_wait.h
x64/native_clock.cpp
x64/native_clock.h
x64/xbyak_abi.h
+1 -1
View File
@@ -66,7 +66,7 @@ public:
* @param description The room description
* @param port The port of the room
* @param net_version The version of the libNetwork that gets used
* @param has_password True if the room is passowrd protected
* @param has_password True if the room is password protected
* @param preferred_game The preferred game of the room
* @param preferred_game_id The title id of the preferred game
*/
+211 -120
View File
@@ -1,158 +1,249 @@
// SPDX-FileCopyrightText: Copyright (c) 2020 Erik Rigtorp <erik@rigtorp.se>
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <bit>
#include <condition_variable>
#include <memory>
#include <cstddef>
#include <mutex>
#include <new>
#include <stop_token>
#include <type_traits>
#include <utility>
#include "common/polyfill_thread.h"
namespace Common {
#if defined(__cpp_lib_hardware_interference_size)
constexpr size_t hardware_interference_size = std::hardware_destructive_interference_size;
#else
constexpr size_t hardware_interference_size = 64;
#endif
namespace detail {
constexpr size_t DefaultCapacity = 0x1000;
} // namespace detail
template <typename T, size_t Capacity = detail::DefaultCapacity>
class SPSCQueue {
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two.");
template <typename T, size_t capacity = 0x400>
class MPSCQueue {
public:
explicit MPSCQueue() : allocator{std::allocator<Slot<T>>()} {
// Allocate one extra slot to prevent false sharing on the last slot
slots = allocator.allocate(capacity + 1);
// Allocators are not required to honor alignment for over-aligned types
// (see http://eel.is/c++draft/allocator.requirements#10) so we verify
// alignment here
if (reinterpret_cast<uintptr_t>(slots) % alignof(Slot<T>) != 0) {
allocator.deallocate(slots, capacity + 1);
throw std::bad_alloc();
}
for (size_t i = 0; i < capacity; ++i) {
std::construct_at(&slots[i]);
}
static_assert(std::has_single_bit(capacity), "capacity must be an integer power of 2");
static_assert(alignof(Slot<T>) == hardware_interference_size,
"Slot must be aligned to cache line boundary to prevent false sharing");
static_assert(sizeof(Slot<T>) % hardware_interference_size == 0,
"Slot size must be a multiple of cache line size to prevent "
"false sharing between adjacent slots");
static_assert(sizeof(MPSCQueue) % hardware_interference_size == 0,
"Queue size must be a multiple of cache line size to "
"prevent false sharing between adjacent queues");
template <typename... Args>
bool TryEmplace(Args&&... args) {
return Emplace<PushMode::Try>(std::forward<Args>(args)...);
}
~MPSCQueue() noexcept {
for (size_t i = 0; i < capacity; ++i) {
std::destroy_at(&slots[i]);
}
allocator.deallocate(slots, capacity + 1);
template <typename... Args>
void EmplaceWait(Args&&... args) {
Emplace<PushMode::Wait>(std::forward<Args>(args)...);
}
// The queue must be both non-copyable and non-movable
MPSCQueue(const MPSCQueue&) = delete;
MPSCQueue& operator=(const MPSCQueue&) = delete;
MPSCQueue(MPSCQueue&&) = delete;
MPSCQueue& operator=(MPSCQueue&&) = delete;
void Push(const T& v) noexcept {
static_assert(std::is_nothrow_copy_constructible_v<T>,
"T must be nothrow copy constructible");
emplace(v);
bool TryPop(T& t) {
return Pop<PopMode::Try>(t);
}
template <typename P, typename = std::enable_if_t<std::is_nothrow_constructible_v<T, P&&>>>
void Push(P&& v) noexcept {
emplace(std::forward<P>(v));
void PopWait(T& t) {
Pop<PopMode::Wait>(t);
}
void Pop(T& v, std::stop_token stop) noexcept {
auto const tail = tail_.fetch_add(1);
auto& slot = slots[idx(tail)];
if (!slot.turn.test()) {
std::unique_lock lock{cv_mutex};
cv.wait(lock, stop, [&slot] { return slot.turn.test(); });
}
v = slot.move();
slot.destroy();
slot.turn.clear();
slot.turn.notify_one();
void PopWait(T& t, std::stop_token stop_token) {
Pop<PopMode::WaitWithStopToken>(t, stop_token);
}
T PopWait() {
T t;
Pop<PopMode::Wait>(t);
return t;
}
T PopWait(std::stop_token stop_token) {
T t;
Pop<PopMode::WaitWithStopToken>(t, stop_token);
return t;
}
private:
template <typename U = T>
struct Slot {
~Slot() noexcept {
if (turn.test()) {
destroy();
}
}
template <typename... Args>
void construct(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible_v<U, Args&&...>,
"T must be nothrow constructible with Args&&...");
std::construct_at(reinterpret_cast<U*>(&storage), std::forward<Args>(args)...);
}
void destroy() noexcept {
static_assert(std::is_nothrow_destructible_v<U>, "T must be nothrow destructible");
std::destroy_at(reinterpret_cast<U*>(&storage));
}
U&& move() noexcept {
return reinterpret_cast<U&&>(storage);
}
// Align to avoid false sharing between adjacent slots
alignas(hardware_interference_size) std::atomic_flag turn{};
struct aligned_store {
struct type {
alignas(U) unsigned char data[sizeof(U)];
};
};
typename aligned_store::type storage;
enum class PushMode {
Try,
Wait,
Count,
};
enum class PopMode {
Try,
Wait,
WaitWithStopToken,
Count,
};
template <PushMode Mode, typename... Args>
bool Emplace(Args&&... args) {
const size_t write_index = m_write_index.load(std::memory_order::relaxed);
if constexpr (Mode == PushMode::Try) {
// Check if we have free slots to write to.
if ((write_index - m_read_index.load(std::memory_order::acquire)) == Capacity) {
return false;
}
} else if constexpr (Mode == PushMode::Wait) {
// Wait until we have free slots to write to.
std::unique_lock lock{producer_cv_mutex};
producer_cv.wait(lock, [this, write_index] {
return (write_index - m_read_index.load(std::memory_order::acquire)) < Capacity;
});
} else {
static_assert(Mode < PushMode::Count, "Invalid PushMode.");
}
// Determine the position to write to.
const size_t pos = write_index % Capacity;
// Emplace into the queue.
std::construct_at(std::addressof(m_data[pos]), std::forward<Args>(args)...);
// Increment the write index.
++m_write_index;
// Notify the consumer that we have pushed into the queue.
std::scoped_lock lock{consumer_cv_mutex};
consumer_cv.notify_one();
return true;
}
template <PopMode Mode>
bool Pop(T& t, [[maybe_unused]] std::stop_token stop_token = {}) {
const size_t read_index = m_read_index.load(std::memory_order::relaxed);
if constexpr (Mode == PopMode::Try) {
// Check if the queue is empty.
if (read_index == m_write_index.load(std::memory_order::acquire)) {
return false;
}
} else if constexpr (Mode == PopMode::Wait) {
// Wait until the queue is not empty.
std::unique_lock lock{consumer_cv_mutex};
consumer_cv.wait(lock, [this, read_index] {
return read_index != m_write_index.load(std::memory_order::acquire);
});
} else if constexpr (Mode == PopMode::WaitWithStopToken) {
// Wait until the queue is not empty.
std::unique_lock lock{consumer_cv_mutex};
Common::CondvarWait(consumer_cv, lock, stop_token, [this, read_index] {
return read_index != m_write_index.load(std::memory_order::acquire);
});
if (stop_token.stop_requested()) {
return false;
}
} else {
static_assert(Mode < PopMode::Count, "Invalid PopMode.");
}
// Determine the position to read from.
const size_t pos = read_index % Capacity;
// Pop the data off the queue, moving it.
t = std::move(m_data[pos]);
// Increment the read index.
++m_read_index;
// Notify the producer that we have popped off the queue.
std::scoped_lock lock{producer_cv_mutex};
producer_cv.notify_one();
return true;
}
alignas(128) std::atomic_size_t m_read_index{0};
alignas(128) std::atomic_size_t m_write_index{0};
std::array<T, Capacity> m_data;
std::condition_variable_any producer_cv;
std::mutex producer_cv_mutex;
std::condition_variable_any consumer_cv;
std::mutex consumer_cv_mutex;
};
template <typename T, size_t Capacity = detail::DefaultCapacity>
class MPSCQueue {
public:
template <typename... Args>
void emplace(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible_v<T, Args&&...>,
"T must be nothrow constructible with Args&&...");
auto const head = head_.fetch_add(1);
auto& slot = slots[idx(head)];
slot.turn.wait(true);
slot.construct(std::forward<Args>(args)...);
slot.turn.test_and_set();
cv.notify_one();
bool TryEmplace(Args&&... args) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryEmplace(std::forward<Args>(args)...);
}
constexpr size_t idx(size_t i) const noexcept {
return i & mask;
template <typename... Args>
void EmplaceWait(Args&&... args) {
std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceWait(std::forward<Args>(args)...);
}
static constexpr size_t mask = capacity - 1;
bool TryPop(T& t) {
return spsc_queue.TryPop(t);
}
// Align to avoid false sharing between head_ and tail_
alignas(hardware_interference_size) std::atomic<size_t> head_{0};
alignas(hardware_interference_size) std::atomic<size_t> tail_{0};
void PopWait(T& t) {
spsc_queue.PopWait(t);
}
std::mutex cv_mutex;
std::condition_variable_any cv;
void PopWait(T& t, std::stop_token stop_token) {
spsc_queue.PopWait(t, stop_token);
}
Slot<T>* slots;
[[no_unique_address]] std::allocator<Slot<T>> allocator;
T PopWait() {
return spsc_queue.PopWait();
}
static_assert(std::is_nothrow_copy_assignable_v<T> || std::is_nothrow_move_assignable_v<T>,
"T must be nothrow copy or move assignable");
T PopWait(std::stop_token stop_token) {
return spsc_queue.PopWait(stop_token);
}
static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible");
private:
SPSCQueue<T, Capacity> spsc_queue;
std::mutex write_mutex;
};
template <typename T, size_t Capacity = detail::DefaultCapacity>
class MPMCQueue {
public:
template <typename... Args>
bool TryEmplace(Args&&... args) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryEmplace(std::forward<Args>(args)...);
}
template <typename... Args>
void EmplaceWait(Args&&... args) {
std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceWait(std::forward<Args>(args)...);
}
bool TryPop(T& t) {
std::scoped_lock lock{read_mutex};
return spsc_queue.TryPop(t);
}
void PopWait(T& t) {
std::scoped_lock lock{read_mutex};
spsc_queue.PopWait(t);
}
void PopWait(T& t, std::stop_token stop_token) {
std::scoped_lock lock{read_mutex};
spsc_queue.PopWait(t, stop_token);
}
T PopWait() {
std::scoped_lock lock{read_mutex};
return spsc_queue.PopWait();
}
T PopWait(std::stop_token stop_token) {
std::scoped_lock lock{read_mutex};
return spsc_queue.PopWait(stop_token);
}
private:
SPSCQueue<T, Capacity> spsc_queue;
std::mutex write_mutex;
std::mutex read_mutex;
};
} // namespace Common
+92
View File
@@ -0,0 +1,92 @@
// SPDX-FileCopyrightText: 2005-2014 Daniel James
// SPDX-FileCopyrightText: 2016 Austin Appleby
// SPDX-License-Identifier: BSL-1.0
#include <array>
#include <climits>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <vector>
namespace Common {
namespace detail {
template <typename T>
requires std::is_unsigned_v<T>
inline std::size_t HashValue(T val) {
const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits;
const unsigned int length =
(std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits);
std::size_t seed = 0;
for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits) {
seed ^= static_cast<size_t>(val >> i) + (seed << 6) + (seed >> 2);
}
seed ^= static_cast<size_t>(val) + (seed << 6) + (seed >> 2);
return seed;
}
template <size_t Bits>
struct HashCombineImpl {
template <typename T>
static inline T fn(T seed, T value) {
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
template <>
struct HashCombineImpl<64> {
static inline std::uint64_t fn(std::uint64_t h, std::uint64_t k) {
const std::uint64_t m = (std::uint64_t(0xc6a4a793) << 32) + 0x5bd1e995;
const int r = 47;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
// Completely arbitrary number, to prevent 0's
// from hashing to 0.
h += 0xe6546b64;
return h;
}
};
} // namespace detail
template <typename T>
inline void HashCombine(std::size_t& seed, const T& v) {
seed = detail::HashCombineImpl<sizeof(std::size_t) * CHAR_BIT>::fn(seed, detail::HashValue(v));
}
template <typename It>
inline std::size_t HashRange(It first, It last) {
std::size_t seed = 0;
for (; first != last; ++first) {
HashCombine<typename std::iterator_traits<It>::value_type>(seed, *first);
}
return seed;
}
template <typename T, size_t Size>
std::size_t HashValue(const std::array<T, Size>& v) {
return HashRange(v.cbegin(), v.cend());
}
template <typename T, typename Allocator>
std::size_t HashValue(const std::vector<T, Allocator>& v) {
return HashRange(v.cbegin(), v.cend());
}
} // namespace Common
+1 -1
View File
@@ -90,7 +90,7 @@ Fiber::~Fiber() {
}
void Fiber::Exit() {
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
ASSERT_MSG(impl->is_thread_fiber, "Exiting non main thread fiber");
if (!impl->is_thread_fiber) {
return;
}
+1 -1
View File
@@ -22,7 +22,7 @@ class FixedPoint;
namespace detail {
// helper templates to make magic with types :)
// these allow us to determine resonable types from
// these allow us to determine reasonable types from
// a desired size, they also let us infer the next largest type
// from a type which is nice for the division op
template <size_t T>
+2 -2
View File
@@ -322,7 +322,7 @@ private:
}
/// Return true when a given memory region is a "nieche" and the placeholders don't have to be
/// splitted.
/// split.
bool IsNiechePlaceholder(size_t virtual_offset, size_t length) const {
const auto it = placeholders.upper_bound({virtual_offset, virtual_offset + length});
if (it != placeholders.end() && it->lower() == virtual_offset + length) {
@@ -484,7 +484,7 @@ class HostMemory::Impl {
public:
explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) {
// This is just a place holder.
// Please implement fastmem in a propper way on your platform.
// Please implement fastmem in a proper way on your platform.
throw std::bad_alloc{};
}
+4 -4
View File
@@ -15,7 +15,7 @@
namespace Common::Input {
// Type of data that is expected to recieve or send
// Type of data that is expected to receive or send
enum class InputType {
None,
Battery,
@@ -103,7 +103,7 @@ enum class VibrationAmplificationType {
struct AnalogProperties {
// Anything below this value will be detected as zero
float deadzone{};
// Anyting above this values will be detected as one
// Anything above this values will be detected as one
float range{1.0f};
// Minimum value to be detected as active
float threshold{0.5f};
@@ -209,7 +209,7 @@ struct LedStatus {
bool led_4{};
};
// Raw data fom camera
// Raw data from camera
struct CameraStatus {
CameraFormat format{CameraFormat::None};
std::vector<u8> data{};
@@ -428,7 +428,7 @@ inline void UnregisterOutputFactory(const std::string& name) {
}
/**
* Create an input device from given paramters.
* Create an input device from given parameters.
* @tparam InputDeviceType the type of input devices to create
* @param params a serialized ParamPackage string that contains all parameters for creating the
* device
+631
View File
@@ -0,0 +1,631 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_funcs.h"
#include "common/parent_of_member.h"
namespace Common {
// Forward declare implementation class for Node.
namespace impl {
class IntrusiveListImpl;
}
class IntrusiveListNode {
YUZU_NON_COPYABLE(IntrusiveListNode);
private:
friend class impl::IntrusiveListImpl;
IntrusiveListNode* m_prev;
IntrusiveListNode* m_next;
public:
constexpr IntrusiveListNode() : m_prev(this), m_next(this) {}
constexpr bool IsLinked() const {
return m_next != this;
}
private:
constexpr void LinkPrev(IntrusiveListNode* node) {
// We can't link an already linked node.
ASSERT(!node->IsLinked());
this->SplicePrev(node, node);
}
constexpr void SplicePrev(IntrusiveListNode* first, IntrusiveListNode* last) {
// Splice a range into the list.
auto last_prev = last->m_prev;
first->m_prev = m_prev;
last_prev->m_next = this;
m_prev->m_next = first;
m_prev = last_prev;
}
constexpr void LinkNext(IntrusiveListNode* node) {
// We can't link an already linked node.
ASSERT(!node->IsLinked());
return this->SpliceNext(node, node);
}
constexpr void SpliceNext(IntrusiveListNode* first, IntrusiveListNode* last) {
// Splice a range into the list.
auto last_prev = last->m_prev;
first->m_prev = this;
last_prev->m_next = m_next;
m_next->m_prev = last_prev;
m_next = first;
}
constexpr void Unlink() {
this->Unlink(m_next);
}
constexpr void Unlink(IntrusiveListNode* last) {
// Unlink a node from a next node.
auto last_prev = last->m_prev;
m_prev->m_next = last;
last->m_prev = m_prev;
last_prev->m_next = this;
m_prev = last_prev;
}
constexpr IntrusiveListNode* GetPrev() {
return m_prev;
}
constexpr const IntrusiveListNode* GetPrev() const {
return m_prev;
}
constexpr IntrusiveListNode* GetNext() {
return m_next;
}
constexpr const IntrusiveListNode* GetNext() const {
return m_next;
}
};
// DEPRECATED: static_assert(std::is_literal_type<IntrusiveListNode>::value);
namespace impl {
class IntrusiveListImpl {
YUZU_NON_COPYABLE(IntrusiveListImpl);
private:
IntrusiveListNode m_root_node;
public:
template <bool Const>
class Iterator;
using value_type = IntrusiveListNode;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
template <bool Const>
class Iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveListImpl::value_type;
using difference_type = typename IntrusiveListImpl::difference_type;
using pointer =
std::conditional_t<Const, IntrusiveListImpl::const_pointer, IntrusiveListImpl::pointer>;
using reference = std::conditional_t<Const, IntrusiveListImpl::const_reference,
IntrusiveListImpl::reference>;
private:
pointer m_node;
public:
constexpr explicit Iterator(pointer n) : m_node(n) {}
constexpr bool operator==(const Iterator& rhs) const {
return m_node == rhs.m_node;
}
constexpr pointer operator->() const {
return m_node;
}
constexpr reference operator*() const {
return *m_node;
}
constexpr Iterator& operator++() {
m_node = m_node->m_next;
return *this;
}
constexpr Iterator& operator--() {
m_node = m_node->m_prev;
return *this;
}
constexpr Iterator operator++(int) {
const Iterator it{*this};
++(*this);
return it;
}
constexpr Iterator operator--(int) {
const Iterator it{*this};
--(*this);
return it;
}
constexpr operator Iterator<true>() const {
return Iterator<true>(m_node);
}
constexpr Iterator<false> GetNonConstIterator() const {
return Iterator<false>(const_cast<IntrusiveListImpl::pointer>(m_node));
}
};
public:
constexpr IntrusiveListImpl() : m_root_node() {}
// Iterator accessors.
constexpr iterator begin() {
return iterator(m_root_node.GetNext());
}
constexpr const_iterator begin() const {
return const_iterator(m_root_node.GetNext());
}
constexpr iterator end() {
return iterator(std::addressof(m_root_node));
}
constexpr const_iterator end() const {
return const_iterator(std::addressof(m_root_node));
}
constexpr iterator iterator_to(reference v) {
// Only allow iterator_to for values in lists.
ASSERT(v.IsLinked());
return iterator(std::addressof(v));
}
constexpr const_iterator iterator_to(const_reference v) const {
// Only allow iterator_to for values in lists.
ASSERT(v.IsLinked());
return const_iterator(std::addressof(v));
}
// Content management.
constexpr bool empty() const {
return !m_root_node.IsLinked();
}
constexpr size_type size() const {
return static_cast<size_type>(std::distance(this->begin(), this->end()));
}
constexpr reference back() {
return *m_root_node.GetPrev();
}
constexpr const_reference back() const {
return *m_root_node.GetPrev();
}
constexpr reference front() {
return *m_root_node.GetNext();
}
constexpr const_reference front() const {
return *m_root_node.GetNext();
}
constexpr void push_back(reference node) {
m_root_node.LinkPrev(std::addressof(node));
}
constexpr void push_front(reference node) {
m_root_node.LinkNext(std::addressof(node));
}
constexpr void pop_back() {
m_root_node.GetPrev()->Unlink();
}
constexpr void pop_front() {
m_root_node.GetNext()->Unlink();
}
constexpr iterator insert(const_iterator pos, reference node) {
pos.GetNonConstIterator()->LinkPrev(std::addressof(node));
return iterator(std::addressof(node));
}
constexpr void splice(const_iterator pos, IntrusiveListImpl& o) {
splice_impl(pos, o.begin(), o.end());
}
constexpr void splice(const_iterator pos, IntrusiveListImpl& o, const_iterator first) {
const_iterator last(first);
std::advance(last, 1);
splice_impl(pos, first, last);
}
constexpr void splice(const_iterator pos, IntrusiveListImpl& o, const_iterator first,
const_iterator last) {
splice_impl(pos, first, last);
}
constexpr iterator erase(const_iterator pos) {
if (pos == this->end()) {
return this->end();
}
iterator it(pos.GetNonConstIterator());
(it++)->Unlink();
return it;
}
constexpr void clear() {
while (!this->empty()) {
this->pop_front();
}
}
private:
constexpr void splice_impl(const_iterator _pos, const_iterator _first, const_iterator _last) {
if (_first == _last) {
return;
}
iterator pos(_pos.GetNonConstIterator());
iterator first(_first.GetNonConstIterator());
iterator last(_last.GetNonConstIterator());
first->Unlink(std::addressof(*last));
pos->SplicePrev(std::addressof(*first), std::addressof(*first));
}
};
} // namespace impl
template <class T, class Traits>
class IntrusiveList {
YUZU_NON_COPYABLE(IntrusiveList);
private:
impl::IntrusiveListImpl m_impl;
public:
template <bool Const>
class Iterator;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
template <bool Const>
class Iterator {
public:
friend class Common::IntrusiveList<T, Traits>;
using ImplIterator =
std::conditional_t<Const, Common::impl::IntrusiveListImpl::const_iterator,
Common::impl::IntrusiveListImpl::iterator>;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveList::value_type;
using difference_type = typename IntrusiveList::difference_type;
using pointer =
std::conditional_t<Const, IntrusiveList::const_pointer, IntrusiveList::pointer>;
using reference =
std::conditional_t<Const, IntrusiveList::const_reference, IntrusiveList::reference>;
private:
ImplIterator m_iterator;
private:
constexpr explicit Iterator(ImplIterator it) : m_iterator(it) {}
constexpr ImplIterator GetImplIterator() const {
return m_iterator;
}
public:
constexpr bool operator==(const Iterator& rhs) const {
return m_iterator == rhs.m_iterator;
}
constexpr pointer operator->() const {
return std::addressof(Traits::GetParent(*m_iterator));
}
constexpr reference operator*() const {
return Traits::GetParent(*m_iterator);
}
constexpr Iterator& operator++() {
++m_iterator;
return *this;
}
constexpr Iterator& operator--() {
--m_iterator;
return *this;
}
constexpr Iterator operator++(int) {
const Iterator it{*this};
++m_iterator;
return it;
}
constexpr Iterator operator--(int) {
const Iterator it{*this};
--m_iterator;
return it;
}
constexpr operator Iterator<true>() const {
return Iterator<true>(m_iterator);
}
};
private:
static constexpr IntrusiveListNode& GetNode(reference ref) {
return Traits::GetNode(ref);
}
static constexpr IntrusiveListNode const& GetNode(const_reference ref) {
return Traits::GetNode(ref);
}
static constexpr reference GetParent(IntrusiveListNode& node) {
return Traits::GetParent(node);
}
static constexpr const_reference GetParent(IntrusiveListNode const& node) {
return Traits::GetParent(node);
}
public:
constexpr IntrusiveList() : m_impl() {}
// Iterator accessors.
constexpr iterator begin() {
return iterator(m_impl.begin());
}
constexpr const_iterator begin() const {
return const_iterator(m_impl.begin());
}
constexpr iterator end() {
return iterator(m_impl.end());
}
constexpr const_iterator end() const {
return const_iterator(m_impl.end());
}
constexpr const_iterator cbegin() const {
return this->begin();
}
constexpr const_iterator cend() const {
return this->end();
}
constexpr reverse_iterator rbegin() {
return reverse_iterator(this->end());
}
constexpr const_reverse_iterator rbegin() const {
return const_reverse_iterator(this->end());
}
constexpr reverse_iterator rend() {
return reverse_iterator(this->begin());
}
constexpr const_reverse_iterator rend() const {
return const_reverse_iterator(this->begin());
}
constexpr const_reverse_iterator crbegin() const {
return this->rbegin();
}
constexpr const_reverse_iterator crend() const {
return this->rend();
}
constexpr iterator iterator_to(reference v) {
return iterator(m_impl.iterator_to(GetNode(v)));
}
constexpr const_iterator iterator_to(const_reference v) const {
return const_iterator(m_impl.iterator_to(GetNode(v)));
}
// Content management.
constexpr bool empty() const {
return m_impl.empty();
}
constexpr size_type size() const {
return m_impl.size();
}
constexpr reference back() {
return GetParent(m_impl.back());
}
constexpr const_reference back() const {
return GetParent(m_impl.back());
}
constexpr reference front() {
return GetParent(m_impl.front());
}
constexpr const_reference front() const {
return GetParent(m_impl.front());
}
constexpr void push_back(reference ref) {
m_impl.push_back(GetNode(ref));
}
constexpr void push_front(reference ref) {
m_impl.push_front(GetNode(ref));
}
constexpr void pop_back() {
m_impl.pop_back();
}
constexpr void pop_front() {
m_impl.pop_front();
}
constexpr iterator insert(const_iterator pos, reference ref) {
return iterator(m_impl.insert(pos.GetImplIterator(), GetNode(ref)));
}
constexpr void splice(const_iterator pos, IntrusiveList& o) {
m_impl.splice(pos.GetImplIterator(), o.m_impl);
}
constexpr void splice(const_iterator pos, IntrusiveList& o, const_iterator first) {
m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator());
}
constexpr void splice(const_iterator pos, IntrusiveList& o, const_iterator first,
const_iterator last) {
m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator(),
last.GetImplIterator());
}
constexpr iterator erase(const_iterator pos) {
return iterator(m_impl.erase(pos.GetImplIterator()));
}
constexpr void clear() {
m_impl.clear();
}
};
template <auto T, class Derived = Common::impl::GetParentType<T>>
class IntrusiveListMemberTraits;
template <class Parent, IntrusiveListNode Parent::*Member, class Derived>
class IntrusiveListMemberTraits<Member, Derived> {
public:
using ListType = IntrusiveList<Derived, IntrusiveListMemberTraits>;
private:
friend class IntrusiveList<Derived, IntrusiveListMemberTraits>;
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
return parent.*Member;
}
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
return parent.*Member;
}
static Derived& GetParent(IntrusiveListNode& node) {
return Common::GetParentReference<Member, Derived>(std::addressof(node));
}
static Derived const& GetParent(IntrusiveListNode const& node) {
return Common::GetParentReference<Member, Derived>(std::addressof(node));
}
};
template <auto T, class Derived = Common::impl::GetParentType<T>>
class IntrusiveListMemberTraitsByNonConstexprOffsetOf;
template <class Parent, IntrusiveListNode Parent::*Member, class Derived>
class IntrusiveListMemberTraitsByNonConstexprOffsetOf<Member, Derived> {
public:
using ListType = IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>;
private:
friend class IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>;
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
return parent.*Member;
}
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
return parent.*Member;
}
static Derived& GetParent(IntrusiveListNode& node) {
return *reinterpret_cast<Derived*>(reinterpret_cast<char*>(std::addressof(node)) -
GetOffset());
}
static Derived const& GetParent(IntrusiveListNode const& node) {
return *reinterpret_cast<const Derived*>(
reinterpret_cast<const char*>(std::addressof(node)) - GetOffset());
}
static uintptr_t GetOffset() {
return reinterpret_cast<uintptr_t>(std::addressof(reinterpret_cast<Derived*>(0)->*Member));
}
};
template <class Derived>
class IntrusiveListBaseNode : public IntrusiveListNode {};
template <class Derived>
class IntrusiveListBaseTraits {
public:
using ListType = IntrusiveList<Derived, IntrusiveListBaseTraits>;
private:
friend class IntrusiveList<Derived, IntrusiveListBaseTraits>;
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
return static_cast<IntrusiveListNode&>(
static_cast<IntrusiveListBaseNode<Derived>&>(parent));
}
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
return static_cast<const IntrusiveListNode&>(
static_cast<const IntrusiveListBaseNode<Derived>&>(parent));
}
static constexpr Derived& GetParent(IntrusiveListNode& node) {
return static_cast<Derived&>(static_cast<IntrusiveListBaseNode<Derived>&>(node));
}
static constexpr Derived const& GetParent(IntrusiveListNode const& node) {
return static_cast<const Derived&>(
static_cast<const IntrusiveListBaseNode<Derived>&>(node));
}
};
} // namespace Common
-8
View File
@@ -96,10 +96,6 @@ public:
return m_node == rhs.m_node;
}
constexpr bool operator!=(const Iterator& rhs) const {
return !(*this == rhs);
}
constexpr pointer operator->() const {
return m_node;
}
@@ -324,10 +320,6 @@ public:
return m_impl == rhs.m_impl;
}
constexpr bool operator!=(const Iterator& rhs) const {
return !(*this == rhs);
}
constexpr pointer operator->() const {
return Traits::GetParent(std::addressof(*m_impl));
}
+8 -8
View File
@@ -28,7 +28,7 @@
#ifdef _WIN32
#include "common/string_util.h"
#endif
#include "common/threadsafe_queue.h"
#include "common/bounded_threadsafe_queue.h"
namespace Common::Log {
@@ -204,11 +204,11 @@ public:
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, std::string&& message) {
if (!filter.CheckMessage(log_class, log_level))
if (!filter.CheckMessage(log_class, log_level)) {
return;
const Entry& entry =
CreateEntry(log_class, log_level, filename, line_num, function, std::move(message));
message_queue.Push(entry);
}
message_queue.EmplaceWait(
CreateEntry(log_class, log_level, filename, line_num, function, std::move(message)));
}
private:
@@ -225,7 +225,7 @@ private:
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
};
while (!stop_token.stop_requested()) {
entry = message_queue.PopWait(stop_token);
message_queue.PopWait(entry, stop_token);
if (entry.filename != nullptr) {
write_logs();
}
@@ -233,7 +233,7 @@ private:
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
// case where a system is repeatedly spamming logs even on close.
int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100;
while (max_logs_to_write-- && message_queue.Pop(entry)) {
while (max_logs_to_write-- && message_queue.TryPop(entry)) {
write_logs();
}
});
@@ -273,7 +273,7 @@ private:
ColorConsoleBackend color_console_backend{};
FileBackend file_backend;
MPSCQueue<Entry, true> message_queue{};
MPSCQueue<Entry> message_queue{};
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
std::jthread backend_thread;
};
+3 -3
View File
@@ -38,12 +38,12 @@ public:
Map(address, address_end, null_value);
}
[[nodiscard]] size_t GetContinousSizeFrom(KeyTBase address) const {
[[nodiscard]] size_t GetContinuousSizeFrom(KeyTBase address) const {
const KeyT new_address = static_cast<KeyT>(address);
if (new_address < 0) {
return 0;
}
return ContinousSizeInternal(new_address);
return ContinuousSizeInternal(new_address);
}
[[nodiscard]] ValueT GetValueAt(KeyT address) const {
@@ -59,7 +59,7 @@ private:
using IteratorType = typename MapType::iterator;
using ConstIteratorType = typename MapType::const_iterator;
size_t ContinousSizeInternal(KeyT address) const {
size_t ContinuousSizeInternal(KeyT address) const {
const auto it = GetFirstElementBeforeOrOn(address);
if (it == container.end() || it->second == null_value) {
return 0;
+3 -1
View File
@@ -45,6 +45,7 @@ void LogSettings() {
log_setting("System_LanguageIndex", values.language_index.GetValue());
log_setting("System_RegionIndex", values.region_index.GetValue());
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
log_setting("System_UnsafeMemoryLayout", values.use_unsafe_extended_memory_layout.GetValue());
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
@@ -191,7 +192,7 @@ void RestoreGlobalState(bool is_powered_on) {
// Core
values.use_multi_core.SetGlobal(true);
values.use_extended_memory_layout.SetGlobal(true);
values.use_unsafe_extended_memory_layout.SetGlobal(true);
// CPU
values.cpu_accuracy.SetGlobal(true);
@@ -205,6 +206,7 @@ void RestoreGlobalState(bool is_powered_on) {
// Renderer
values.fsr_sharpening_slider.SetGlobal(true);
values.renderer_backend.SetGlobal(true);
values.async_presentation.SetGlobal(true);
values.renderer_force_max_clock.SetGlobal(true);
values.vulkan_device.SetGlobal(true);
values.fullscreen_mode.SetGlobal(true);
+3 -1
View File
@@ -388,7 +388,8 @@ struct Values {
// Core
SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
SwitchableSetting<bool> use_unsafe_extended_memory_layout{false,
"use_unsafe_extended_memory_layout"};
// Cpu
SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
@@ -422,6 +423,7 @@ struct Values {
// Renderer
SwitchableSetting<RendererBackend, true> renderer_backend{
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};
SwitchableSetting<bool> async_presentation{false, "async_presentation"};
SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"};
Setting<bool> renderer_debug{false, "debug"};
Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
+25
View File
@@ -23,6 +23,19 @@ static s64 WindowsQueryPerformanceCounter() {
QueryPerformanceCounter(&counter);
return counter.QuadPart;
}
static s64 GetSystemTimeNS() {
// GetSystemTimePreciseAsFileTime returns the file time in 100ns units.
static constexpr s64 Multiplier = 100;
// Convert Windows epoch to Unix epoch.
static constexpr s64 WindowsEpochToUnixEpochNS = 0x19DB1DED53E8000LL;
FILETIME filetime;
GetSystemTimePreciseAsFileTime(&filetime);
return Multiplier * ((static_cast<s64>(filetime.dwHighDateTime) << 32) +
static_cast<s64>(filetime.dwLowDateTime)) -
WindowsEpochToUnixEpochNS;
}
#endif
SteadyClock::time_point SteadyClock::Now() noexcept {
@@ -53,4 +66,16 @@ SteadyClock::time_point SteadyClock::Now() noexcept {
#endif
}
RealTimeClock::time_point RealTimeClock::Now() noexcept {
#if defined(_WIN32)
return time_point{duration{GetSystemTimeNS()}};
#elif defined(__APPLE__)
return time_point{duration{clock_gettime_nsec_np(CLOCK_REALTIME)}};
#else
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
#endif
}
}; // namespace Common
+11
View File
@@ -20,4 +20,15 @@ struct SteadyClock {
[[nodiscard]] static time_point Now() noexcept;
};
struct RealTimeClock {
using rep = s64;
using period = std::nano;
using duration = std::chrono::nanoseconds;
using time_point = std::chrono::time_point<RealTimeClock>;
static constexpr bool is_steady = false;
[[nodiscard]] static time_point Now() noexcept;
};
} // namespace Common
+7 -7
View File
@@ -125,18 +125,18 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
return result;
}
std::string UTF16ToUTF8(const std::u16string& input) {
std::string UTF16ToUTF8(std::u16string_view input) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.to_bytes(input);
return convert.to_bytes(input.data(), input.data() + input.size());
}
std::u16string UTF8ToUTF16(const std::string& input) {
std::u16string UTF8ToUTF16(std::string_view input) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.from_bytes(input);
return convert.from_bytes(input.data(), input.data() + input.size());
}
#ifdef _WIN32
static std::wstring CPToUTF16(u32 code_page, const std::string& input) {
static std::wstring CPToUTF16(u32 code_page, std::string_view input) {
const auto size =
MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
@@ -154,7 +154,7 @@ static std::wstring CPToUTF16(u32 code_page, const std::string& input) {
return output;
}
std::string UTF16ToUTF8(const std::wstring& input) {
std::string UTF16ToUTF8(std::wstring_view input) {
const auto size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),
nullptr, 0, nullptr, nullptr);
if (size == 0) {
@@ -172,7 +172,7 @@ std::string UTF16ToUTF8(const std::wstring& input) {
return output;
}
std::wstring UTF8ToUTF16W(const std::string& input) {
std::wstring UTF8ToUTF16W(std::string_view input) {
return CPToUTF16(CP_UTF8, input);
}
+4 -4
View File
@@ -36,12 +36,12 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
const std::string& dest);
[[nodiscard]] std::string UTF16ToUTF8(const std::u16string& input);
[[nodiscard]] std::u16string UTF8ToUTF16(const std::string& input);
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
#ifdef _WIN32
[[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);
[[nodiscard]] std::wstring UTF8ToUTF16W(const std::string& str);
[[nodiscard]] std::string UTF16ToUTF8(std::wstring_view input);
[[nodiscard]] std::wstring UTF8ToUTF16W(std::string_view str);
#endif
+6 -6
View File
@@ -229,7 +229,7 @@ public:
value = swap(swap() - 1);
return old;
}
// Comparaison
// Comparison
// v == i
bool operator==(const swapped_t& i) const {
return swap() == i.swap();
@@ -368,7 +368,7 @@ public:
// Member
/** todo **/
// Arithmetics
// Arithmetic
template <typename S, typename T2, typename F2>
friend S operator+(const S& p, const swapped_t v);
@@ -384,7 +384,7 @@ public:
template <typename S, typename T2, typename F2>
friend S operator%(const S& p, const swapped_t v);
// Arithmetics + assignments
// Arithmetic + assignments
template <typename S, typename T2, typename F2>
friend S operator+=(const S& p, const swapped_t v);
@@ -415,7 +415,7 @@ public:
friend bool operator==(const S& p, const swapped_t v);
};
// Arithmetics
// Arithmetic
template <typename S, typename T, typename F>
S operator+(const S& i, const swap_struct_t<T, F> v) {
return i + v.swap();
@@ -441,7 +441,7 @@ S operator%(const S& i, const swap_struct_t<T, F> v) {
return i % v.swap();
}
// Arithmetics + assignments
// Arithmetic + assignments
template <typename S, typename T, typename F>
S& operator+=(S& i, const swap_struct_t<T, F> v) {
i += v.swap();
@@ -465,7 +465,7 @@ S operator&(const swap_struct_t<T, F> v, const S& i) {
return static_cast<S>(v.swap() & i);
}
// Comparaison
// Comparison
template <typename S, typename T, typename F>
bool operator<(const S& p, const swap_struct_t<T, F> v) {
return p < v.swap();
+1
View File
@@ -97,6 +97,7 @@ void AppendCPUInfo(FieldCollection& fc) {
add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq);
add_field("CPU_Extension_x64_POPCNT", caps.popcnt);
add_field("CPU_Extension_x64_SHA", caps.sha);
add_field("CPU_Extension_x64_WAITPKG", caps.waitpkg);
#else
fc.AddField(FieldType::UserSystem, "CPU_Model", "Other");
#endif
+315
View File
@@ -0,0 +1,315 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <compare>
#include <type_traits>
#include <fmt/format.h>
#include "common/common_types.h"
namespace Common {
template <bool Virtual, typename T>
class TypedAddress {
public:
// Constructors.
constexpr inline TypedAddress() : m_address(0) {}
constexpr inline TypedAddress(uint64_t a) : m_address(a) {}
template <typename U>
constexpr inline explicit TypedAddress(const U* ptr)
: m_address(reinterpret_cast<uint64_t>(ptr)) {}
// Copy constructor.
constexpr inline TypedAddress(const TypedAddress& rhs) = default;
// Assignment operator.
constexpr inline TypedAddress& operator=(const TypedAddress& rhs) = default;
// Arithmetic operators.
template <typename I>
constexpr inline TypedAddress operator+(I rhs) const {
static_assert(std::is_integral_v<I>);
return m_address + rhs;
}
constexpr inline TypedAddress operator+(TypedAddress rhs) const {
return m_address + rhs.m_address;
}
constexpr inline TypedAddress operator++() {
return ++m_address;
}
constexpr inline TypedAddress operator++(int) {
return m_address++;
}
template <typename I>
constexpr inline TypedAddress operator-(I rhs) const {
static_assert(std::is_integral_v<I>);
return m_address - rhs;
}
constexpr inline ptrdiff_t operator-(TypedAddress rhs) const {
return m_address - rhs.m_address;
}
constexpr inline TypedAddress operator--() {
return --m_address;
}
constexpr inline TypedAddress operator--(int) {
return m_address--;
}
template <typename I>
constexpr inline TypedAddress operator+=(I rhs) {
static_assert(std::is_integral_v<I>);
m_address += rhs;
return *this;
}
template <typename I>
constexpr inline TypedAddress operator-=(I rhs) {
static_assert(std::is_integral_v<I>);
m_address -= rhs;
return *this;
}
// Logical operators.
constexpr inline uint64_t operator&(uint64_t mask) const {
return m_address & mask;
}
constexpr inline uint64_t operator|(uint64_t mask) const {
return m_address | mask;
}
template <typename I>
constexpr inline TypedAddress operator|=(I rhs) {
static_assert(std::is_integral_v<I>);
m_address |= rhs;
return *this;
}
constexpr inline uint64_t operator<<(int shift) const {
return m_address << shift;
}
constexpr inline uint64_t operator>>(int shift) const {
return m_address >> shift;
}
template <typename U>
constexpr inline size_t operator/(U size) const {
return m_address / size;
}
constexpr explicit operator bool() const {
return m_address != 0;
}
// constexpr inline uint64_t operator%(U align) const { return m_address % align; }
// Comparison operators.
constexpr bool operator==(const TypedAddress&) const = default;
constexpr auto operator<=>(const TypedAddress&) const = default;
// For convenience, also define comparison operators versus uint64_t.
constexpr inline bool operator==(uint64_t rhs) const {
return m_address == rhs;
}
// Allow getting the address explicitly, for use in accessors.
constexpr inline uint64_t GetValue() const {
return m_address;
}
private:
uint64_t m_address{};
};
struct PhysicalAddressTag {};
struct VirtualAddressTag {};
struct ProcessAddressTag {};
using PhysicalAddress = TypedAddress<false, PhysicalAddressTag>;
using VirtualAddress = TypedAddress<true, VirtualAddressTag>;
using ProcessAddress = TypedAddress<true, ProcessAddressTag>;
// Define accessors.
template <typename T>
concept IsTypedAddress = std::same_as<T, PhysicalAddress> || std::same_as<T, VirtualAddress> ||
std::same_as<T, ProcessAddress>;
template <typename T>
constexpr inline T Null = [] {
if constexpr (std::is_same<T, uint64_t>::value) {
return 0;
} else {
static_assert(std::is_same<T, PhysicalAddress>::value ||
std::is_same<T, VirtualAddress>::value ||
std::is_same<T, ProcessAddress>::value);
return T(0);
}
}();
// Basic type validations.
static_assert(sizeof(PhysicalAddress) == sizeof(uint64_t));
static_assert(sizeof(VirtualAddress) == sizeof(uint64_t));
static_assert(sizeof(ProcessAddress) == sizeof(uint64_t));
static_assert(std::is_trivially_copyable_v<PhysicalAddress>);
static_assert(std::is_trivially_copyable_v<VirtualAddress>);
static_assert(std::is_trivially_copyable_v<ProcessAddress>);
static_assert(std::is_trivially_copy_constructible_v<PhysicalAddress>);
static_assert(std::is_trivially_copy_constructible_v<VirtualAddress>);
static_assert(std::is_trivially_copy_constructible_v<ProcessAddress>);
static_assert(std::is_trivially_move_constructible_v<PhysicalAddress>);
static_assert(std::is_trivially_move_constructible_v<VirtualAddress>);
static_assert(std::is_trivially_move_constructible_v<ProcessAddress>);
static_assert(std::is_trivially_copy_assignable_v<PhysicalAddress>);
static_assert(std::is_trivially_copy_assignable_v<VirtualAddress>);
static_assert(std::is_trivially_copy_assignable_v<ProcessAddress>);
static_assert(std::is_trivially_move_assignable_v<PhysicalAddress>);
static_assert(std::is_trivially_move_assignable_v<VirtualAddress>);
static_assert(std::is_trivially_move_assignable_v<ProcessAddress>);
static_assert(std::is_trivially_destructible_v<PhysicalAddress>);
static_assert(std::is_trivially_destructible_v<VirtualAddress>);
static_assert(std::is_trivially_destructible_v<ProcessAddress>);
static_assert(Null<uint64_t> == 0);
static_assert(Null<PhysicalAddress> == Null<uint64_t>);
static_assert(Null<VirtualAddress> == Null<uint64_t>);
static_assert(Null<ProcessAddress> == Null<uint64_t>);
// Constructor/assignment validations.
static_assert([] {
const PhysicalAddress a(5);
PhysicalAddress b(a);
return b;
}() == PhysicalAddress(5));
static_assert([] {
const PhysicalAddress a(5);
PhysicalAddress b(10);
b = a;
return b;
}() == PhysicalAddress(5));
// Arithmetic validations.
static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15));
static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5));
static_assert([] {
PhysicalAddress v(10);
v += 5;
return v;
}() == PhysicalAddress(15));
static_assert([] {
PhysicalAddress v(10);
v -= 5;
return v;
}() == PhysicalAddress(5));
static_assert(PhysicalAddress(10)++ == PhysicalAddress(10));
static_assert(++PhysicalAddress(10) == PhysicalAddress(11));
static_assert(PhysicalAddress(10)-- == PhysicalAddress(10));
static_assert(--PhysicalAddress(10) == PhysicalAddress(9));
// Logical validations.
static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111);
static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101);
static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110);
static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010);
static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101);
static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010);
static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000);
static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101);
static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111);
static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111);
// Comparisons.
static_assert(PhysicalAddress(0) == PhysicalAddress(0));
static_assert(PhysicalAddress(0) != PhysicalAddress(1));
static_assert(PhysicalAddress(0) < PhysicalAddress(1));
static_assert(PhysicalAddress(0) <= PhysicalAddress(1));
static_assert(PhysicalAddress(1) > PhysicalAddress(0));
static_assert(PhysicalAddress(1) >= PhysicalAddress(0));
static_assert(!(PhysicalAddress(0) == PhysicalAddress(1)));
static_assert(!(PhysicalAddress(0) != PhysicalAddress(0)));
static_assert(!(PhysicalAddress(1) < PhysicalAddress(0)));
static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0)));
static_assert(!(PhysicalAddress(0) > PhysicalAddress(1)));
static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1)));
} // namespace Common
template <bool Virtual, typename T>
constexpr inline uint64_t GetInteger(Common::TypedAddress<Virtual, T> address) {
return address.GetValue();
}
template <>
struct fmt::formatter<Common::PhysicalAddress> {
constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Common::PhysicalAddress& addr, FormatContext& ctx) {
return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
}
};
template <>
struct fmt::formatter<Common::ProcessAddress> {
constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Common::ProcessAddress& addr, FormatContext& ctx) {
return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
}
};
template <>
struct fmt::formatter<Common::VirtualAddress> {
constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Common::VirtualAddress& addr, FormatContext& ctx) {
return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
}
};
namespace std {
template <>
struct hash<Common::PhysicalAddress> {
size_t operator()(const Common::PhysicalAddress& k) const noexcept {
return k.GetValue();
}
};
template <>
struct hash<Common::ProcessAddress> {
size_t operator()(const Common::ProcessAddress& k) const noexcept {
return k.GetValue();
}
};
template <>
struct hash<Common::VirtualAddress> {
size_t operator()(const Common::VirtualAddress& k) const noexcept {
return k.GetValue();
}
};
} // namespace std
+1
View File
@@ -144,6 +144,7 @@ static CPUCaps Detect() {
caps.bmi2 = Common::Bit<8>(cpu_id[1]);
caps.sha = Common::Bit<29>(cpu_id[1]);
caps.waitpkg = Common::Bit<5>(cpu_id[2]);
caps.gfni = Common::Bit<8>(cpu_id[2]);
__cpuidex(cpu_id, 0x00000007, 0x00000001);
+1
View File
@@ -67,6 +67,7 @@ struct CPUCaps {
bool pclmulqdq : 1;
bool popcnt : 1;
bool sha : 1;
bool waitpkg : 1;
};
/**
+69
View File
@@ -0,0 +1,69 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#ifdef _MSC_VER
#include <intrin.h>
#endif
#include "common/x64/cpu_detect.h"
#include "common/x64/cpu_wait.h"
namespace Common::X64 {
#ifdef _MSC_VER
__forceinline static u64 FencedRDTSC() {
_mm_lfence();
_ReadWriteBarrier();
const u64 result = __rdtsc();
_mm_lfence();
_ReadWriteBarrier();
return result;
}
__forceinline static void TPAUSE() {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
static constexpr auto PauseCycles = 100'000;
_tpause(0, FencedRDTSC() + PauseCycles);
}
#else
static u64 FencedRDTSC() {
u64 eax;
u64 edx;
asm volatile("lfence\n\t"
"rdtsc\n\t"
"lfence\n\t"
: "=a"(eax), "=d"(edx));
return (edx << 32) | eax;
}
static void TPAUSE() {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
static constexpr auto PauseCycles = 100'000;
const auto tsc = FencedRDTSC() + PauseCycles;
const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
const auto edx = static_cast<u32>(tsc >> 32);
asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax));
}
#endif
void MicroSleep() {
static const bool has_waitpkg = GetCPUCaps().waitpkg;
if (has_waitpkg) {
TPAUSE();
} else {
std::this_thread::yield();
}
}
} // namespace Common::X64
+10
View File
@@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Common::X64 {
void MicroSleep();
} // namespace Common::X64
+36 -15
View File
@@ -27,16 +27,13 @@ __forceinline static u64 FencedRDTSC() {
}
#else
static u64 FencedRDTSC() {
u64 result;
u64 eax;
u64 edx;
asm volatile("lfence\n\t"
"rdtsc\n\t"
"shl $32, %%rdx\n\t"
"or %%rdx, %0\n\t"
"lfence"
: "=a"(result)
:
: "rdx", "memory", "cc");
return result;
"lfence\n\t"
: "=a"(eax), "=d"(edx));
return (edx << 32) | eax;
}
#endif
@@ -53,11 +50,11 @@ u64 EstimateRDTSCFrequency() {
FencedRDTSC();
// Get the current time.
const auto start_time = Common::SteadyClock::Now();
const auto start_time = Common::RealTimeClock::Now();
const u64 tsc_start = FencedRDTSC();
// Wait for 250 milliseconds.
std::this_thread::sleep_for(std::chrono::milliseconds{250});
const auto end_time = Common::SteadyClock::Now();
const auto end_time = Common::RealTimeClock::Now();
const u64 tsc_end = FencedRDTSC();
// Calculate differences.
const u64 timer_diff = static_cast<u64>(
@@ -72,13 +69,29 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
u64 rtsc_frequency_)
: WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
rtsc_frequency_} {
// Thread to re-adjust the RDTSC frequency after 10 seconds has elapsed.
time_sync_thread = std::jthread{[this](std::stop_token token) {
// Get the current time.
const auto start_time = Common::RealTimeClock::Now();
const u64 tsc_start = FencedRDTSC();
// Wait for 10 seconds.
if (!Common::StoppableTimedWait(token, std::chrono::seconds{10})) {
return;
}
const auto end_time = Common::RealTimeClock::Now();
const u64 tsc_end = FencedRDTSC();
// Calculate differences.
const u64 timer_diff = static_cast<u64>(
std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());
const u64 tsc_diff = tsc_end - tsc_start;
const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff);
rtsc_frequency = tsc_freq;
CalculateAndSetFactors();
}};
time_point.inner.last_measure = FencedRDTSC();
time_point.inner.accumulated_ticks = 0U;
ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);
us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency);
ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency);
clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency);
cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency);
CalculateAndSetFactors();
}
u64 NativeClock::GetRTSC() {
@@ -138,6 +151,14 @@ u64 NativeClock::GetCPUCycles() {
return MultiplyHigh(rtsc_value, cpu_rtsc_factor);
}
void NativeClock::CalculateAndSetFactors() {
ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);
us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency);
ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency);
clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency);
cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency);
}
} // namespace X64
} // namespace Common
+5
View File
@@ -3,6 +3,7 @@
#pragma once
#include "common/polyfill_thread.h"
#include "common/wall_clock.h"
namespace Common {
@@ -28,6 +29,8 @@ public:
private:
u64 GetRTSC();
void CalculateAndSetFactors();
union alignas(16) TimePoint {
TimePoint() : pack{} {}
u128 pack{};
@@ -47,6 +50,8 @@ private:
u64 ms_rtsc_factor{};
u64 rtsc_frequency;
std::jthread time_sync_thread;
};
} // namespace X64
+1 -1
View File
@@ -33,7 +33,7 @@ std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_siz
std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed) {
const std::size_t decompressed_size =
ZSTD_getDecompressedSize(compressed.data(), compressed.size());
ZSTD_getFrameContentSize(compressed.data(), compressed.size());
std::vector<u8> decompressed(decompressed_size);
const std::size_t uncompressed_result_size = ZSTD_decompress(
+4 -4
View File
@@ -158,6 +158,7 @@ add_library(core STATIC
hid/motion_input.h
hle/api_version.h
hle/ipc.h
hle/kernel/board/nintendo/nx/k_memory_layout.cpp
hle/kernel/board/nintendo/nx/k_memory_layout.h
hle/kernel/board/nintendo/nx/k_system_control.cpp
hle/kernel/board/nintendo/nx/k_system_control.h
@@ -211,12 +212,10 @@ add_library(core STATIC
hle/kernel/k_light_condition_variable.h
hle/kernel/k_light_lock.cpp
hle/kernel/k_light_lock.h
hle/kernel/k_linked_list.h
hle/kernel/k_memory_block.h
hle/kernel/k_memory_block_manager.cpp
hle/kernel/k_memory_block_manager.h
hle/kernel/k_memory_layout.cpp
hle/kernel/k_memory_layout.board.nintendo_nx.cpp
hle/kernel/k_memory_layout.h
hle/kernel/k_memory_manager.cpp
hle/kernel/k_memory_manager.h
@@ -279,6 +278,7 @@ add_library(core STATIC
hle/kernel/k_trace.h
hle/kernel/k_transfer_memory.cpp
hle/kernel/k_transfer_memory.h
hle/kernel/k_typed_address.h
hle/kernel/k_worker_task.h
hle/kernel/k_worker_task_manager.cpp
hle/kernel/k_worker_task_manager.h
@@ -570,10 +570,10 @@ add_library(core STATIC
hle/service/nfp/nfp.h
hle/service/nfp/nfp_device.cpp
hle/service/nfp/nfp_device.h
hle/service/nfp/nfp_interface.cpp
hle/service/nfp/nfp_interface.h
hle/service/nfp/nfp_result.h
hle/service/nfp/nfp_types.h
hle/service/nfp/nfp_user.cpp
hle/service/nfp/nfp_user.h
hle/service/ngct/ngct.cpp
hle/service/ngct/ngct.h
hle/service/nifm/nifm.cpp
+6 -6
View File
@@ -44,7 +44,7 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
std::map<std::string, Symbols::Symbols> symbols;
for (const auto& module : modules) {
symbols.insert_or_assign(
module.second, Symbols::GetSymbols(module.first, system.Memory(),
module.second, Symbols::GetSymbols(module.first, system.ApplicationMemory(),
system.ApplicationProcess()->Is64BitProcess()));
}
@@ -168,21 +168,21 @@ void ARM_Interface::LoadWatchpointArray(const WatchpointArray& wp) {
}
const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint(
VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const {
u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const {
if (!watchpoints) {
return nullptr;
}
const VAddr start_address{addr};
const VAddr end_address{addr + size};
const u64 start_address{addr};
const u64 end_address{addr + size};
for (size_t i = 0; i < Core::Hardware::NUM_WATCHPOINTS; i++) {
const auto& watch{(*watchpoints)[i]};
if (end_address <= watch.start_address) {
if (end_address <= GetInteger(watch.start_address)) {
continue;
}
if (start_address >= watch.end_address) {
if (start_address >= GetInteger(watch.end_address)) {
continue;
}
if ((access_type & watch.type) == Kernel::DebugWatchpointType::None) {
+4 -4
View File
@@ -78,7 +78,7 @@ public:
* @param addr Start address of the cache range to clear
* @param size Size of the cache range to clear, starting at addr
*/
virtual void InvalidateCacheRange(VAddr addr, std::size_t size) = 0;
virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0;
/**
* Notifies CPU emulation that the current page table has changed.
@@ -149,9 +149,9 @@ public:
*/
virtual void SetPSTATE(u32 pstate) = 0;
virtual VAddr GetTlsAddress() const = 0;
virtual u64 GetTlsAddress() const = 0;
virtual void SetTlsAddress(VAddr address) = 0;
virtual void SetTlsAddress(u64 address) = 0;
/**
* Gets the value within the TPIDR_EL0 (read/write software thread ID) register.
@@ -214,7 +214,7 @@ protected:
static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out);
const Kernel::DebugWatchpoint* MatchingWatchpoint(
VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const;
u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const;
virtual Dynarmic::HaltReason RunJit() = 0;
virtual Dynarmic::HaltReason StepJit() = 0;
+16 -19
View File
@@ -5,7 +5,6 @@
#include <memory>
#include <dynarmic/interface/A32/a32.h>
#include <dynarmic/interface/A32/config.h>
#include <dynarmic/interface/A32/context.h>
#include "common/assert.h"
#include "common/literals.h"
#include "common/logging/log.h"
@@ -28,8 +27,8 @@ using namespace Common::Literals;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
: parent{parent_},
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()},
: parent{parent_}, memory(parent.system.ApplicationMemory()),
debugger_enabled{parent.system.DebuggerEnabled()},
check_memory_access{debugger_enabled ||
!Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
@@ -155,7 +154,7 @@ public:
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
}
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
if (!check_memory_access) {
return true;
}
@@ -397,7 +396,7 @@ u64 ARM_Dynarmic_32::GetTlsAddress() const {
return cp15->uro;
}
void ARM_Dynarmic_32::SetTlsAddress(VAddr address) {
void ARM_Dynarmic_32::SetTlsAddress(u64 address) {
cp15->uro = static_cast<u32>(address);
}
@@ -410,21 +409,19 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
}
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
Dynarmic::A32::Context context;
jit.load()->SaveContext(context);
ctx.cpu_registers = context.Regs();
ctx.extension_registers = context.ExtRegs();
ctx.cpsr = context.Cpsr();
ctx.fpscr = context.Fpscr();
Dynarmic::A32::Jit* j = jit.load();
ctx.cpu_registers = j->Regs();
ctx.extension_registers = j->ExtRegs();
ctx.cpsr = j->Cpsr();
ctx.fpscr = j->Fpscr();
}
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
Dynarmic::A32::Context context;
context.Regs() = ctx.cpu_registers;
context.ExtRegs() = ctx.extension_registers;
context.SetCpsr(ctx.cpsr);
context.SetFpscr(ctx.fpscr);
jit.load()->LoadContext(context);
Dynarmic::A32::Jit* j = jit.load();
j->Regs() = ctx.cpu_registers;
j->ExtRegs() = ctx.extension_registers;
j->SetCpsr(ctx.cpsr);
j->SetFpscr(ctx.fpscr);
}
void ARM_Dynarmic_32::SignalInterrupt() {
@@ -439,7 +436,7 @@ void ARM_Dynarmic_32::ClearInstructionCache() {
jit.load()->ClearCache();
}
void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
void ARM_Dynarmic_32::InvalidateCacheRange(u64 addr, std::size_t size) {
jit.load()->InvalidateCacheRange(static_cast<u32>(addr), size);
}
@@ -468,7 +465,7 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system,
u64 fp, u64 lr, u64 pc) {
std::vector<BacktraceEntry> out;
auto& memory = system.Memory();
auto& memory = system.ApplicationMemory();
out.push_back({"", 0, pc, 0, ""});
+3 -3
View File
@@ -41,8 +41,8 @@ public:
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
u64 GetTlsAddress() const override;
void SetTlsAddress(u64 address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
@@ -60,7 +60,7 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void InvalidateCacheRange(VAddr addr, std::size_t size) override;
void InvalidateCacheRange(u64 addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
+7 -7
View File
@@ -28,8 +28,8 @@ using namespace Common::Literals;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_)
: parent{parent_},
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()},
: parent{parent_}, memory(parent.system.ApplicationMemory()),
debugger_enabled{parent.system.DebuggerEnabled()},
check_memory_access{debugger_enabled ||
!Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
@@ -117,7 +117,7 @@ public:
}
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
VAddr value) override {
u64 value) override {
switch (op) {
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
static constexpr u64 ICACHE_LINE_SIZE = 64;
@@ -199,7 +199,7 @@ public:
return parent.system.CoreTiming().GetClockTicks();
}
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
if (!check_memory_access) {
return true;
}
@@ -452,7 +452,7 @@ u64 ARM_Dynarmic_64::GetTlsAddress() const {
return cb->tpidrro_el0;
}
void ARM_Dynarmic_64::SetTlsAddress(VAddr address) {
void ARM_Dynarmic_64::SetTlsAddress(u64 address) {
cb->tpidrro_el0 = address;
}
@@ -500,7 +500,7 @@ void ARM_Dynarmic_64::ClearInstructionCache() {
jit.load()->ClearCache();
}
void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
void ARM_Dynarmic_64::InvalidateCacheRange(u64 addr, std::size_t size) {
jit.load()->InvalidateCacheRange(addr, size);
}
@@ -529,7 +529,7 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system,
u64 fp, u64 lr, u64 pc) {
std::vector<BacktraceEntry> out;
auto& memory = system.Memory();
auto& memory = system.ApplicationMemory();
out.push_back({"", 0, pc, 0, ""});
+3 -3
View File
@@ -38,8 +38,8 @@ public:
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
u64 GetTlsAddress() const override;
void SetTlsAddress(u64 address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
@@ -53,7 +53,7 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void InvalidateCacheRange(VAddr addr, std::size_t size) override;
void InvalidateCacheRange(u64 addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
+12 -11
View File
@@ -137,7 +137,7 @@ struct System::Impl {
device_memory = std::make_unique<Core::DeviceMemory>();
is_multicore = Settings::values.use_multi_core.GetValue();
extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue();
extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
core_timing.SetMulticore(is_multicore);
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
@@ -169,7 +169,7 @@ struct System::Impl {
void ReinitializeIfNecessary(System& system) {
const bool must_reinitialize =
is_multicore != Settings::values.use_multi_core.GetValue() ||
extended_memory_layout != Settings::values.use_extended_memory_layout.GetValue();
extended_memory_layout != Settings::values.use_unsafe_extended_memory_layout.GetValue();
if (!must_reinitialize) {
return;
@@ -178,7 +178,7 @@ struct System::Impl {
LOG_DEBUG(Kernel, "Re-initializing");
is_multicore = Settings::values.use_multi_core.GetValue();
extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue();
extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
Initialize(system);
}
@@ -293,6 +293,8 @@ struct System::Impl {
ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
Kernel::KProcess::ProcessType::Userland, resource_limit)
.IsSuccess());
Kernel::KProcess::Register(system.Kernel(), main_process);
kernel.MakeApplicationProcess(main_process);
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
@@ -302,7 +304,6 @@ struct System::Impl {
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
kernel.MakeApplicationProcess(main_process);
kernel.InitializeCores();
// Initialize cheat engine
@@ -358,7 +359,7 @@ struct System::Impl {
void ShutdownMainProcess() {
SetShuttingDown(true);
// Log last frame performance stats if game was loded
// Log last frame performance stats if game was loaded
if (perf_stats) {
const auto perf_results = GetAndResetPerfStats();
constexpr auto performance = Common::Telemetry::FieldType::Performance;
@@ -434,7 +435,7 @@ struct System::Impl {
}
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process.GetProgramID();
launch.title_id = process.GetProgramId();
FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
launch.version = pm.GetGameVersion().value_or(0);
@@ -564,7 +565,7 @@ void System::InvalidateCpuInstructionCaches() {
impl->kernel.InvalidateAllInstructionCaches();
}
void System::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
void System::InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size) {
impl->kernel.InvalidateCpuInstructionCacheRange(addr, size);
}
@@ -681,11 +682,11 @@ const ExclusiveMonitor& System::Monitor() const {
return impl->kernel.GetExclusiveMonitor();
}
Memory::Memory& System::Memory() {
Memory::Memory& System::ApplicationMemory() {
return impl->memory;
}
const Core::Memory::Memory& System::Memory() const {
const Core::Memory::Memory& System::ApplicationMemory() const {
return impl->memory;
}
@@ -762,7 +763,7 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
}
u64 System::GetApplicationProcessProgramID() const {
return impl->kernel.ApplicationProcess()->GetProgramID();
return impl->kernel.ApplicationProcess()->GetProgramId();
}
Loader::ResultStatus System::GetGameName(std::string& out) const {
@@ -794,7 +795,7 @@ FileSys::VirtualFilesystem System::GetFilesystem() const {
}
void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 32>& build_id, VAddr main_region_begin,
const std::array<u8, 32>& build_id, u64 main_region_begin,
u64 main_region_size) {
impl->cheat_engine = std::make_unique<Memory::CheatEngine>(*this, list, build_id);
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
+5 -5
View File
@@ -146,7 +146,7 @@ public:
/**
* Initializes the system
* This function will initialize core functionaility used for system emulation
* This function will initialize core functionality used for system emulation
*/
void Initialize();
@@ -172,7 +172,7 @@ public:
*/
void InvalidateCpuInstructionCaches();
void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
void InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size);
/// Shutdown the main emulated process.
void ShutdownMainProcess();
@@ -256,10 +256,10 @@ public:
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
/// Gets a mutable reference to the system memory instance.
[[nodiscard]] Core::Memory::Memory& Memory();
[[nodiscard]] Core::Memory::Memory& ApplicationMemory();
/// Gets a constant reference to the system memory instance.
[[nodiscard]] const Core::Memory::Memory& Memory() const;
[[nodiscard]] const Core::Memory::Memory& ApplicationMemory() const;
/// Gets a mutable reference to the GPU interface
[[nodiscard]] Tegra::GPU& GPU();
@@ -353,7 +353,7 @@ public:
[[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const;
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
const std::array<u8, 0x20>& build_id, u64 main_region_begin,
u64 main_region_size);
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
+9 -1
View File
@@ -10,6 +10,10 @@
#include "common/windows/timer_resolution.h"
#endif
#ifdef ARCHITECTURE_x86_64
#include "common/x64/cpu_wait.h"
#endif
#include "common/microprofile.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
@@ -53,7 +57,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) {
static constexpr char name[] = "HostTiming";
MicroProfileOnThreadCreate(name);
Common::SetCurrentThreadName(name);
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
instance.on_thread_init();
instance.ThreadLoop();
MicroProfileOnThreadExit();
@@ -269,7 +273,11 @@ void CoreTiming::ThreadLoop() {
if (wait_time >= timer_resolution_ns) {
Common::Windows::SleepForOneTick();
} else {
#ifdef ARCHITECTURE_x86_64
Common::X64::MicroSleep();
#else
std::this_thread::yield();
#endif
}
}
+1 -1
View File
@@ -150,7 +150,7 @@ private:
// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
// We don't use std::priority_queue because we need to be able to serialize, unserialize and
// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't
// accomodated by the standard adaptor class.
// accommodated by the standard adaptor class.
std::vector<Event> event_queue;
u64 event_fifo_id = 0;
+1 -1
View File
@@ -192,7 +192,7 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
}
MicroProfileOnThreadCreate(name.c_str());
Common::SetCurrentThreadName(name.c_str());
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
auto& data = core_data[core];
data.host_context = Common::Fiber::ThreadToFiber();
+1 -1
View File
@@ -11,7 +11,7 @@
namespace Core::Crypto {
// Sits on top of a VirtualFile and provides CTR-mode AES decription.
// Sits on top of a VirtualFile and provides CTR-mode AES description.
class CTREncryptionLayer : public EncryptionLayer {
public:
using IVData = std::array<u8, 16>;
+1 -1
View File
@@ -249,7 +249,7 @@ public:
static bool KeyFileExists(bool title);
// Call before using the sd seed to attempt to derive it if it dosen't exist. Needs system
// Call before using the sd seed to attempt to derive it if it doesn't exist. Needs system
// save 8*43 and the private file to exist.
void DeriveSDSeedLazy();

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