Compare commits

...

279 Commits

Author SHA1 Message Date
german77 ebca59b8e9 yuzu_cmd: Fix mismatching controller input 2023-02-04 11:05:57 -06:00
german77 424643f9af yuzu_cmd: Fix touch input 2023-02-04 10:31:12 -06:00
liamwhite 8a33f8bd30 Merge pull request #9708 from ameerj/gl-context-flush
gl_shader_cache: Force context flush when loading disk shader cache
2023-02-01 22:38:13 -05:00
liamwhite a9a860a4f7 Merge pull request #9703 from ameerj/txq-ms
shaders: Fix TXQ with MSAA textures
2023-02-01 22:38:00 -05:00
bunnei 92c5ab33b7 Merge pull request #9696 from german77/please_forgive_me_for_this_sin
input_common: Implement turbo buttons
2023-02-01 12:08:34 -08:00
german77 ce1895497d yuzu: config: Draw turbo buttons with a different color 2023-02-01 12:42:06 -06:00
german77 75e81885b0 input_common: Implement turbo buttons 2023-02-01 12:42:05 -06:00
Mai c4aa833d61 Merge pull request #9711 from zhaobot/tx-update-20230201062139
Update translations (2023-02-01)
2023-02-01 01:26:51 -05:00
The yuzu Community 6ef4bee98e Update translations (2023-02-01) 2023-02-01 06:21:50 +00:00
bunnei de28cd0c2d Merge pull request #9697 from liamwhite/kcap
kernel: add KCapabilities
2023-01-31 10:51:10 -08:00
bunnei ed4a88bd93 Merge pull request #9508 from ameerj/hle-ipc-buffer-span
hle_ipc: Use std::span to avoid heap allocations/copies when calling ReadBuffer
2023-01-30 12:17:09 -08:00
liamwhite e74660673b Merge pull request #9701 from german77/common_protocol
input_common: joycon: Remove Magic numbers from common protocol
2023-01-30 09:02:12 -05:00
liamwhite 9de88cb5a7 Merge pull request #9631 from vonchenplus/vulkan_clear
video_core: Implement vulkan clear specified channel
2023-01-30 09:01:55 -05:00
Liam 67a8740af6 kernel: add KCapabilities 2023-01-29 22:08:28 -05:00
ameerj 720ff38097 gl_compute_pipeline: Force context flush when loading shader cache 2023-01-29 21:32:12 -05:00
Narr the Reg c318a4c80b input_common: joycon: Remove Magic numbers from common protocol 2023-01-29 20:12:58 -06:00
Morph 4069c3ac8b Merge pull request #9707 from german77/clang15
cmake: Download clang format 15
2023-01-29 21:00:55 -05:00
german77 fb425159b1 cmake: Download clang format 15 2023-01-29 19:57:40 -06:00
ameerj 01eeda74a6 gl_graphics_pipeline: Force context flush when loading shader cache 2023-01-29 20:26:49 -05:00
Narr the Reg 11fea5deea input_common: joycon: Fill missing enum data 2023-01-29 19:11:46 -06:00
Morph 07cefe9062 Merge pull request #9706 from Morph1984/github-tagged-merge
ci: Abort on failure to query Github's API
2023-01-29 20:09:29 -05:00
Morph e711188be7 apply-patches-by-label: Remove unused variables and imports 2023-01-29 19:53:14 -05:00
Morph 0f04cabf84 apply-patches-by-label: Use python f-strings 2023-01-29 19:53:14 -05:00
Morph 8532e17243 ci: Abort on failure to query Github's API
This raises an exception if the GET request to Github's API returns anything other than 200 OK, ensuring we always have successful merges of tagged PRs.
Also, reduces the number of queried pages from 29 to 9 to reduce the number of requests.
2023-01-29 19:53:14 -05:00
Morph 5f4647df7d Merge pull request #9705 from behunin/patch-1
Move to Clang Format 15
2023-01-29 19:52:38 -05:00
Levi Behunin d5fc56db4b Move to Clang Format 15
Depends on https://github.com/yuzu-emu/build-environments/pull/69

clang-15 primary run
2023-01-29 17:49:42 -07:00
ameerj a63e17566a spirv: Fix TXQ with MSAA textures 2023-01-29 13:47:30 -05:00
ameerj a1d8306bfd emit_glasm_image: Fix TXQ with MSAA textures 2023-01-29 13:42:34 -05:00
ameerj 08feba2b56 emit_glsl_image: Implement TXQ with MSAA textures
Also fixes for texture buffers, which do not have mips eithers.
2023-01-29 13:31:47 -05:00
liamwhite 3aab574521 Merge pull request #9699 from ameerj/texture-pass-desc
texture_pass: Fix texture descriptors comparisons
2023-01-29 12:27:41 -05:00
liamwhite 149271923c Merge pull request #9698 from ameerj/texture-pass-handle
texture_pass: Refactor texture handle retrieval
2023-01-29 12:27:33 -05:00
liamwhite 208e635f37 Merge pull request #9694 from ameerj/txq-mips
shader_recompiler: TXQ: Skip QueryLevels when possible
2023-01-29 12:27:26 -05:00
liamwhite d960723dc9 Merge pull request #9684 from liamwhite/read-the-spec
polyfill_thread: satisfy execution ordering requirements of stop_callback
2023-01-29 09:35:42 -05:00
bunnei 9170387e71 Merge pull request #9689 from german77/joycon-calibration
input_common: joycon: Remove magic numbers from calibration protocol
2023-01-29 02:43:14 -08:00
bunnei a3aedcce65 Merge pull request #9691 from ameerj/msaa-texcache
texture_cache: Fix tracking of MSAA image views
2023-01-28 23:47:45 -08:00
liamwhite 236f591bde Merge pull request #9690 from german77/whoops
yuzu: config: Avoid reading deleted object
2023-01-28 22:28:38 -05:00
ameerj 0d820f2dab texture_pass: Fix texture descriptors comparisons 2023-01-28 21:23:52 -05:00
ameerj 9bb429999e texture_pass: Refactor texture handle retrieval 2023-01-28 21:11:38 -05:00
bunnei 40e7d78179 Merge pull request #9687 from ameerj/ogl-shader-ms
glasm, glsl: Implement multisampled Image Fetch
2023-01-28 16:32:11 -08:00
bunnei 159aab9a97 Merge pull request #9682 from ameerj/shader-s32
shader_recompiler: Remove S32 IR type
2023-01-28 14:00:11 -08:00
ameerj 2c2e019a44 shader_recompiler: TXQ: Skip QueryLevels when possible 2023-01-28 16:25:18 -05:00
ameerj c0cedbae94 emit_glsl_image: Fix ImageFetch for MSAA textures 2023-01-28 14:39:27 -05:00
Narr the Reg e84a441d75 yuzu: config: Avoid reading deleted object 2023-01-28 12:50:27 -06:00
liamwhite cd138540e2 Merge pull request #9661 from SoRadGaming/LDNhostnameSupport
LDN hostname support in direct connect
2023-01-28 12:09:57 -05:00
SoRadGaming ad712926d6 LDN Hostname Support in Direct Connect
- Added IPv6 & Namespace support in direct connection Regex
- Updated Tooltip for Direct Connect UI
- Removed Dropdown Connection Type in Direct Connect
2023-01-28 18:33:21 +11:00
ameerj c2fb7b64ce texture_cache: Adjust image view sizes by MSAA samples 2023-01-28 00:15:29 -05:00
FengChen 818631a412 video_core: Implement vulkan clear specified channel 2023-01-28 12:53:05 +08:00
Liam 619c0e70f0 polyfill_thread: satisfy execution ordering requirements of stop_callback 2023-01-27 21:34:49 -05:00
bunnei 2efe42fc93 Merge pull request #9677 from Morph1984/sleep-one
polyfill_thread: Implement StoppableTimedWait
2023-01-27 18:28:03 -08:00
Narr the Reg 4e29afefc4 input_common: joycon: Replace ReadSPI vector with span 2023-01-27 18:45:25 -06:00
liamwhite 6fa86989f1 Merge pull request #9539 from Wollnashorn/opengl-fsr
video_core/opengl: Added FSR upscaling filter to the OpenGL renderer
2023-01-27 19:28:35 -05:00
Narr the Reg 8647c72778 input_common: joycon: Remove magic numbers from calibration protocol 2023-01-27 17:12:04 -06:00
bunnei 32b2a72e7b Merge pull request #9666 from liamwhite/wait-for-me
kernel: fix incorrect locking order in suspension
2023-01-27 15:06:09 -08:00
ameerj 0f795603fc glasm: Add MS sampler types 2023-01-27 02:09:18 -05:00
ameerj 5710e90150 glsl: Add MS sampler types 2023-01-27 02:09:17 -05:00
Mai e54d08fc1f Merge pull request #9685 from liamwhite/minmax
kernel: unbreak min/max template deduction on Apple Clang
2023-01-27 00:07:50 +00:00
Liam e9e1e7aa3a kernel: unbreak min/max template deduction on Apple Clang 2023-01-26 17:43:37 -05:00
Wollnashorn c4a49eb1dd video_core/opengl: Add FSR upscaling filter to the OpenGL renderer 2023-01-26 21:43:33 +01:00
bunnei 7d0a77a825 Merge pull request #9683 from german77/high_power_joycon
input_common: Implement SetLowPowerMode and TriggersElapsed
2023-01-26 10:56:31 -08:00
Narr the Reg 49707916db input_common: Implement SetLowPowerMode and TriggersElapsed for the joycon driver 2023-01-26 11:21:04 -06:00
bunnei 5669692b4e Merge pull request #9670 from merryhime/revert-af5ecb0b15d4449f58434e70eed835cf71fc5527
Revert "MemoryManager: use fastmem directly."
2023-01-25 22:28:55 -08:00
bunnei 58ba508e9a Merge pull request #9652 from liamwhite/ms
spirv: fix multisampled image fetch
2023-01-25 22:28:18 -08:00
bunnei 2158ccda3b Merge pull request #9604 from liamwhite/pt
kernel: KPageTable: update
2023-01-25 22:27:48 -08:00
ameerj 93cc6e4d99 shader_recompiler: Remove S32 IR type
The frontend IR opcodes do not distinguish between signed and unsigned integer types.

Fixes broken shaders when IR validation/graphics debugging is enabled for shaders that used BitCastS32F32
2023-01-25 22:03:15 -05:00
Morph 0a7cdc1981 Merge pull request #9681 from Morph1984/nice-one-qt6
main: Only set AA_DisableWindowContextHelpButton below Qt6
2023-01-25 20:46:51 -05:00
Morph b6e5a6bda8 main: Only set AA_DisableWindowContextHelpButton below Qt6
This is fortunately disabled by default on Qt6, so we just have to check whether we are compiling with Qt6 or not.
2023-01-25 18:45:22 -05:00
liamwhite 0d1a9a12c9 Merge pull request #9675 from Morph1984/ini-concat
default_ini: Split and concatenate the config string literal
2023-01-25 17:57:09 -05:00
liamwhite 4ec50dfd4f Merge pull request #9668 from Morph1984/qt-why-is-this-not-the-default
main: Globally disable the "?" button on dialogs
2023-01-25 17:56:58 -05:00
liamwhite abda68f3a4 Merge pull request #9676 from german77/revert-stick-range
Revert #9617 and fix it on input_common
2023-01-25 17:56:47 -05:00
Morph c55147b24a input_common: Make use of StoppableTimedWait 2023-01-25 16:43:04 -05:00
Morph 9b0563fa87 polyfill_thread: Implement StoppableTimedWait
StoppableTimedWait allows for a timed wait to be stopped immediately after a stop is requested.
This is useful in cases where long duration thread sleeps are needed and allows for immediate joining of waiting threads after a stop is requested.

Co-Authored-By: liamwhite <liamwhite@users.noreply.github.com>
2023-01-25 16:43:04 -05:00
Narr the Reg b82a098968 Merge pull request #9679 from jbeich/libc++
input_common: unbreak build with libc++ (missing std::ranges::find_if)
2023-01-25 15:21:59 -06:00
Jan Beich 20c7084892 input_common: add missing header for libc++ after 340f15d1fa
src/input_common/drivers/joycon.cpp:187:26: error: no member named 'find_if' in namespace 'std::ranges'
            std::ranges::find_if(left_joycons, [](auto& device) { return !device->IsConnected(); });
            ~~~~~~~~~~~~~^
src/input_common/drivers/joycon.cpp:193:54: error: no member named 'find_if' in namespace 'std::ranges'
        const auto unconnected_device = std::ranges::find_if(
                                        ~~~~~~~~~~~~~^
src/input_common/drivers/joycon.cpp:393:51: error: no member named 'find_if' in namespace 'std::ranges'
        const auto matching_device = std::ranges::find_if(
                                     ~~~~~~~~~~~~~^
src/input_common/drivers/joycon.cpp:402:51: error: no member named 'find_if' in namespace 'std::ranges'
        const auto matching_device = std::ranges::find_if(
                                     ~~~~~~~~~~~~~^
2023-01-25 19:52:56 +00:00
Narr the Reg cc821bfae1 Revert 9617 and fix it on input_common 2023-01-25 13:52:50 -06:00
Morph 4cdf69c378 default_ini: Split and concatenate the config string literal
We are dangerously close to MSVC's 16384 character limit for string literals. Breaking this string up and concatenating will allow for more settings to be added in the future.
2023-01-25 14:06:06 -05:00
Merry dc7ab4c5d6 Revert "MemoryManager: use fastmem directly."
This reverts commit af5ecb0b15.
2023-01-25 10:12:04 +00:00
Morph cdfb3795af main: Globally disable the "?" button on dialogs
Sets the AA_DisableWindowContextHelpButton attribute to disable this useless button globally.
2023-01-25 01:12:50 -05:00
bunnei 44b981fd3e Merge pull request #9662 from abouvier/cmake-llvm
cmake: prefer system llvm library
2023-01-24 11:03:14 -08:00
liamwhite a68af583ea Merge pull request #9492 from german77/joycon_release
Input_common: Implement custom joycon driver v2
2023-01-24 09:29:37 -05:00
Liam 693cad8e9b kernel: split SetAddressKey into user and kernel variants 2023-01-23 20:31:03 -05:00
Liam 5086380a63 kernel: fix incorrect locking order in suspension 2023-01-23 17:14:41 -05:00
Liam 76a4356e55 spirv: fix multisampled image fetch 2023-01-23 12:03:19 -05:00
Alexandre Bouvier 34b1ea9c19 cmake: prefer system llvm library 2023-01-23 06:23:00 +01:00
liamwhite f99f618d45 Merge pull request #9555 from abouvier/catch2-update
tests: update catch2 to 3.0.1
2023-01-22 18:22:47 -05:00
Liam 31e54c4573 kernel: KPageTable: update 2023-01-22 13:17:29 -05:00
liamwhite 78df1ddce8 Merge pull request #9660 from german77/koreaToTaiwan
yuzu: Fix language comobox crash
2023-01-22 13:14:38 -05:00
liamwhite 9184b6ed2b Merge pull request #9656 from liamwhite/nsight
nsight_aftermath_tracker: update for latest Aftermath SDK
2023-01-22 13:14:28 -05:00
liamwhite ff2bbc8205 Merge pull request #9637 from SaiKai/repeat_shortcuts
allow volume up/down hotkeys to be repeated
2023-01-22 13:14:19 -05:00
liamwhite 02ac593257 Merge pull request #9617 from german77/off_by_one
core: hid: Fix stick minimum range
2023-01-22 13:14:10 -05:00
liamwhite 9705094a57 Merge pull request #9613 from Kelebek1/demangle
Add stacktrace symbol demangling
2023-01-22 13:13:58 -05:00
german77 a436467152 yuzu: Fix language comobox crash 2023-01-22 10:42:59 -06:00
Liam c6eab71d5c nsight_aftermath_tracker: update for latest Aftermath SDK 2023-01-21 13:01:19 -05:00
Kelebek1 31229dd245 Change licenses 2023-01-21 06:19:43 +00:00
bunnei 380dcde154 Merge pull request #9642 from Tachi107/appstream-metadata-fix
fix(dist): wrap screenshots in <image> tags
2023-01-20 21:02:38 -08:00
bunnei f78068d7bf Merge pull request #9611 from liamwhite/patch-1
debugger: add host fastmem pointer fetch command
2023-01-20 10:00:33 -08:00
Narr the Reg d9ee7c3297 core: hid: Make use of SCOPE_EXIT and SCOPE_GUARD where applicable 2023-01-20 00:51:46 -06:00
german77 fafa92cfb8 input_common: Fix joycon mappings 2023-01-20 00:51:46 -06:00
german77 340f15d1fa input_common: Address byte review 2023-01-20 00:51:45 -06:00
bunnei 7d77798f0e Merge pull request #9640 from german77/why_sdl
input_common: reset sdl motion if data is invalid
2023-01-19 18:47:21 -08:00
Narr the Reg 4a307a7b3a core: hid: Only set the polling mode to the correct side 2023-01-19 18:05:23 -06:00
german77 b40aefb39e input_common: Drop Pro controller support from custom driver 2023-01-19 18:05:22 -06:00
german77 d05ea2f3eb input_common: Fix issue where ring and irs are enabled at the same time 2023-01-19 18:05:22 -06:00
Narr the Reg 459fb2b213 input_common: Implement joycon ir camera 2023-01-19 18:05:22 -06:00
german77 5cb437703f yuzu: Add ring controller test button 2023-01-19 18:05:22 -06:00
german77 527dad7097 input_common: Use DriverResult on all engines 2023-01-19 18:05:22 -06:00
german77 e1a3bda4d9 Address review comments 2023-01-19 18:05:22 -06:00
Narr the Reg 1c08d532e0 core: hid: Fix input regressions 2023-01-19 18:05:22 -06:00
german77 6d6b7bdbc3 input_common: Implement joycon nfc 2023-01-19 18:05:21 -06:00
Narr the Reg 6e33731f29 input_common: Add dual joycon support 2023-01-19 18:05:21 -06:00
Narr the Reg 751d36e739 input_common: Add support for joycon ring controller 2023-01-19 18:05:21 -06:00
Narr the Reg f09a023292 input_common: Add support for joycon input reports 2023-01-19 18:05:21 -06:00
Narr the Reg 5676c2e17f input_common: Use calibration from joycon 2023-01-19 18:05:21 -06:00
Narr the Reg 594b2ade6d input_common: Add support for joycon generic functions 2023-01-19 18:05:21 -06:00
Narr the Reg 6aa6301acd input_common: Add joycon low level functions 2023-01-19 18:05:21 -06:00
Narr the Reg 36d5e0a411 service: hid: Set led pattern and fix color detection 2023-01-19 18:05:20 -06:00
Narr the Reg ed5fa10e97 core: hid: Enable pulling color data from controllers 2023-01-19 18:05:20 -06:00
Narr the Reg a4074001fe core: hid: Migrate ring from emulated devices to emulated controller 2023-01-19 18:05:20 -06:00
Narr the Reg 18c9f8eeed yuzu: Update controller colors and button names 2023-01-19 18:05:20 -06:00
Narr the Reg 2d802893e7 input_common: Disable SDL driver with switch controllers 2023-01-19 18:05:20 -06:00
Narr the Reg d80e6c399b input_common: Initial skeleton for custom joycon driver 2023-01-19 18:05:20 -06:00
liamwhite 475370c8f8 Merge pull request #9556 from vonchenplus/draw_texture
video_core: Implement maxwell3d draw texture method
2023-01-19 14:58:53 -05:00
bunnei 9ca3a4758a Merge pull request #9623 from liamwhite/wp-oops
memory: fix watchpoint use when fastmem is enabled
2023-01-19 10:50:21 -08:00
Andrea Pappacoda 9f08b3c3c9 fix(dist): wrap screenshots in <image> tags
The [appstream] spec says that <screenshot/> tags must be wrapped in
either <image/> or <video/> tags, so this patch does just that.

[appstream]: https://freedesktop.org/software/appstream/docs/chap-Metadata.html#tag-screenshots
2023-01-19 10:13:30 +01:00
Narr the Reg 67c3c65f7b Merge pull request #9638 from Kelebek1/firmware4
Demote maxwell3d Firmware4 call log to debug
2023-01-18 23:15:22 -06:00
bunnei 413df0811d Merge pull request #9619 from liamwhite/timing-spaghetti
timing: wait for completion on unregister
2023-01-18 15:13:38 -08:00
german77 db6cb9cc0a input_common: reset sdl motion if data is invalid 2023-01-18 10:05:55 -06:00
Jonas Gutenschwager 887ed5c0e2 fix format 2023-01-18 15:49:47 +01:00
bunnei 82e2ac6026 Merge pull request #9615 from merryhime/upsample-ob1
audio_core: Corrective fixes to upsampler
2023-01-17 23:34:12 -08:00
bunnei 1551f97950 Merge pull request #9608 from liamwhite/fps
nvnflinger: correct swap interval handling
2023-01-17 23:13:47 -08:00
Kelebek1 5a106cf11e Demote maxwell3d Firmware4 call log to debug 2023-01-18 01:59:11 +00:00
Jonas Gutenschwager 83754e4789 allow volume up/down hotkeys to be repeated 2023-01-18 00:39:31 +01:00
bunnei 28fde29924 Merge pull request #9612 from goldenx86/1.5xScaler
1.5X, 7X, 8X resolution scaler options
2023-01-16 17:49:06 -08:00
bunnei 58a10ed5d0 Merge pull request #9622 from merryhime/dynarmic
externals: Update dynarmic to 6.4.4
2023-01-15 23:22:54 -08:00
Feng Chen 9fc7ca1731 Address feedback 2023-01-16 10:27:57 +08:00
Liam f1a0ce0e70 memory: fix watchpoint use when fastmem is enabled 2023-01-15 10:24:31 -05:00
Merry 2817af0961 externals: Update dynarmic to 6.4.4 2023-01-15 02:31:00 +00:00
Liam 0953cdd271 timing: wait for completion on unregister 2023-01-14 15:48:01 -05:00
Kelebek1 42b16bb33a Be careful of mangled out of bounds read 2023-01-14 19:53:55 +00:00
german77 50c86b3c2a core: hid: Fix stick minimum range 2023-01-14 11:53:43 -06:00
Merry a0e8e5b22e upsample: Fix coefficient format 2023-01-14 17:09:03 +00:00
Merry 122a8faa38 audio_core: Fix off-by-one error in upsampler 2023-01-14 15:19:11 +00:00
Kelebek1 ce0b8d618d Move demangle impl to cpp 2023-01-14 05:12:41 +00:00
Kelebek1 80a55c1663 Add stacktrace symbol demangling 2023-01-14 04:43:21 +00:00
Matías Locatti d7dbd8e774 Update settings.h 2023-01-13 04:56:25 -03:00
Matías Locatti 4294429a07 CPP 2023-01-13 04:55:26 -03:00
Matías Locatti bb2aec00a2 UI change 2023-01-13 04:54:29 -03:00
Matías Locatti 3ba53f2511 1.5X resolution scaler option 2023-01-13 02:34:24 -03:00
Liam e9c3d16f6f debugger: add host fastmem pointer fetch command 2023-01-12 18:35:14 -05:00
Liam 2f2ef5b147 nvnflinger: correct swap interval handling 2023-01-11 22:05:08 -05:00
bunnei 0e8f98a441 Merge pull request #9605 from german77/mouse_mapping
yuzu: Read mouse scroll
2023-01-10 17:32:58 -08:00
Narr the Reg 87b02f78e1 yuzu: Read mouse wheel input 2023-01-10 18:20:58 -06:00
Morph c277dad25f Merge pull request #9596 from liamwhite/mvk
MoltenVK: restrict number of vertex attributes/bindings to 16
2023-01-10 18:11:44 -05:00
liamwhite cbcf210c19 Merge pull request #9582 from yuzu-emu/revert-9518-revert-9504-pg2
Revert "Revert "k_page_group: synchronize""
2023-01-10 15:27:33 -05:00
liamwhite 0eae0b6803 Merge pull request #9601 from liamwhite/it-never-ends
qt: unlock during signal emission
2023-01-10 15:27:12 -05:00
liamwhite 74404261d2 Merge pull request #9598 from liamwhite/indirect
vulkan_common: fix indirect draw with count
2023-01-10 15:27:02 -05:00
liamwhite e2c68edd35 Merge pull request #9595 from liamwhite/per-game
qt: fix configuration weirdness on turbo
2023-01-10 15:26:49 -05:00
liamwhite 9f974ea818 Merge pull request #9565 from MonsterDruide1/tas-multiplayer-lengths
TAS: Show all script lengths for multiplayer
2023-01-10 15:26:36 -05:00
Liam 385ddef8c3 qt: unlock during signal emission 2023-01-10 12:46:01 -05:00
Liam fa8581e900 vulkan_common: fix indirect draw with count 2023-01-10 09:43:36 -05:00
TellowKrinkle eaf425bd32 MoltenVK: restrict number of vertex attributes/bindings to 16 2023-01-09 19:01:09 -05:00
Liam 1caa84e652 qt: fix configuration weirdness on turbo 2023-01-09 17:54:49 -05:00
UltraHDR fda0e7e989 macOS: Make Yuzu show up in the Launchpad Games folder (#9594)
https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype
This makes it show up in the Launchpad Games folder
2023-01-09 16:43:45 -05:00
Morph 6bf1436f5c Merge pull request #9589 from liamwhite/default
renderer_vulkan: disable turbo by default
2023-01-09 16:23:24 -05:00
Morph ffb12f4f9f Merge pull request #9581 from liamwhite/turbo2
renderer_vulkan: pause turbo submissions on inactive queue
2023-01-09 16:23:16 -05:00
Morph a4cd747122 Merge pull request #9530 from liamwhite/vk-feature-init
vulkan_device: refactor feature testing
2023-01-09 16:23:04 -05:00
Morph 3be8312120 Merge pull request #9569 from liamwhite/shutdown-wars
qt: additional fixes for reentrant shutdown
2023-01-09 16:21:27 -05:00
Liam 279005448a vulkan_device: refactor feature testing 2023-01-09 16:12:16 -05:00
Fernando S 948ac976d1 Merge pull request #9583 from FernandoS27/fuck-ogl-already
VideoCore: Fix OGL cache invalidation.
2023-01-08 14:05:29 -05:00
Liam 0df43e4e07 renderer_vulkan: disable turbo by default 2023-01-08 11:38:30 -05:00
Fernando Sahmkow efbb6fe288 VideoCore: Fix OGL cache invalidation. 2023-01-07 21:56:17 -05:00
bunnei a5693afa03 Revert "Revert "k_page_group: synchronize"" 2023-01-07 15:32:10 -08:00
bunnei 66e4a48b75 Merge pull request #9563 from german77/crash_not_allowed
input_common: Create an update engine
2023-01-07 13:41:27 -08:00
MonsterDruide1 115bf20448 TAS: Show all script lengths for multiplayer 2023-01-07 21:15:37 +01:00
liamwhite 926438b68d Merge pull request #9578 from bylaws/patch-2
Avoid OOB array access reading passthrough attr mask
2023-01-07 15:14:08 -05:00
Liam c19c8ac92c renderer_vulkan: pause turbo submissions on inactive queue 2023-01-07 14:35:11 -05:00
Billy Laws d34275a260 Avoid OOB array access reading passthrough attr mask
YFC 1.5 extended the size of the varying mask used to hold passthrough attrs without considering this
2023-01-07 18:38:21 +00:00
Narr the Reg 432d48d9c8 Merge pull request #9570 from liamwhite/less-clock-boost
renderer_vulkan: disable clock boost on unvalidated devices
2023-01-07 10:41:37 -06:00
Narr the Reg cc92b7fd94 Merge pull request #9573 from liamwhite/optional
vulkan_device: avoid attempt to access empty optional
2023-01-07 10:40:21 -06:00
Liam 444b25bae1 vulkan_device: avoid attempt to access empty optional 2023-01-06 21:23:21 -05:00
Liam 2e4dde12c7 renderer_vulkan: disable clock boost on unvalidated devices 2023-01-06 19:07:47 -05:00
Liam 9ed4c13758 qt: additional fixes for reentrant shutdown 2023-01-06 18:50:01 -05:00
liamwhite c0f17e1b27 Merge pull request #9567 from german77/antialias
opengl: Sanitize antialiasing config
2023-01-06 15:20:23 -05:00
Narr the Reg 4bda2b475f opengl: Sanitize antialiasing config 2023-01-06 13:42:20 -06:00
Fernando S 7ef897a277 Merge pull request #9566 from Wollnashorn/vulkan-cache-header-fix
video_core/vulkan: Fixed loading of Vulkan driver pipeline cache
2023-01-06 11:58:36 -05:00
Wollnashorn 457826a83b video_core/vulkan: Fixed loading of Vulkan driver pipeline cache
The header size of the Vulkan driver pipeline cache files was incorrectly in PipelineCache::LoadVulkanPipelineCache, for which the pipeline cache wasn't read correctly and got invalidated on each load.
2023-01-06 16:52:41 +01:00
Fernando S 8b251fc3f6 Merge pull request #9535 from bylaws/master
Port over several shader-compiler fixes from skyline
2023-01-06 10:06:45 -05:00
liamwhite 3c05988df2 Merge pull request #9561 from liamwhite/update-dynarmic
externals: update dynarmic, xbyak
2023-01-06 10:00:18 -05:00
liamwhite 6d74490139 Merge pull request #9558 from MonsterDruide1/network-timeout-noerror
net: Silently translate ETIMEDOUT network error
2023-01-06 10:00:09 -05:00
liamwhite 020dbcdbc7 Merge pull request #9552 from liamwhite/turbo
vulkan: implement 'turbo mode' clock booster
2023-01-06 09:59:59 -05:00
Fernando S 5bcbb8de45 Merge pull request #9559 from FernandoS27/cached-writes
VideoCore: Implement Cached Writes, use fastmem for reading GPU memory and eliminate old stuffs
2023-01-06 07:31:39 -05:00
liamwhite 990fe2b3fc Merge pull request #9564 from FernandoS27/oops-i-did-it-again
MacroHLE: eliminate 2 rushed macros.
2023-01-05 22:14:27 -05:00
Fernando Sahmkow f6245dc40a MacroHLE: eliminate 2 rushed macros. 2023-01-05 20:53:31 -05:00
Narr the Reg 8042ce7e19 input_common: Create an update engine 2023-01-05 19:24:29 -06:00
liamwhite eaca61e073 Merge pull request #9528 from liamwhite/mvk-nulldesc
renderer_vulkan: implement fallback path for null buffer descriptors
2023-01-05 18:31:55 -05:00
liamwhite 3e33a878dc Merge pull request #9536 from liamwhite/debug-utils
vulkan_common: unify VK_EXT_debug_utils and selection of validation layer
2023-01-05 18:31:45 -05:00
Liam 1ee0540f82 externals: update dynarmic, xbyak 2023-01-05 18:06:06 -05:00
Billy Laws 58fec43768 Run clang-format 2023-01-05 22:18:10 +00:00
Billy Laws 12b4c9c04c externals: Update sirit 2023-01-05 22:13:07 +00:00
Billy Laws 68ed60cee4 shader_recompiler: Fix shuffle partitioning for >64 invoc-per-subgroup GPUs
The existing implementation only supports 64 invoc-per-subgroup GPUs, and misbehaves on adreno when invocations need to be split into 4 emulated subgroups.
2023-01-05 22:13:07 +00:00
Billy Laws 6c812a0c84 Vulkan, OpenGL: Hook up geometry shader passthrough emulation 2023-01-05 22:13:07 +00:00
Billy Laws 625a4af73a shader_recompiler: Add support for lowering geometry passthrough
Reuses most of the existing code for generating the gl_Layer passthrough. Fixes geometry in Nier: Automata on GPUs without HW passthrough support.
2023-01-05 22:13:07 +00:00
Billy Laws 9e2997c4b6 Vulkan, OpenGL: Hook up storage buffer alignment code 2023-01-05 22:13:07 +00:00
Billy Laws 8804a4eb23 shader_recompiler: Align SSBO offsets to meet host requirements
We can take advantage of SSBO addresses being passed in a constant bufer to account for the extra alignment requirements in the shader itself.
2023-01-05 22:13:07 +00:00
Billy Laws 3f0985c7b0 shader_recompiler: SPIRV: Only enable int64 feature when supported 2023-01-05 22:13:07 +00:00
Billy Laws c1cc99584c shader_recompiler: Add comparison operators to descriptor types 2023-01-05 22:13:07 +00:00
Billy Laws bbfad79c89 Vulkan: Add a workaround for input_position on Adreno drivers
Adreno drivers will crash compiling geometry shaders if the input position is not wrapped in a gl_in struct.
2023-01-05 22:13:07 +00:00
Fernando S 1428451722 Merge pull request #9527 from Wollnashorn/amd-cache-fix
video_core/vulkan: Implemented `VkPipelineCache` to store Vulkan pipelines
2023-01-05 16:38:07 -05:00
Wollnashorn e07976a22b video_core/vulkan: Vulkan driver pipelines now contain cache version
So that old cache can get deleted when the cache version changes and does not grow infinitely
2023-01-05 21:03:01 +01:00
Wollnashorn 9c9008ac81 video_core/vulkan: Driver pipeline cache will now be deleted with the shader cache 2023-01-05 21:03:01 +01:00
Wollnashorn 8945fafcc0 config: Set the Vulkan driver pipeline cache option to be global 2023-01-05 21:03:01 +01:00
Wollnashorn f2aa816679 video_core/vulkan: Added check if Vulkan pipeline path has been set 2023-01-05 21:03:01 +01:00
Wollnashorn f4626512ff config: Better wording for VK pipeline cache option and enable by default 2023-01-05 21:03:01 +01:00
Wollnashorn 67d4f190f7 yuzu-cmd: Removed use_vulkan_driver_pipeline_cache from default_ini.h
The addition of the use_vulkan_driver_pipeline_cache option into the default ini string literal caused the 16,384-byte limit of the MSVC compiler to be exceeded.
2023-01-05 21:03:01 +01:00
Wollnashorn 16809c1fa7 video_core/vulkan: Added VkPipelineCache to store Vulkan pipelines
As an optional feature which can be enabled in the advanced graphics configuration, all pipelines that get built at the initial shader loading are stored in a VkPipelineCache object and are dumped to the disk.

These vendor specific pipeline cache files are located at `/shader/GAME_ID/vulkan_pipelines.bin`. This feature was mainly added because of an issue with the AMD driver (see yuzu-emu#8507) causing invalidation of the cache files the driver builds automatically.
2023-01-05 21:02:44 +01:00
Fernando Sahmkow b56ad93bbc BufferBase: Don't ignore GPU pages. 2023-01-05 14:00:10 -05:00
Fernando Sahmkow 2d0c4f2b1d Fermi2D: sync cache flushes 2023-01-05 06:43:28 -05:00
Fernando Sahmkow af5ecb0b15 MemoryManager: use fastmem directly. 2023-01-05 06:06:33 -05:00
MonsterDruide1 688a9fbfa6 net: Silently translate ETIMEDOUT network error 2023-01-05 11:54:36 +01:00
Fernando Sahmkow 6c7eb81f7d video_core: Cache GPU internal writes. 2023-01-05 05:23:39 -05:00
liamwhite e82e3e06be Merge pull request #9557 from FernandoS27/ooops-i-killed-the-shitty-drivers
Vulkan: Fix drivers that don't support dynamic_state_2 up
2023-01-05 00:14:01 -05:00
Fernando Sahmkow 4d9af4a9d2 Vulkan: Fix drivers that don't support dynamic_state_2 up 2023-01-05 00:11:16 -05:00
Feng Chen 013b689153 video_core: Implement opengl/vulkan draw_texture 2023-01-05 12:41:33 +08:00
Feng Chen 1e8cee2ddf video_core: Implement maxwell3d draw texture method 2023-01-05 12:41:28 +08:00
Alexandre Bouvier 7a2bd13f5b cmake: support the standard cmake testing option 2023-01-05 05:03:34 +01:00
Alexandre Bouvier d0fe27708e tests: update catch2 to 3.0.1 2023-01-05 04:58:31 +01:00
Liam a4269c285a common: add setting for renderer clock workaround 2023-01-04 22:22:01 -05:00
Liam 301e9bbc03 vulkan: implement 'turbo mode' clock booster 2023-01-04 22:22:01 -05:00
Liam 66ae79de13 renderer_vulkan: implement fallback path for null descriptors 2023-01-04 22:14:01 -05:00
liamwhite b78328f19a Merge pull request #9501 from FernandoS27/yfc-rel-2
Yuzu Fried Chicken Part 1.5: MacroHLE Rework and Dynamic State
2023-01-04 21:20:00 -05:00
Fernando Sahmkow 3ecc03ec1b yuzu-ui: Add setting for disabling macro HLE 2023-01-04 14:56:52 -05:00
Fernando Sahmkow a0c697124c Video_core: Address feedback 2023-01-04 14:39:42 -05:00
Fernando Sahmkow 03ccd8bf43 Texture Cache: Implement async texture downloads. 2023-01-03 22:52:15 -05:00
liamwhite bbeb6e460c Merge pull request #9518 from gidoly/revert-9504-pg2
Revert "k_page_group: synchronize"
2023-01-03 21:40:57 -05:00
Fernando Sahmkow ddbf851ef6 Vulkan: Update blacklisting to latest driver versions. 2023-01-03 21:16:43 -05:00
Fernando Sahmkow a045e860dd ShaderCompiler: Inline driver specific constants. 2023-01-03 16:29:25 -05:00
Fernando Sahmkow b62ffb612d Vulkan: rework stencil tracking. 2023-01-03 16:29:16 -05:00
liamwhite 6f031f08fe Merge pull request #9547 from MonsterDruide1/tas-doesnt-flap
TAS: Immediately switch stick to TAS on input
2023-01-03 15:03:58 -05:00
MonsterDruide1 04cb05fce0 TAS: Immediately switch stick to TAS on input
Co-Authored-By: Narr the Reg <5944268+german77@users.noreply.github.com>
2023-01-03 20:08:25 +01:00
liamwhite a7e610403d Merge pull request #9542 from abouvier/cmake-module-path
cmake: move find-modules to root cmake dir
2023-01-02 13:45:36 -05:00
Alexandre Bouvier eceee8c3d9 cmake: move find-modules to root cmake dir 2023-01-02 18:22:07 +01:00
liamwhite 2b110d61e7 Merge pull request #9541 from abouvier/cmake-option
cmake: allow options shadowing with normal variables
2023-01-02 11:29:32 -05:00
liamwhite 6804a43f49 Merge pull request #9540 from MonsterDruide1/tas-sanitized-record
TAS: Record sanitized instead of raw stick inputs
2023-01-02 09:51:29 -05:00
bunnei 48bcb91a2e Merge pull request #9537 from abouvier/cmake-almost-quiet
cmake: improve find_package failure messages
2023-01-02 01:08:20 -08:00
bunnei 09c9be3703 Merge pull request #9543 from german77/nifm
service: nifm: Initialize request state
2023-01-01 21:38:43 -08:00
german77 80bcc18788 service: nifm: Initialize request state 2023-01-01 20:58:08 -06:00
german77 ebd811b535 service: nifm: Match documentation names 2023-01-01 20:58:01 -06:00
Alexandre Bouvier 306c791e67 cmake: allow options shadowing with normal variables 2023-01-02 02:43:38 +01:00
Liam f9c6d39a6c vulkan_common: blacklist radv from extended_dynamic_state2 on drivers before 22.3.1 2023-01-01 16:43:58 -05:00
Liam 4814d87385 video_core: fix build 2023-01-01 16:43:58 -05:00
Fernando Sahmkow d09aa0182f MacroHLE: Final cleanup and fixes. 2023-01-01 16:43:58 -05:00
Fernando Sahmkow 581a7d785b Rasterizer: Setup skeleton for Host Conditional rendering 2023-01-01 16:43:58 -05:00
Fernando Sahmkow 3630bfaef3 RasterizerMemory: Add filtering for flushing/invalidation operations. 2023-01-01 16:43:58 -05:00
Fernando Sahmkow 2793304117 Vulkan: Allow stagging buffer deferrals. 2023-01-01 16:43:58 -05:00
Fernando Sahmkow 8d694701bc MacroHLE: Add OpenGL Support 2023-01-01 16:43:58 -05:00
Fernando Sahmkow 4c82e47edd Vulkan: Add other additional pipeline specs 2023-01-01 16:43:58 -05:00
Fernando Sahmkow d33251db93 Vulkan: Implement Dynamic State 3 2023-01-01 16:43:58 -05:00
Fernando Sahmkow f800e485c9 Vulkan Implement Dynamic State 2 LogicOp and PatchVertices 2023-01-01 16:43:58 -05:00
Fernando Sahmkow c897c55e3c Vulkan: Implement Dynamic States 2 2023-01-01 16:43:57 -05:00
Fernando Sahmkow cb1497d0d7 DMAPusher: Improve collection of non executing methods 2023-01-01 16:43:57 -05:00
Fernando Sahmkow ce448ce770 Revert Buffer cache changes and setup additional macros. 2023-01-01 16:43:57 -05:00
Fernando Sahmkow 18637766ef MacroHLE: Reduce massive calculations on sizing estimation. 2023-01-01 16:43:57 -05:00
Fernando Sahmkow aad0cbf024 MacroHLE: Add HLE replacement for base vertex and base instance. 2023-01-01 16:43:57 -05:00
Fernando Sahmkow 93ac5a6a6d MacroHLE: Add Index Buffer size estimation. 2023-01-01 16:43:57 -05:00
Fernando Sahmkow c541559767 MacroHLE: Refactor MacroHLE system. 2023-01-01 16:43:57 -05:00
Fernando Sahmkow 0f89828073 MacroHLE: Implement DrawIndexedIndirect & DrawArraysIndirect. 2023-01-01 16:43:57 -05:00
Fernando Sahmkow a5a94f52ff MacroHLE: Add MultidrawIndirect HLE Macro. 2023-01-01 16:43:57 -05:00
MonsterDruide1 d46c9c4659 TAS: Record sanitized instead of raw stick inputs
Co-Authored-By: Narr the Reg <5944268+german77@users.noreply.github.com>
2023-01-01 22:39:18 +01:00
Liam aa13ee5c4a vulkan_common: unify VK_EXT_debug_utils and selection of validation layer 2023-01-01 11:59:47 -05:00
gidoly 10eaf31af3 Revert "k_page_group: synchronize" 2022-12-29 17:39:42 +09:00
ameerj b0722591c9 hle_ipc: Use thread_local ReadBuffer 2022-12-28 18:46:54 -05:00
ameerj a1490d77ac hle_ipc: Rename ReadBufferSpan to ReadBuffer 2022-12-28 18:46:54 -05:00
ameerj 59c0f85407 hle_ipc: Rename ReadBuffer to ReadBufferCopy
Indicates explicitly that a copy is occurring
2022-12-28 18:46:54 -05:00
ameerj 7c1bf68bb4 bsd: Use std::span for read payloads
Allows the use of HLERequestContext::ReadBufferSpan
2022-12-28 18:46:54 -05:00
ameerj f517f82416 nvdrv: Use std::span for inputs
Allows the use of HLERequestContext::ReadBufferSpan
2022-12-28 18:46:53 -05:00
ameerj e7032d9e64 hidbus: Use ReadBufferSpan 2022-12-28 18:46:53 -05:00
ameerj 32d01a39b0 nvflinger: Split Parcel class into InputParcel and OutputParcel
The usages of the Parcel class were already unique to either Read or Write operations.
Avoids needing a vector of the input payload for the InputParcel use-case, instead it can remain as a span.
2022-12-25 17:19:10 -05:00
ameerj 7ffd624248 service: Use ReadBufferSpan where it is trivial to do so 2022-12-25 17:04:02 -05:00
ameerj fbc375f0de fsp_srv: Use ReadBufferSpan 2022-12-25 13:21:15 -05:00
ameerj 9349f06963 hle_ipc: Add ReadBufferSpan function
Returns a std::span to the buffer address, rather than create a copy of the memory into a std::vector
2022-12-25 13:20:59 -05:00
418 changed files with 36786 additions and 15613 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
fi
# Default clang-format points to default 3.5 version one
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-12}
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-15}
$CLANG_FORMAT --version
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
+9 -11
View File
@@ -2,15 +2,12 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Download all pull requests as patches that match a specific label
# Usage: python download-patches-by-label.py <Label to Match> <Root Path Folder to DL to>
# Usage: python apply-patches-by-label.py <Label to Match>
import requests, sys, json, urllib3.request, shutil, subprocess, os, traceback
import json, requests, subprocess, sys, traceback
tagline = sys.argv[2]
http = urllib3.PoolManager()
dl_list = {}
def check_individual(labels):
for label in labels:
if (label["name"] == sys.argv[1]):
@@ -18,8 +15,9 @@ def check_individual(labels):
return False
def do_page(page):
url = 'https://api.github.com/repos/yuzu-emu/yuzu/pulls?page=%s' % page
url = f"https://api.github.com/repos/yuzu-emu/yuzu/pulls?page={page}"
response = requests.get(url)
response.raise_for_status()
if (response.ok):
j = json.loads(response.content)
if j == []:
@@ -27,13 +25,13 @@ def do_page(page):
for pr in j:
if (check_individual(pr["labels"])):
pn = pr["number"]
print("Matched PR# %s" % pn)
print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", "pull/%s/head:pr-%s" % (pn, pn), "-f", "--no-recurse-submodules"]))
print(subprocess.check_output(["git", "merge", "--squash", "pr-%s" % pn]))
print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)]))
print(f"Matched PR# {pn}")
print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", f"pull/{pn}/head:pr-{pn}", "-f", "--no-recurse-submodules"]))
print(subprocess.check_output(["git", "merge", "--squash", f"pr-{pn}"]))
print(subprocess.check_output(["git", "commit", f"-m\"Merge {tagline} PR {pn}\""]))
try:
for i in range(1,30):
for i in range(1,10):
do_page(i)
except:
traceback.print_exc(file=sys.stdout)
+7 -10
View File
@@ -3,17 +3,14 @@
cmake_minimum_required(VERSION 3.22)
# Dynarmic has cmake_minimum_required(3.12) and we may want to override
# some of its variables, which is only possible in 3.13+
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
project(yuzu)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/find-modules")
include(DownloadExternals)
include(CMakeDependentOption)
project(yuzu)
include(CTest)
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
@@ -47,7 +44,7 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
option(YUZU_TESTS "Compile tests" ON)
option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
@@ -211,6 +208,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
find_package(enet 1.3 MODULE)
find_package(fmt 9 REQUIRED)
find_package(inih MODULE)
find_package(LLVM MODULE)
find_package(lz4 REQUIRED)
find_package(nlohmann_json 3.8 REQUIRED)
find_package(Opus 1.3 MODULE)
@@ -247,7 +245,7 @@ if (ENABLE_WEB_SERVICE)
endif()
if (YUZU_TESTS)
find_package(Catch2 2.13.7 REQUIRED)
find_package(Catch2 3.0.1 REQUIRED)
endif()
find_package(Boost 1.73.0 COMPONENTS context)
@@ -516,7 +514,7 @@ endif()
# against all the src files. This should be used before making a pull request.
# =======================================================================
set(CLANG_FORMAT_POSTFIX "-12")
set(CLANG_FORMAT_POSTFIX "-15")
find_program(CLANG_FORMAT
NAMES clang-format${CLANG_FORMAT_POSTFIX}
clang-format
@@ -611,7 +609,6 @@ if (YUZU_USE_FASTER_LD AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
endif()
endif()
enable_testing()
add_subdirectory(externals)
add_subdirectory(src)
+16
View File
@@ -0,0 +1,16 @@
# SPDX-FileCopyrightText: 2023 Alexandre Bouvier <contact@amb.tf>
#
# SPDX-License-Identifier: GPL-3.0-or-later
find_package(LLVM QUIET CONFIG)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LLVM CONFIG_MODE)
if (LLVM_FOUND AND NOT TARGET LLVM::Demangle)
add_library(LLVM::Demangle INTERFACE IMPORTED)
llvm_map_components_to_libnames(LLVM_LIBRARIES demangle)
target_compile_definitions(LLVM::Demangle INTERFACE ${LLVM_DEFINITIONS})
target_include_directories(LLVM::Demangle INTERFACE ${LLVM_INCLUDE_DIRS})
target_link_libraries(LLVM::Demangle INTERFACE ${LLVM_LIBRARIES})
endif()
+15
View File
@@ -0,0 +1,15 @@
---- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
+673 -509
View File
File diff suppressed because it is too large Load Diff
+674 -510
View File
File diff suppressed because it is too large Load Diff
+672 -508
View File
File diff suppressed because it is too large Load Diff
+699 -535
View File
File diff suppressed because it is too large Load Diff
+676 -512
View File
File diff suppressed because it is too large Load Diff
+738 -571
View File
File diff suppressed because it is too large Load Diff
+675 -511
View File
File diff suppressed because it is too large Load Diff
+673 -509
View File
File diff suppressed because it is too large Load Diff
+675 -511
View File
File diff suppressed because it is too large Load Diff
+675 -511
View File
File diff suppressed because it is too large Load Diff
+711 -544
View File
File diff suppressed because it is too large Load Diff
+673 -509
View File
File diff suppressed because it is too large Load Diff
+680 -516
View File
File diff suppressed because it is too large Load Diff
+877 -698
View File
File diff suppressed because it is too large Load Diff
+678 -514
View File
File diff suppressed because it is too large Load Diff
+678 -514
View File
File diff suppressed because it is too large Load Diff
+716 -552
View File
File diff suppressed because it is too large Load Diff
+680 -516
View File
File diff suppressed because it is too large Load Diff
+675 -511
View File
File diff suppressed because it is too large Load Diff
+700 -536
View File
File diff suppressed because it is too large Load Diff
+709 -545
View File
File diff suppressed because it is too large Load Diff
+675 -511
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -53,10 +53,10 @@ SPDX-License-Identifier: CC0-1.0
<developer_name>yuzu Emulator Team</developer_name>
<content_rating type="oars-1.0"/>
<screenshots>
<screenshot type="default">https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/001-Super%20Mario%20Odyssey%20.png</screenshot>
<screenshot>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/004-The%20Legend%20of%20Zelda%20Skyward%20Sword%20HD.png</screenshot>
<screenshot>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/007-Pokemon%20Sword.png</screenshot>
<screenshot>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/010-Hyrule%20Warriors%20Age%20of%20Calamity.png</screenshot>
<screenshot>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/039-Pok%C3%A9mon%20Mystery%20Dungeon%20Rescue%20Team%20DX.png.png.png</screenshot>
<screenshot type="default"><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/001-Super%20Mario%20Odyssey%20.png</image></screenshot>
<screenshot><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/004-The%20Legend%20of%20Zelda%20Skyward%20Sword%20HD.png</image></screenshot>
<screenshot><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/007-Pokemon%20Sword.png</image></screenshot>
<screenshot><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/010-Hyrule%20Warriors%20Age%20of%20Calamity.png</image></screenshot>
<screenshot><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/039-Pok%C3%A9mon%20Mystery%20Dungeon%20Rescue%20Team%20DX.png.png.png</image></screenshot>
</screenshots>
</component>
+19 -10
View File
@@ -1,9 +1,12 @@
# SPDX-FileCopyrightText: 2016 Citra Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/externals/find-modules")
include(DownloadExternals)
# Dynarmic has cmake_minimum_required(3.12) and we may want to override
# some of its variables, which is only possible in 3.13+
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
# Disable tests in all externals supporting the standard option name
set(BUILD_TESTING OFF)
# xbyak
if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
@@ -12,8 +15,7 @@ endif()
# Dynarmic
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)
set(DYNARMIC_NO_BUNDLED_FMT ON)
set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE)
set(DYNARMIC_IGNORE_ASSERTS ON)
add_subdirectory(dynarmic EXCLUDE_FROM_ALL)
add_library(dynarmic::dynarmic ALIAS dynarmic)
endif()
@@ -60,10 +62,10 @@ if (YUZU_USE_EXTERNAL_SDL2)
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
option(SDL_${_OPT} "" OFF)
set(SDL_${_OPT} OFF)
endforeach()
option(HIDAPI "" ON)
set(HIDAPI ON)
endif()
set(SDL_STATIC ON)
set(SDL_SHARED OFF)
@@ -83,7 +85,7 @@ endif()
# Cubeb
if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)
set(BUILD_TESTS OFF CACHE BOOL "")
set(BUILD_TESTS OFF)
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
add_library(cubeb::cubeb ALIAS cubeb)
endif()
@@ -98,6 +100,7 @@ endif()
# Sirit
add_subdirectory(sirit EXCLUDE_FROM_ALL)
# httplib
if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
if (NOT WIN32)
find_package(OpenSSL 1.1)
@@ -108,7 +111,7 @@ if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
if (WIN32 OR NOT OPENSSL_FOUND)
# LibreSSL
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
set(LIBRESSL_SKIP_INSTALL ON)
set(OPENSSLDIR "/etc/ssl/")
add_subdirectory(libressl EXCLUDE_FROM_ALL)
target_include_directories(ssl INTERFACE ./libressl/include)
@@ -118,7 +121,6 @@ if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
DEFINITION OPENSSL_LIBS)
endif()
# httplib
add_library(httplib INTERFACE)
target_include_directories(httplib INTERFACE ./cpp-httplib)
target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
@@ -155,3 +157,10 @@ endif()
if (YUZU_USE_EXTERNAL_VULKAN_HEADERS)
add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL)
endif()
if (NOT TARGET LLVM::Demangle)
add_library(demangle STATIC)
target_include_directories(demangle PUBLIC ./demangle)
target_sources(demangle PRIVATE demangle/ItaniumDemangle.cpp)
add_library(LLVM::Demangle ALIAS demangle)
endif()
+588
View File
@@ -0,0 +1,588 @@
//===------------------------- ItaniumDemangle.cpp ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// FIXME: (possibly) incomplete list of features that clang mangles that this
// file does not yet support:
// - C++ modules TS
#include "llvm/Demangle/Demangle.h"
#include "llvm/Demangle/ItaniumDemangle.h"
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <numeric>
#include <utility>
#include <vector>
using namespace llvm;
using namespace llvm::itanium_demangle;
constexpr const char *itanium_demangle::FloatData<float>::spec;
constexpr const char *itanium_demangle::FloatData<double>::spec;
constexpr const char *itanium_demangle::FloatData<long double>::spec;
// <discriminator> := _ <non-negative number> # when number < 10
// := __ <non-negative number> _ # when number >= 10
// extension := decimal-digit+ # at the end of string
const char *itanium_demangle::parse_discriminator(const char *first,
const char *last) {
// parse but ignore discriminator
if (first != last) {
if (*first == '_') {
const char *t1 = first + 1;
if (t1 != last) {
if (std::isdigit(*t1))
first = t1 + 1;
else if (*t1 == '_') {
for (++t1; t1 != last && std::isdigit(*t1); ++t1)
;
if (t1 != last && *t1 == '_')
first = t1 + 1;
}
}
} else if (std::isdigit(*first)) {
const char *t1 = first + 1;
for (; t1 != last && std::isdigit(*t1); ++t1)
;
if (t1 == last)
first = last;
}
}
return first;
}
#ifndef NDEBUG
namespace {
struct DumpVisitor {
unsigned Depth = 0;
bool PendingNewline = false;
template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
return true;
}
static bool wantsNewline(NodeArray A) { return !A.empty(); }
static constexpr bool wantsNewline(...) { return false; }
template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
for (bool B : {wantsNewline(Vs)...})
if (B)
return true;
return false;
}
void printStr(const char *S) { fprintf(stderr, "%s", S); }
void print(StringView SV) {
fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
}
void print(const Node *N) {
if (N)
N->visit(std::ref(*this));
else
printStr("<null>");
}
void print(NodeOrString NS) {
if (NS.isNode())
print(NS.asNode());
else if (NS.isString())
print(NS.asString());
else
printStr("NodeOrString()");
}
void print(NodeArray A) {
++Depth;
printStr("{");
bool First = true;
for (const Node *N : A) {
if (First)
print(N);
else
printWithComma(N);
First = false;
}
printStr("}");
--Depth;
}
// Overload used when T is exactly 'bool', not merely convertible to 'bool'.
void print(bool B) { printStr(B ? "true" : "false"); }
template <class T>
typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
fprintf(stderr, "%llu", (unsigned long long)N);
}
template <class T>
typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
fprintf(stderr, "%lld", (long long)N);
}
void print(ReferenceKind RK) {
switch (RK) {
case ReferenceKind::LValue:
return printStr("ReferenceKind::LValue");
case ReferenceKind::RValue:
return printStr("ReferenceKind::RValue");
}
}
void print(FunctionRefQual RQ) {
switch (RQ) {
case FunctionRefQual::FrefQualNone:
return printStr("FunctionRefQual::FrefQualNone");
case FunctionRefQual::FrefQualLValue:
return printStr("FunctionRefQual::FrefQualLValue");
case FunctionRefQual::FrefQualRValue:
return printStr("FunctionRefQual::FrefQualRValue");
}
}
void print(Qualifiers Qs) {
if (!Qs) return printStr("QualNone");
struct QualName { Qualifiers Q; const char *Name; } Names[] = {
{QualConst, "QualConst"},
{QualVolatile, "QualVolatile"},
{QualRestrict, "QualRestrict"},
};
for (QualName Name : Names) {
if (Qs & Name.Q) {
printStr(Name.Name);
Qs = Qualifiers(Qs & ~Name.Q);
if (Qs) printStr(" | ");
}
}
}
void print(SpecialSubKind SSK) {
switch (SSK) {
case SpecialSubKind::allocator:
return printStr("SpecialSubKind::allocator");
case SpecialSubKind::basic_string:
return printStr("SpecialSubKind::basic_string");
case SpecialSubKind::string:
return printStr("SpecialSubKind::string");
case SpecialSubKind::istream:
return printStr("SpecialSubKind::istream");
case SpecialSubKind::ostream:
return printStr("SpecialSubKind::ostream");
case SpecialSubKind::iostream:
return printStr("SpecialSubKind::iostream");
}
}
void print(TemplateParamKind TPK) {
switch (TPK) {
case TemplateParamKind::Type:
return printStr("TemplateParamKind::Type");
case TemplateParamKind::NonType:
return printStr("TemplateParamKind::NonType");
case TemplateParamKind::Template:
return printStr("TemplateParamKind::Template");
}
}
void newLine() {
printStr("\n");
for (unsigned I = 0; I != Depth; ++I)
printStr(" ");
PendingNewline = false;
}
template<typename T> void printWithPendingNewline(T V) {
print(V);
if (wantsNewline(V))
PendingNewline = true;
}
template<typename T> void printWithComma(T V) {
if (PendingNewline || wantsNewline(V)) {
printStr(",");
newLine();
} else {
printStr(", ");
}
printWithPendingNewline(V);
}
struct CtorArgPrinter {
DumpVisitor &Visitor;
template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
if (Visitor.anyWantNewline(V, Vs...))
Visitor.newLine();
Visitor.printWithPendingNewline(V);
int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
(void)PrintInOrder;
}
};
template<typename NodeT> void operator()(const NodeT *Node) {
Depth += 2;
fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
Node->match(CtorArgPrinter{*this});
fprintf(stderr, ")");
Depth -= 2;
}
void operator()(const ForwardTemplateReference *Node) {
Depth += 2;
fprintf(stderr, "ForwardTemplateReference(");
if (Node->Ref && !Node->Printing) {
Node->Printing = true;
CtorArgPrinter{*this}(Node->Ref);
Node->Printing = false;
} else {
CtorArgPrinter{*this}(Node->Index);
}
fprintf(stderr, ")");
Depth -= 2;
}
};
}
void itanium_demangle::Node::dump() const {
DumpVisitor V;
visit(std::ref(V));
V.newLine();
}
#endif
namespace {
class BumpPointerAllocator {
struct BlockMeta {
BlockMeta* Next;
size_t Current;
};
static constexpr size_t AllocSize = 4096;
static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
alignas(long double) char InitialBuffer[AllocSize];
BlockMeta* BlockList = nullptr;
void grow() {
char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
if (NewMeta == nullptr)
std::terminate();
BlockList = new (NewMeta) BlockMeta{BlockList, 0};
}
void* allocateMassive(size_t NBytes) {
NBytes += sizeof(BlockMeta);
BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
if (NewMeta == nullptr)
std::terminate();
BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
return static_cast<void*>(NewMeta + 1);
}
public:
BumpPointerAllocator()
: BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
void* allocate(size_t N) {
N = (N + 15u) & ~15u;
if (N + BlockList->Current >= UsableAllocSize) {
if (N > UsableAllocSize)
return allocateMassive(N);
grow();
}
BlockList->Current += N;
return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
BlockList->Current - N);
}
void reset() {
while (BlockList) {
BlockMeta* Tmp = BlockList;
BlockList = BlockList->Next;
if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
std::free(Tmp);
}
BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
}
~BumpPointerAllocator() { reset(); }
};
class DefaultAllocator {
BumpPointerAllocator Alloc;
public:
void reset() { Alloc.reset(); }
template<typename T, typename ...Args> T *makeNode(Args &&...args) {
return new (Alloc.allocate(sizeof(T)))
T(std::forward<Args>(args)...);
}
void *allocateNodeArray(size_t sz) {
return Alloc.allocate(sizeof(Node *) * sz);
}
};
} // unnamed namespace
//===----------------------------------------------------------------------===//
// Code beyond this point should not be synchronized with libc++abi.
//===----------------------------------------------------------------------===//
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
size_t *N, int *Status) {
if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
if (Status)
*Status = demangle_invalid_args;
return nullptr;
}
int InternalStatus = demangle_success;
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
OutputStream S;
Node *AST = Parser.parse();
if (AST == nullptr)
InternalStatus = demangle_invalid_mangled_name;
else if (!initializeOutputStream(Buf, N, S, 1024))
InternalStatus = demangle_memory_alloc_failure;
else {
assert(Parser.ForwardTemplateRefs.empty());
AST->print(S);
S += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
Buf = S.getBuffer();
}
if (Status)
*Status = InternalStatus;
return InternalStatus == demangle_success ? Buf : nullptr;
}
ItaniumPartialDemangler::ItaniumPartialDemangler()
: RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}
ItaniumPartialDemangler::~ItaniumPartialDemangler() {
delete static_cast<Demangler *>(Context);
}
ItaniumPartialDemangler::ItaniumPartialDemangler(
ItaniumPartialDemangler &&Other)
: RootNode(Other.RootNode), Context(Other.Context) {
Other.Context = Other.RootNode = nullptr;
}
ItaniumPartialDemangler &ItaniumPartialDemangler::
operator=(ItaniumPartialDemangler &&Other) {
std::swap(RootNode, Other.RootNode);
std::swap(Context, Other.Context);
return *this;
}
// Demangle MangledName into an AST, storing it into this->RootNode.
bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
Demangler *Parser = static_cast<Demangler *>(Context);
size_t Len = std::strlen(MangledName);
Parser->reset(MangledName, MangledName + Len);
RootNode = Parser->parse();
return RootNode == nullptr;
}
static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
RootNode->print(S);
S += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
if (!isFunction())
return nullptr;
const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
while (true) {
switch (Name->getKind()) {
case Node::KAbiTagAttr:
Name = static_cast<const AbiTagAttr *>(Name)->Base;
continue;
case Node::KStdQualifiedName:
Name = static_cast<const StdQualifiedName *>(Name)->Child;
continue;
case Node::KNestedName:
Name = static_cast<const NestedName *>(Name)->Name;
continue;
case Node::KLocalName:
Name = static_cast<const LocalName *>(Name)->Entity;
continue;
case Node::KNameWithTemplateArgs:
Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
continue;
default:
return printNode(Name, Buf, N);
}
}
}
char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
size_t *N) const {
if (!isFunction())
return nullptr;
const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
KeepGoingLocalFunction:
while (true) {
if (Name->getKind() == Node::KAbiTagAttr) {
Name = static_cast<const AbiTagAttr *>(Name)->Base;
continue;
}
if (Name->getKind() == Node::KNameWithTemplateArgs) {
Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
continue;
}
break;
}
switch (Name->getKind()) {
case Node::KStdQualifiedName:
S += "std";
break;
case Node::KNestedName:
static_cast<const NestedName *>(Name)->Qual->print(S);
break;
case Node::KLocalName: {
auto *LN = static_cast<const LocalName *>(Name);
LN->Encoding->print(S);
S += "::";
Name = LN->Entity;
goto KeepGoingLocalFunction;
}
default:
break;
}
S += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
if (!isFunction())
return nullptr;
auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
return printNode(Name, Buf, N);
}
char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
size_t *N) const {
if (!isFunction())
return nullptr;
NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
S += '(';
Params.printWithComma(S);
S += ')';
S += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionReturnType(
char *Buf, size_t *N) const {
if (!isFunction())
return nullptr;
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
if (const Node *Ret =
static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
Ret->print(S);
S += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
}
char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
assert(RootNode != nullptr && "must call partialDemangle()");
return printNode(static_cast<Node *>(RootNode), Buf, N);
}
bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
assert(RootNode != nullptr && "must call partialDemangle()");
if (!isFunction())
return false;
auto *E = static_cast<const FunctionEncoding *>(RootNode);
return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
}
bool ItaniumPartialDemangler::isCtorOrDtor() const {
const Node *N = static_cast<const Node *>(RootNode);
while (N) {
switch (N->getKind()) {
default:
return false;
case Node::KCtorDtorName:
return true;
case Node::KAbiTagAttr:
N = static_cast<const AbiTagAttr *>(N)->Base;
break;
case Node::KFunctionEncoding:
N = static_cast<const FunctionEncoding *>(N)->getName();
break;
case Node::KLocalName:
N = static_cast<const LocalName *>(N)->Entity;
break;
case Node::KNameWithTemplateArgs:
N = static_cast<const NameWithTemplateArgs *>(N)->Name;
break;
case Node::KNestedName:
N = static_cast<const NestedName *>(N)->Name;
break;
case Node::KStdQualifiedName:
N = static_cast<const StdQualifiedName *>(N)->Child;
break;
}
}
return false;
}
bool ItaniumPartialDemangler::isFunction() const {
assert(RootNode != nullptr && "must call partialDemangle()");
return static_cast<const Node *>(RootNode)->getKind() ==
Node::KFunctionEncoding;
}
bool ItaniumPartialDemangler::isSpecialName() const {
assert(RootNode != nullptr && "must call partialDemangle()");
auto K = static_cast<const Node *>(RootNode)->getKind();
return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
}
bool ItaniumPartialDemangler::isData() const {
return !isFunction() && !isSpecialName();
}
+104
View File
@@ -0,0 +1,104 @@
//===--- Demangle.h ---------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_DEMANGLE_H
#define LLVM_DEMANGLE_DEMANGLE_H
#include <cstddef>
#include <string>
namespace llvm {
/// This is a llvm local version of __cxa_demangle. Other than the name and
/// being in the llvm namespace it is identical.
///
/// The mangled_name is demangled into buf and returned. If the buffer is not
/// large enough, realloc is used to expand it.
///
/// The *status will be set to a value from the following enumeration
enum : int {
demangle_unknown_error = -4,
demangle_invalid_args = -3,
demangle_invalid_mangled_name = -2,
demangle_memory_alloc_failure = -1,
demangle_success = 0,
};
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
int *status);
enum MSDemangleFlags {
MSDF_None = 0,
MSDF_DumpBackrefs = 1 << 0,
MSDF_NoAccessSpecifier = 1 << 1,
MSDF_NoCallingConvention = 1 << 2,
MSDF_NoReturnType = 1 << 3,
MSDF_NoMemberType = 1 << 4,
};
char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
int *status, MSDemangleFlags Flags = MSDF_None);
/// "Partial" demangler. This supports demangling a string into an AST
/// (typically an intermediate stage in itaniumDemangle) and querying certain
/// properties or partially printing the demangled name.
struct ItaniumPartialDemangler {
ItaniumPartialDemangler();
ItaniumPartialDemangler(ItaniumPartialDemangler &&Other);
ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other);
/// Demangle into an AST. Subsequent calls to the rest of the member functions
/// implicitly operate on the AST this produces.
/// \return true on error, false otherwise
bool partialDemangle(const char *MangledName);
/// Just print the entire mangled name into Buf. Buf and N behave like the
/// second and third parameters to itaniumDemangle.
char *finishDemangle(char *Buf, size_t *N) const;
/// Get the base name of a function. This doesn't include trailing template
/// arguments, ie for "a::b<int>" this function returns "b".
char *getFunctionBaseName(char *Buf, size_t *N) const;
/// Get the context name for a function. For "a::b::c", this function returns
/// "a::b".
char *getFunctionDeclContextName(char *Buf, size_t *N) const;
/// Get the entire name of this function.
char *getFunctionName(char *Buf, size_t *N) const;
/// Get the parameters for this function.
char *getFunctionParameters(char *Buf, size_t *N) const;
char *getFunctionReturnType(char *Buf, size_t *N) const;
/// If this function has any any cv or reference qualifiers. These imply that
/// the function is a non-static member function.
bool hasFunctionQualifiers() const;
/// If this symbol describes a constructor or destructor.
bool isCtorOrDtor() const;
/// If this symbol describes a function.
bool isFunction() const;
/// If this symbol describes a variable.
bool isData() const;
/// If this symbol is a <special-name>. These are generally implicitly
/// generated by the implementation, such as vtables and typeinfo names.
bool isSpecialName() const;
~ItaniumPartialDemangler();
private:
void *RootNode;
void *Context;
};
} // namespace llvm
#endif
+93
View File
@@ -0,0 +1,93 @@
//===--- DemangleConfig.h ---------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains a variety of feature test macros copied from
// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take
// a dependency on LLVMSupport.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_COMPILER_H
#define LLVM_DEMANGLE_COMPILER_H
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#ifndef __has_cpp_attribute
#define __has_cpp_attribute(x) 0
#endif
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#ifndef DEMANGLE_GNUC_PREREQ
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
((maj) << 20) + ((min) << 10) + (patch))
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
#else
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
#endif
#endif
#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
#else
#define DEMANGLE_ATTRIBUTE_USED
#endif
#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
#define DEMANGLE_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define DEMANGLE_UNREACHABLE __assume(false)
#else
#define DEMANGLE_UNREACHABLE
#endif
#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
#else
#define DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if !defined(NDEBUG)
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
#else
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
#define DEMANGLE_FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]]
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define DEMANGLE_FALLTHROUGH
#elif __has_cpp_attribute(clang::fallthrough)
#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
#else
#define DEMANGLE_FALLTHROUGH
#endif
#define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle {
#define DEMANGLE_NAMESPACE_END } }
#endif
File diff suppressed because it is too large Load Diff
+127
View File
@@ -0,0 +1,127 @@
//===--- StringView.h -------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// FIXME: Use std::string_view instead when we support C++17.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_STRINGVIEW_H
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
#include <algorithm>
#include <cassert>
#include <cstring>
DEMANGLE_NAMESPACE_BEGIN
class StringView {
const char *First;
const char *Last;
public:
static const size_t npos = ~size_t(0);
template <size_t N>
StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
StringView(const char *First_, const char *Last_)
: First(First_), Last(Last_) {}
StringView(const char *First_, size_t Len)
: First(First_), Last(First_ + Len) {}
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
StringView() : First(nullptr), Last(nullptr) {}
StringView substr(size_t From) const {
return StringView(begin() + From, size() - From);
}
size_t find(char C, size_t From = 0) const {
size_t FindBegin = std::min(From, size());
// Avoid calling memchr with nullptr.
if (FindBegin < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop.
if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
return size_t(static_cast<const char *>(P) - First);
}
return npos;
}
StringView substr(size_t From, size_t To) const {
if (To >= size())
To = size() - 1;
if (From >= size())
From = size() - 1;
return StringView(First + From, First + To);
}
StringView dropFront(size_t N = 1) const {
if (N >= size())
N = size();
return StringView(First + N, Last);
}
StringView dropBack(size_t N = 1) const {
if (N >= size())
N = size();
return StringView(First, Last - N);
}
char front() const {
assert(!empty());
return *begin();
}
char back() const {
assert(!empty());
return *(end() - 1);
}
char popFront() {
assert(!empty());
return *First++;
}
bool consumeFront(char C) {
if (!startsWith(C))
return false;
*this = dropFront(1);
return true;
}
bool consumeFront(StringView S) {
if (!startsWith(S))
return false;
*this = dropFront(S.size());
return true;
}
bool startsWith(char C) const { return !empty() && *begin() == C; }
bool startsWith(StringView Str) const {
if (Str.size() > size())
return false;
return std::equal(Str.begin(), Str.end(), begin());
}
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
const char *begin() const { return First; }
const char *end() const { return Last; }
size_t size() const { return static_cast<size_t>(Last - First); }
bool empty() const { return First == Last; }
};
inline bool operator==(const StringView &LHS, const StringView &RHS) {
return LHS.size() == RHS.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
}
DEMANGLE_NAMESPACE_END
#endif
+192
View File
@@ -0,0 +1,192 @@
//===--- Utility.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Provide some utility classes for use in the demangler(s).
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H
#include "StringView.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <limits>
DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputStream {
char *Buffer;
size_t CurrentPosition;
size_t BufferCapacity;
// Ensure there is at least n more positions in buffer.
void grow(size_t N) {
if (N + CurrentPosition >= BufferCapacity) {
BufferCapacity *= 2;
if (BufferCapacity < N + CurrentPosition)
BufferCapacity = N + CurrentPosition;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
void writeUnsigned(uint64_t N, bool isNeg = false) {
// Handle special case...
if (N == 0) {
*this << '0';
return;
}
char Temp[21];
char *TempPtr = std::end(Temp);
while (N) {
*--TempPtr = '0' + char(N % 10);
N /= 10;
}
// Add negative sign...
if (isNeg)
*--TempPtr = '-';
this->operator<<(StringView(TempPtr, std::end(Temp)));
}
public:
OutputStream(char *StartBuf, size_t Size)
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
OutputStream() = default;
void reset(char *Buffer_, size_t BufferCapacity_) {
CurrentPosition = 0;
Buffer = Buffer_;
BufferCapacity = BufferCapacity_;
}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
OutputStream &operator+=(StringView R) {
size_t Size = R.size();
if (Size == 0)
return *this;
grow(Size);
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
CurrentPosition += Size;
return *this;
}
OutputStream &operator+=(char C) {
grow(1);
Buffer[CurrentPosition++] = C;
return *this;
}
OutputStream &operator<<(StringView R) { return (*this += R); }
OutputStream &operator<<(char C) { return (*this += C); }
OutputStream &operator<<(long long N) {
if (N < 0)
writeUnsigned(static_cast<unsigned long long>(-N), true);
else
writeUnsigned(static_cast<unsigned long long>(N));
return *this;
}
OutputStream &operator<<(unsigned long long N) {
writeUnsigned(N, false);
return *this;
}
OutputStream &operator<<(long N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
OutputStream &operator<<(int N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
}
bool empty() const { return CurrentPosition == 0; }
char *getBuffer() { return Buffer; }
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
size_t getBufferCapacity() { return BufferCapacity; }
};
template <class T> class SwapAndRestore {
T &Restore;
T OriginalValue;
bool ShouldRestore = true;
public:
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
SwapAndRestore(T &Restore_, T NewVal)
: Restore(Restore_), OriginalValue(Restore) {
Restore = std::move(NewVal);
}
~SwapAndRestore() {
if (ShouldRestore)
Restore = std::move(OriginalValue);
}
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
void restoreNow(bool Force) {
if (!Force && !ShouldRestore)
return;
Restore = std::move(OriginalValue);
ShouldRestore = false;
}
SwapAndRestore(const SwapAndRestore &) = delete;
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
};
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
size_t InitSize) {
size_t BufferSize;
if (Buf == nullptr) {
Buf = static_cast<char *>(std::malloc(InitSize));
if (Buf == nullptr)
return false;
BufferSize = InitSize;
} else
BufferSize = *N;
S.reset(Buf, BufferSize);
return true;
}
DEMANGLE_NAMESPACE_END
#endif
@@ -20,25 +20,25 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
const u32 target_sample_count, const u32 source_sample_count,
UpsamplerState* state) {
constexpr u32 WindowSize = 10;
constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow1{
51.93359375f, -18.80078125f, 9.73046875f, -5.33203125f, 2.84375f,
-1.41015625f, 0.62109375f, -0.2265625f, 0.0625f, -0.00390625f,
constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc1{
0.95376587f, -0.12872314f, 0.060028076f, -0.032470703f, 0.017669678f,
-0.009124756f, 0.004272461f, -0.001739502f, 0.000579834f, -0.000091552734f,
};
constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow2{
105.35546875f, -24.52734375f, 11.9609375f, -6.515625f, 3.52734375f,
-1.796875f, 0.828125f, -0.32421875f, 0.1015625f, -0.015625f,
constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc2{
0.8230896f, -0.19161987f, 0.093444824f, -0.05090332f, 0.027557373f,
-0.014038086f, 0.0064697266f, -0.002532959f, 0.00079345703f, -0.00012207031f,
};
constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow3{
122.08203125f, -16.47656250f, 7.68359375f, -4.15625000f, 2.26171875f,
-1.16796875f, 0.54687500f, -0.22265625f, 0.07421875f, -0.01171875f,
constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc3{
0.6298828f, -0.19274902f, 0.09725952f, -0.05319214f, 0.028625488f,
-0.014373779f, 0.006500244f, -0.0024719238f, 0.0007324219f, -0.000091552734f,
};
constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow4{
23.73437500f, -9.62109375f, 5.07812500f, -2.78125000f, 1.46875000f,
-0.71484375f, 0.30859375f, -0.10546875f, 0.02734375f, 0.00000000f,
constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc4{
0.4057312f, -0.1468811f, 0.07601929f, -0.041656494f, 0.022216797f,
-0.011016846f, 0.004852295f, -0.0017700195f, 0.00048828125f, -0.000030517578f,
};
constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow5{
80.62500000f, -24.67187500f, 12.44921875f, -6.80859375f, 3.66406250f,
-1.83984375f, 0.83203125f, -0.31640625f, 0.09375000f, -0.01171875f,
constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc5{
0.1854248f, -0.075164795f, 0.03967285f, -0.021728516f, 0.011474609f,
-0.005584717f, 0.0024108887f, -0.0008239746f, 0.00021362305f, 0.0f,
};
if (!state->initialized) {
@@ -91,52 +91,31 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize);
};
auto calculate_sample = [&state](std::span<const Common::FixedPoint<24, 8>> coeffs1,
std::span<const Common::FixedPoint<24, 8>> coeffs2) -> s32 {
auto calculate_sample = [&state](std::span<const Common::FixedPoint<17, 15>> coeffs1,
std::span<const Common::FixedPoint<17, 15>> coeffs2) -> s32 {
auto output_index{state->history_output_index};
auto start_pos{output_index - state->history_start_index + 1U};
auto end_pos{10U};
u64 result{0};
if (start_pos < 10) {
end_pos = start_pos;
}
for (u32 coeff_index = 0; coeff_index < 10; coeff_index++) {
result += static_cast<u64>(state->history[output_index].to_raw()) *
coeffs1[coeff_index].to_raw();
u64 prev_contrib{0};
u32 coeff_index{0};
for (; coeff_index < end_pos; coeff_index++, output_index--) {
prev_contrib += static_cast<u64>(state->history[output_index].to_raw()) *
coeffs1[coeff_index].to_raw();
}
auto end_index{state->history_end_index};
for (; start_pos < 9; start_pos++, coeff_index++, end_index--) {
prev_contrib += static_cast<u64>(state->history[end_index].to_raw()) *
coeffs1[coeff_index].to_raw();
output_index = output_index == state->history_start_index ? state->history_end_index
: output_index - 1;
}
output_index =
static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize);
start_pos = state->history_end_index - output_index + 1U;
end_pos = 10U;
if (start_pos < 10) {
end_pos = start_pos;
for (u32 coeff_index = 0; coeff_index < 10; coeff_index++) {
result += static_cast<u64>(state->history[output_index].to_raw()) *
coeffs2[coeff_index].to_raw();
output_index = output_index == state->history_end_index ? state->history_start_index
: output_index + 1;
}
u64 next_contrib{0};
coeff_index = 0;
for (; coeff_index < end_pos; coeff_index++, output_index++) {
next_contrib += static_cast<u64>(state->history[output_index].to_raw()) *
coeffs2[coeff_index].to_raw();
}
auto start_index{state->history_start_index};
for (; start_pos < 9; start_pos++, start_index++, coeff_index++) {
next_contrib += static_cast<u64>(state->history[start_index].to_raw()) *
coeffs2[coeff_index].to_raw();
}
return static_cast<s32>(((prev_contrib >> 15) + (next_contrib >> 15)) >> 8);
return static_cast<s32>(result >> (8 + 15));
};
switch (state->ratio.to_int_floor()) {
@@ -150,23 +129,23 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
break;
case 1:
output[write_index] = calculate_sample(SincWindow3, SincWindow4);
output[write_index] = calculate_sample(WindowedSinc1, WindowedSinc5);
break;
case 2:
output[write_index] = calculate_sample(SincWindow2, SincWindow1);
output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
break;
case 3:
output[write_index] = calculate_sample(SincWindow5, SincWindow5);
output[write_index] = calculate_sample(WindowedSinc3, WindowedSinc3);
break;
case 4:
output[write_index] = calculate_sample(SincWindow1, SincWindow2);
output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
break;
case 5:
output[write_index] = calculate_sample(SincWindow4, SincWindow3);
output[write_index] = calculate_sample(WindowedSinc5, WindowedSinc1);
break;
}
state->sample_index = static_cast<u8>((state->sample_index + 1) % 6);
@@ -183,11 +162,11 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
break;
case 1:
output[write_index] = calculate_sample(SincWindow2, SincWindow1);
output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
break;
case 2:
output[write_index] = calculate_sample(SincWindow1, SincWindow2);
output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
break;
}
state->sample_index = static_cast<u8>((state->sample_index + 1) % 3);
@@ -204,12 +183,12 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
break;
case 1:
output[write_index] = calculate_sample(SincWindow1, SincWindow2);
output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
break;
case 2:
increment();
output[write_index] = calculate_sample(SincWindow2, SincWindow1);
output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
break;
}
state->sample_index = static_cast<u8>((state->sample_index + 1) % 3);
+4 -1
View File
@@ -38,6 +38,8 @@ add_library(common STATIC
common_precompiled_headers.h
common_types.h
concepts.h
demangle.cpp
demangle.h
div_ceil.h
dynamic_library.cpp
dynamic_library.h
@@ -97,6 +99,7 @@ add_library(common STATIC
point.h
precompiled_headers.h
quaternion.h
range_map.h
reader_writer_queue.h
ring_buffer.h
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
@@ -174,7 +177,7 @@ endif()
create_target_directory_groups(common)
target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile Threads::Threads)
target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd)
target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle)
if (YUZU_USE_PRECOMPILED_HEADERS)
target_precompile_headers(common PRIVATE precompiled_headers.h)
+4 -3
View File
@@ -12,7 +12,8 @@
namespace Common {
template <typename VaType, size_t AddressSpaceBits>
concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >= AddressSpaceBits;
concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >=
AddressSpaceBits;
struct EmptyStruct {};
@@ -21,7 +22,7 @@ struct EmptyStruct {};
*/
template <typename VaType, VaType UnmappedVa, typename PaType, PaType UnmappedPa,
bool PaContigSplit, size_t AddressSpaceBits, typename ExtraBlockInfo = EmptyStruct>
requires AddressSpaceValid<VaType, AddressSpaceBits>
requires AddressSpaceValid<VaType, AddressSpaceBits>
class FlatAddressSpaceMap {
public:
/// The maximum VA that this AS can technically reach
@@ -109,7 +110,7 @@ private:
* initial, fast linear pass and a subsequent slower pass that iterates until it finds a free block
*/
template <typename VaType, VaType UnmappedVa, size_t AddressSpaceBits>
requires AddressSpaceValid<VaType, AddressSpaceBits>
requires AddressSpaceValid<VaType, AddressSpaceBits>
class FlatAllocator
: public FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits> {
private:
+9 -9
View File
@@ -10,7 +10,7 @@
namespace Common {
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignUp(T value, size_t size) {
auto mod{static_cast<T>(value % size)};
value -= mod;
@@ -18,31 +18,31 @@ requires std::is_unsigned_v<T>
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignDown(T value, size_t size) {
return static_cast<T>(value - value % size);
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool Is4KBAligned(T value) {
return (value & 0xFFF) == 0;
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool IsWordAligned(T value) {
return (value & 0b11) == 0;
}
template <typename T>
requires std::is_integral_v<T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
using U = typename std::make_unsigned_t<T>;
const U mask = static_cast<U>(alignment - 1);
@@ -50,7 +50,7 @@ requires std::is_integral_v<T>
}
template <typename T, typename U>
requires std::is_integral_v<T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr T DivideUp(T x, U y) {
return (x + (y - 1)) / y;
}
@@ -73,11 +73,11 @@ public:
constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
[[nodiscard]] T* allocate(size_type n) {
return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
return static_cast<T*>(::operator new(n * sizeof(T), std::align_val_t{Align}));
}
void deallocate(T* p, size_type n) {
::operator delete (p, n * sizeof(T), std::align_val_t{Align});
::operator delete(p, n * sizeof(T), std::align_val_t{Align});
}
template <typename T2>
+1 -1
View File
@@ -75,7 +75,7 @@ extern "C" void AnnotateHappensAfter(const char*, int, void*);
#if defined(AE_VCPP) || defined(AE_ICC)
#define AE_FORCEINLINE __forceinline
#elif defined(AE_GCC)
//#define AE_FORCEINLINE __attribute__((always_inline))
// #define AE_FORCEINLINE __attribute__((always_inline))
#define AE_FORCEINLINE inline
#else
#define AE_FORCEINLINE inline
+3 -3
View File
@@ -45,19 +45,19 @@ template <typename T>
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool IsPow2(T value) {
return std::has_single_bit(value);
}
template <typename T>
requires std::is_integral_v<T>
requires std::is_integral_v<T>
[[nodiscard]] T NextPow2(T value) {
return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
}
template <size_t bit_index, typename T>
requires std::is_integral_v<T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr bool Bit(const T value) {
static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T");
return ((value >> bit_index) & T(1)) == T(1);
+3 -3
View File
@@ -16,9 +16,9 @@ concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>;
// is available on all supported platforms.
template <typename Derived, typename Base>
concept DerivedFrom = requires {
std::is_base_of_v<Base, Derived>;
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
};
std::is_base_of_v<Base, Derived>;
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
};
// TODO: Replace with std::convertible_to when libc++ implements it.
template <typename From, typename To>
+35
View File
@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <llvm/Demangle/Demangle.h>
#include "common/demangle.h"
#include "common/scope_exit.h"
namespace Common {
std::string DemangleSymbol(const std::string& mangled) {
auto is_itanium = [](const std::string& name) -> bool {
// A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'.
auto pos = name.find_first_not_of('_');
return pos > 0 && pos <= 4 && pos < name.size() && name[pos] == 'Z';
};
if (mangled.empty()) {
return mangled;
}
char* demangled = nullptr;
SCOPE_EXIT({ std::free(demangled); });
if (is_itanium(mangled)) {
demangled = llvm::itaniumDemangle(mangled.c_str(), nullptr, nullptr, nullptr);
}
if (!demangled) {
return mangled;
}
return demangled;
}
} // namespace Common
+12
View File
@@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
namespace Common {
std::string DemangleSymbol(const std::string& mangled);
} // namespace Common
+2 -2
View File
@@ -10,14 +10,14 @@ namespace Common {
/// Ceiled integer division.
template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D>
requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeil(N number, D divisor) {
return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
}
/// Ceiled integer division with logarithmic divisor in base 2
template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D>
requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
}
+30 -30
View File
@@ -64,7 +64,7 @@ struct no_init_t {
* Additionally, this requires E to be trivially destructible
*/
template <typename T, typename E, bool = std::is_trivially_destructible_v<T>>
requires std::is_trivially_destructible_v<E>
requires std::is_trivially_destructible_v<E>
struct expected_storage_base {
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
@@ -111,7 +111,7 @@ struct expected_storage_base {
* Additionally, this requires E to be trivially destructible
*/
template <typename T, typename E>
requires std::is_trivially_destructible_v<E>
requires std::is_trivially_destructible_v<E>
struct expected_storage_base<T, E, true> {
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
@@ -251,7 +251,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
* Additionally, this requires E to be trivially copy constructible
*/
template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>>
requires std::is_trivially_copy_constructible_v<E>
requires std::is_trivially_copy_constructible_v<E>
struct expected_copy_base : expected_operations_base<T, E> {
using expected_operations_base<T, E>::expected_operations_base;
};
@@ -261,7 +261,7 @@ struct expected_copy_base : expected_operations_base<T, E> {
* Additionally, this requires E to be trivially copy constructible
*/
template <typename T, typename E>
requires std::is_trivially_copy_constructible_v<E>
requires std::is_trivially_copy_constructible_v<E>
struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
using expected_operations_base<T, E>::expected_operations_base;
@@ -289,7 +289,7 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
* Additionally, this requires E to be trivially move constructible
*/
template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>>
requires std::is_trivially_move_constructible_v<E>
requires std::is_trivially_move_constructible_v<E>
struct expected_move_base : expected_copy_base<T, E> {
using expected_copy_base<T, E>::expected_copy_base;
};
@@ -299,7 +299,7 @@ struct expected_move_base : expected_copy_base<T, E> {
* Additionally, this requires E to be trivially move constructible
*/
template <typename T, typename E>
requires std::is_trivially_move_constructible_v<E>
requires std::is_trivially_move_constructible_v<E>
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
using expected_copy_base<T, E>::expected_copy_base;
@@ -330,9 +330,9 @@ template <typename T, typename E,
bool = std::conjunction_v<std::is_trivially_copy_assignable<T>,
std::is_trivially_copy_constructible<T>,
std::is_trivially_destructible<T>>>
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
std::is_trivially_copy_constructible<E>,
std::is_trivially_destructible<E>>
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
std::is_trivially_copy_constructible<E>,
std::is_trivially_destructible<E>>
struct expected_copy_assign_base : expected_move_base<T, E> {
using expected_move_base<T, E>::expected_move_base;
};
@@ -342,9 +342,9 @@ struct expected_copy_assign_base : expected_move_base<T, E> {
* Additionally, this requires E to be trivially copy assignable
*/
template <typename T, typename E>
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
std::is_trivially_copy_constructible<E>,
std::is_trivially_destructible<E>>
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
std::is_trivially_copy_constructible<E>,
std::is_trivially_destructible<E>>
struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
using expected_move_base<T, E>::expected_move_base;
@@ -371,9 +371,9 @@ template <typename T, typename E,
bool = std::conjunction_v<std::is_trivially_move_assignable<T>,
std::is_trivially_move_constructible<T>,
std::is_trivially_destructible<T>>>
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
std::is_trivially_move_constructible<E>,
std::is_trivially_destructible<E>>
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
std::is_trivially_move_constructible<E>,
std::is_trivially_destructible<E>>
struct expected_move_assign_base : expected_copy_assign_base<T, E> {
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
};
@@ -383,9 +383,9 @@ struct expected_move_assign_base : expected_copy_assign_base<T, E> {
* Additionally, this requires E to be trivially move assignable
*/
template <typename T, typename E>
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
std::is_trivially_move_constructible<E>,
std::is_trivially_destructible<E>>
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
std::is_trivially_move_constructible<E>,
std::is_trivially_destructible<E>>
struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> {
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
@@ -412,7 +412,7 @@ struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E>
*/
template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>,
bool EnableMove = std::is_move_constructible_v<T>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
@@ -422,7 +422,7 @@ struct expected_delete_ctor_base {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, true, false> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
@@ -432,7 +432,7 @@ struct expected_delete_ctor_base<T, E, true, false> {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, false, true> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
@@ -442,7 +442,7 @@ struct expected_delete_ctor_base<T, E, false, true> {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, false, false> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
@@ -460,8 +460,8 @@ template <
typename T, typename E,
bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>,
bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -471,8 +471,8 @@ struct expected_delete_assign_base {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, true, false> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -482,8 +482,8 @@ struct expected_delete_assign_base<T, E, true, false> {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, false, true> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -493,8 +493,8 @@ struct expected_delete_assign_base<T, E, false, true> {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, false, false> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
+43 -30
View File
@@ -51,6 +51,8 @@ enum class PollingMode {
NFC,
// Enable infrared camera polling
IR,
// Enable ring controller polling
Ring,
};
enum class CameraFormat {
@@ -62,21 +64,22 @@ enum class CameraFormat {
None,
};
// Vibration reply from the controller
enum class VibrationError {
None,
// Different results that can happen from a device request
enum class DriverResult {
Success,
WrongReply,
Timeout,
UnsupportedControllerType,
HandleInUse,
ErrorReadingData,
ErrorWritingData,
NoDeviceDetected,
InvalidHandle,
NotSupported,
Disabled,
Unknown,
};
// Polling mode reply from the controller
enum class PollingError {
None,
NotSupported,
Unknown,
};
// Nfc reply from the controller
enum class NfcState {
Success,
@@ -90,13 +93,6 @@ enum class NfcState {
Unknown,
};
// Ir camera reply from the controller
enum class CameraError {
None,
NotSupported,
Unknown,
};
// Hint for amplification curve to be used
enum class VibrationAmplificationType {
Linear,
@@ -134,6 +130,8 @@ struct ButtonStatus {
bool inverted{};
// Press once to activate, press again to release
bool toggle{};
// Spams the button when active
bool turbo{};
// Internal lock for the toggle status
bool locked{};
};
@@ -190,6 +188,8 @@ struct TouchStatus {
struct BodyColorStatus {
u32 body{};
u32 buttons{};
u32 left_grip{};
u32 right_grip{};
};
// HD rumble data
@@ -228,17 +228,31 @@ enum class ButtonNames {
Engine,
// This will display the button by value instead of the button name
Value,
// Joycon button names
ButtonLeft,
ButtonRight,
ButtonDown,
ButtonUp,
TriggerZ,
TriggerR,
TriggerL,
ButtonA,
ButtonB,
ButtonX,
ButtonY,
ButtonPlus,
ButtonMinus,
ButtonHome,
ButtonCapture,
ButtonStickL,
ButtonStickR,
TriggerL,
TriggerZL,
TriggerSL,
TriggerR,
TriggerZR,
TriggerSR,
// GC button names
TriggerZ,
ButtonStart,
// DS4 button names
@@ -292,9 +306,6 @@ class InputDevice {
public:
virtual ~InputDevice() = default;
// Request input device to update if necessary
virtual void SoftUpdate() {}
// Force input device to update data regardless of the current state
virtual void ForceUpdate() {}
@@ -319,22 +330,24 @@ class OutputDevice {
public:
virtual ~OutputDevice() = default;
virtual void SetLED([[maybe_unused]] const LedStatus& led_status) {}
virtual DriverResult SetLED([[maybe_unused]] const LedStatus& led_status) {
return DriverResult::NotSupported;
}
virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {
return VibrationError::NotSupported;
virtual DriverResult SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {
return DriverResult::NotSupported;
}
virtual bool IsVibrationEnabled() {
return false;
}
virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
return PollingError::NotSupported;
virtual DriverResult SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
return DriverResult::NotSupported;
}
virtual CameraError SetCameraFormat([[maybe_unused]] CameraFormat camera_format) {
return CameraError::NotSupported;
virtual DriverResult SetCameraFormat([[maybe_unused]] CameraFormat camera_format) {
return DriverResult::NotSupported;
}
virtual NfcState SupportsNfc() const {
+11 -9
View File
@@ -242,19 +242,21 @@ public:
template <typename T>
concept HasRedBlackKeyType = requires {
{ std::is_same<typename T::RedBlackKeyType, void>::value } -> std::convertible_to<bool>;
};
{
std::is_same<typename T::RedBlackKeyType, void>::value
} -> std::convertible_to<bool>;
};
namespace impl {
template <typename T, typename Default>
consteval auto* GetRedBlackKeyType() {
if constexpr (HasRedBlackKeyType<T>) {
return static_cast<typename T::RedBlackKeyType*>(nullptr);
} else {
return static_cast<Default*>(nullptr);
}
template <typename T, typename Default>
consteval auto* GetRedBlackKeyType() {
if constexpr (HasRedBlackKeyType<T>) {
return static_cast<typename T::RedBlackKeyType*>(nullptr);
} else {
return static_cast<Default*>(nullptr);
}
}
} // namespace impl
+5 -3
View File
@@ -9,17 +9,19 @@
namespace Common {
template <class T>
requires(!std::is_array_v<T>) std::unique_ptr<T> make_unique_for_overwrite() {
requires(!std::is_array_v<T>)
std::unique_ptr<T> make_unique_for_overwrite() {
return std::unique_ptr<T>(new T);
}
template <class T>
requires std::is_unbounded_array_v<T> std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
requires std::is_unbounded_array_v<T>
std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
return std::unique_ptr<T>(new std::remove_extent_t<T>[n]);
}
template <class T, class... Args>
requires std::is_bounded_array_v<T>
requires std::is_bounded_array_v<T>
void make_unique_for_overwrite(Args&&...) = delete;
} // namespace Common
+4 -4
View File
@@ -18,9 +18,9 @@ namespace ranges {
template <typename T>
concept range = requires(T& t) {
begin(t);
end(t);
};
begin(t);
end(t);
};
template <typename T>
concept input_range = range<T>;
@@ -421,7 +421,7 @@ struct generate_fn {
}
template <typename R, std::copy_constructible F>
requires std::invocable<F&> && ranges::output_range<R>
requires std::invocable<F&> && ranges::output_range<R>
constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const {
return operator()(ranges::begin(r), ranges::end(r), std::move(gen));
}
+86 -41
View File
@@ -11,6 +11,8 @@
#ifdef __cpp_lib_jthread
#include <chrono>
#include <condition_variable>
#include <stop_token>
#include <thread>
@@ -21,23 +23,36 @@ void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) {
cv.wait(lock, token, std::move(pred));
}
template <typename Rep, typename Period>
bool StoppableTimedWait(std::stop_token token, const std::chrono::duration<Rep, Period>& rel_time) {
std::condition_variable_any cv;
std::mutex m;
// Perform the timed wait.
std::unique_lock lk{m};
return !cv.wait_for(lk, token, rel_time, [&] { return token.stop_requested(); });
}
} // namespace Common
#else
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include <type_traits>
#include <utility>
namespace std {
namespace polyfill {
using stop_state_callbacks = list<function<void()>>;
using stop_state_callback = size_t;
class stop_state {
public:
@@ -45,61 +60,69 @@ public:
~stop_state() = default;
bool request_stop() {
stop_state_callbacks callbacks;
unique_lock lk{m_lock};
{
scoped_lock lk{m_lock};
if (m_stop_requested.load()) {
// Already set, nothing to do
return false;
}
// Set as requested
m_stop_requested = true;
// Copy callback list
callbacks = m_callbacks;
if (m_stop_requested) {
// Already set, nothing to do.
return false;
}
for (auto callback : callbacks) {
callback();
// Mark stop requested.
m_stop_requested = true;
while (!m_callbacks.empty()) {
// Get an iterator to the first element.
const auto it = m_callbacks.begin();
// Move the callback function out of the map.
function<void()> f;
swap(it->second, f);
// Erase the now-empty map element.
m_callbacks.erase(it);
// Run the callback.
if (f) {
f();
}
}
return true;
}
bool stop_requested() const {
return m_stop_requested.load();
unique_lock lk{m_lock};
return m_stop_requested;
}
stop_state_callbacks::const_iterator insert_callback(function<void()> f) {
stop_state_callbacks::const_iterator ret{};
bool should_run{};
stop_state_callback insert_callback(function<void()> f) {
unique_lock lk{m_lock};
{
scoped_lock lk{m_lock};
should_run = m_stop_requested.load();
m_callbacks.push_front(f);
ret = m_callbacks.begin();
}
if (should_run) {
f();
if (m_stop_requested) {
// Stop already requested. Don't insert anything,
// just run the callback synchronously.
if (f) {
f();
}
return 0;
}
// Insert the callback.
stop_state_callback ret = ++m_next_callback;
m_callbacks.emplace(ret, move(f));
return ret;
}
void remove_callback(stop_state_callbacks::const_iterator it) {
scoped_lock lk{m_lock};
m_callbacks.erase(it);
void remove_callback(stop_state_callback cb) {
unique_lock lk{m_lock};
m_callbacks.erase(cb);
}
private:
mutex m_lock;
atomic<bool> m_stop_requested;
stop_state_callbacks m_callbacks;
mutable recursive_mutex m_lock;
map<stop_state_callback, function<void()>> m_callbacks;
stop_state_callback m_next_callback{0};
bool m_stop_requested{false};
};
} // namespace polyfill
@@ -190,7 +213,7 @@ public:
using callback_type = Callback;
template <typename C>
requires constructible_from<Callback, C>
requires constructible_from<Callback, C>
explicit stop_callback(const stop_token& st,
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(st.m_stop_state) {
@@ -199,7 +222,7 @@ public:
}
}
template <typename C>
requires constructible_from<Callback, C>
requires constructible_from<Callback, C>
explicit stop_callback(stop_token&& st,
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(move(st.m_stop_state)) {
@@ -209,7 +232,7 @@ public:
}
~stop_callback() {
if (m_stop_state && m_callback) {
m_stop_state->remove_callback(*m_callback);
m_stop_state->remove_callback(m_callback);
}
}
@@ -220,7 +243,7 @@ public:
private:
shared_ptr<polyfill::stop_state> m_stop_state;
optional<polyfill::stop_state_callbacks::const_iterator> m_callback;
polyfill::stop_state_callback m_callback;
};
template <typename Callback>
@@ -318,6 +341,28 @@ void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred pred) {
cv.wait(lock, [&] { return pred() || token.stop_requested(); });
}
template <typename Rep, typename Period>
bool StoppableTimedWait(std::stop_token token, const std::chrono::duration<Rep, Period>& rel_time) {
if (token.stop_requested()) {
return false;
}
bool stop_requested = false;
std::condition_variable cv;
std::mutex m;
std::stop_callback cb(token, [&] {
// Wake up the waiting thread.
std::unique_lock lk{m};
stop_requested = true;
cv.notify_one();
});
// Perform the timed wait.
std::unique_lock lk{m};
return !cv.wait_for(lk, rel_time, [&] { return stop_requested; });
}
} // namespace Common
#endif
+139
View File
@@ -0,0 +1,139 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <map>
#include <type_traits>
#include "common/common_types.h"
namespace Common {
template <typename KeyTBase, typename ValueT>
class RangeMap {
private:
using KeyT =
std::conditional_t<std::is_signed_v<KeyTBase>, KeyTBase, std::make_signed_t<KeyTBase>>;
public:
explicit RangeMap(ValueT null_value_) : null_value{null_value_} {
container.emplace(std::numeric_limits<KeyT>::min(), null_value);
};
~RangeMap() = default;
void Map(KeyTBase address, KeyTBase address_end, ValueT value) {
KeyT new_address = static_cast<KeyT>(address);
KeyT new_address_end = static_cast<KeyT>(address_end);
if (new_address < 0) {
new_address = 0;
}
if (new_address_end < 0) {
new_address_end = 0;
}
InternalMap(new_address, new_address_end, value);
}
void Unmap(KeyTBase address, KeyTBase address_end) {
Map(address, address_end, null_value);
}
[[nodiscard]] size_t GetContinousSizeFrom(KeyTBase address) const {
const KeyT new_address = static_cast<KeyT>(address);
if (new_address < 0) {
return 0;
}
return ContinousSizeInternal(new_address);
}
[[nodiscard]] ValueT GetValueAt(KeyT address) const {
const KeyT new_address = static_cast<KeyT>(address);
if (new_address < 0) {
return null_value;
}
return GetValueInternal(new_address);
}
private:
using MapType = std::map<KeyT, ValueT>;
using IteratorType = typename MapType::iterator;
using ConstIteratorType = typename MapType::const_iterator;
size_t ContinousSizeInternal(KeyT address) const {
const auto it = GetFirstElementBeforeOrOn(address);
if (it == container.end() || it->second == null_value) {
return 0;
}
const auto it_end = std::next(it);
if (it_end == container.end()) {
return std::numeric_limits<KeyT>::max() - address;
}
return it_end->first - address;
}
ValueT GetValueInternal(KeyT address) const {
const auto it = GetFirstElementBeforeOrOn(address);
if (it == container.end()) {
return null_value;
}
return it->second;
}
ConstIteratorType GetFirstElementBeforeOrOn(KeyT address) const {
auto it = container.lower_bound(address);
if (it == container.begin()) {
return it;
}
if (it != container.end() && (it->first == address)) {
return it;
}
--it;
return it;
}
ValueT GetFirstValueWithin(KeyT address) {
auto it = container.lower_bound(address);
if (it == container.begin()) {
return it->second;
}
if (it == container.end()) [[unlikely]] { // this would be a bug
return null_value;
}
--it;
return it->second;
}
ValueT GetLastValueWithin(KeyT address) {
auto it = container.upper_bound(address);
if (it == container.end()) {
return null_value;
}
if (it == container.begin()) [[unlikely]] { // this would be a bug
return it->second;
}
--it;
return it->second;
}
void InternalMap(KeyT address, KeyT address_end, ValueT value) {
const bool must_add_start = GetFirstValueWithin(address) != value;
const ValueT last_value = GetLastValueWithin(address_end);
const bool must_add_end = last_value != value;
auto it = container.lower_bound(address);
const auto it_end = container.upper_bound(address_end);
while (it != it_end) {
it = container.erase(it);
}
if (must_add_start) {
container.emplace(address, value);
}
if (must_add_end) {
container.emplace(address_end, last_value);
}
}
ValueT null_value;
MapType container;
};
} // namespace Common
+14
View File
@@ -129,6 +129,10 @@ void UpdateRescalingInfo() {
info.up_scale = 1;
info.down_shift = 0;
break;
case ResolutionSetup::Res3_2X:
info.up_scale = 3;
info.down_shift = 1;
break;
case ResolutionSetup::Res2X:
info.up_scale = 2;
info.down_shift = 0;
@@ -149,6 +153,14 @@ void UpdateRescalingInfo() {
info.up_scale = 6;
info.down_shift = 0;
break;
case ResolutionSetup::Res7X:
info.up_scale = 7;
info.down_shift = 0;
break;
case ResolutionSetup::Res8X:
info.up_scale = 8;
info.down_shift = 0;
break;
default:
ASSERT(false);
info.up_scale = 1;
@@ -185,6 +197,7 @@ void RestoreGlobalState(bool is_powered_on) {
// Renderer
values.fsr_sharpening_slider.SetGlobal(true);
values.renderer_backend.SetGlobal(true);
values.renderer_force_max_clock.SetGlobal(true);
values.vulkan_device.SetGlobal(true);
values.aspect_ratio.SetGlobal(true);
values.max_anisotropy.SetGlobal(true);
@@ -200,6 +213,7 @@ void RestoreGlobalState(bool is_powered_on) {
values.use_asynchronous_shaders.SetGlobal(true);
values.use_fast_gpu_time.SetGlobal(true);
values.use_pessimistic_flushes.SetGlobal(true);
values.use_vulkan_driver_pipeline_cache.SetGlobal(true);
values.bg_red.SetGlobal(true);
values.bg_green.SetGlobal(true);
values.bg_blue.SetGlobal(true);
+21 -9
View File
@@ -56,11 +56,14 @@ enum class ResolutionSetup : u32 {
Res1_2X = 0,
Res3_4X = 1,
Res1X = 2,
Res2X = 3,
Res3X = 4,
Res4X = 5,
Res5X = 6,
Res6X = 7,
Res3_2X = 3,
Res2X = 4,
Res3X = 5,
Res4X = 6,
Res5X = 7,
Res6X = 8,
Res7X = 9,
Res8X = 10,
};
enum class ScalingFilter : u32 {
@@ -128,7 +131,8 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const std::string& name) requires(!ranged)
explicit Setting(const Type& default_val, const std::string& name)
requires(!ranged)
: value{default_val}, default_value{default_val}, label{name} {}
virtual ~Setting() = default;
@@ -141,7 +145,8 @@ public:
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name) requires(ranged)
const std::string& name)
requires(ranged)
: value{default_val},
default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
@@ -229,7 +234,8 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
explicit SwitchableSetting(const Type& default_val, const std::string& name) requires(!ranged)
explicit SwitchableSetting(const Type& default_val, const std::string& name)
requires(!ranged)
: Setting<Type>{default_val, name} {}
virtual ~SwitchableSetting() = default;
@@ -242,7 +248,8 @@ public:
* @param name Label for the setting
*/
explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name) requires(ranged)
const std::string& name)
requires(ranged)
: Setting<Type, true>{default_val, min_val, max_val, name} {}
/**
@@ -415,6 +422,7 @@ struct Values {
// Renderer
SwitchableSetting<RendererBackend, true> renderer_backend{
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};
SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"};
Setting<bool> renderer_debug{false, "debug"};
Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
@@ -451,6 +459,8 @@ struct Values {
SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
SwitchableSetting<bool> use_pessimistic_flushes{false, "use_pessimistic_flushes"};
SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true,
"use_vulkan_driver_pipeline_cache"};
SwitchableSetting<u8> bg_red{0, "bg_red"};
SwitchableSetting<u8> bg_green{0, "bg_green"};
@@ -477,6 +487,7 @@ struct Values {
Setting<bool> enable_raw_input{false, "enable_raw_input"};
Setting<bool> controller_navigation{true, "controller_navigation"};
Setting<bool> enable_joycon_driver{true, "enable_joycon_driver"};
SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"};
SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
@@ -531,6 +542,7 @@ struct Values {
Setting<bool> reporting_services{false, "reporting_services"};
Setting<bool> quest_flag{false, "quest_flag"};
Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
Setting<bool> disable_macro_hle{false, "disable_macro_hle"};
Setting<bool> extended_logging{false, "extended_logging"};
Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
Setting<bool> use_auto_stub{false, "use_auto_stub"};
+1 -1
View File
@@ -30,7 +30,7 @@ std::string ToUpper(std::string str) {
return str;
}
std::string StringFromBuffer(const std::vector<u8>& data) {
std::string StringFromBuffer(std::span<const u8> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
+2 -1
View File
@@ -5,6 +5,7 @@
#pragma once
#include <cstddef>
#include <span>
#include <string>
#include <vector>
#include "common/common_types.h"
@@ -17,7 +18,7 @@ namespace Common {
/// Make a string uppercase
[[nodiscard]] std::string ToUpper(std::string str);
[[nodiscard]] std::string StringFromBuffer(const std::vector<u8>& data);
[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
[[nodiscard]] std::string StripSpaces(const std::string& s);
[[nodiscard]] std::string StripQuotes(const std::string& s);
+37 -37
View File
@@ -103,12 +103,12 @@ concept IsRBEntry = CheckRBEntry<T>::value;
template <typename T>
concept HasRBEntry = requires(T& t, const T& ct) {
{ t.GetRBEntry() } -> std::same_as<RBEntry<T>&>;
{ ct.GetRBEntry() } -> std::same_as<const RBEntry<T>&>;
};
{ t.GetRBEntry() } -> std::same_as<RBEntry<T>&>;
{ ct.GetRBEntry() } -> std::same_as<const RBEntry<T>&>;
};
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
class RBHead {
private:
T* m_rbh_root = nullptr;
@@ -130,90 +130,90 @@ public:
};
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr RBEntry<T>& RB_ENTRY(T* t) {
return t->GetRBEntry();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr const RBEntry<T>& RB_ENTRY(const T* t) {
return t->GetRBEntry();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_LEFT(T* t) {
return RB_ENTRY(t).Left();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_LEFT(const T* t) {
return RB_ENTRY(t).Left();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_RIGHT(T* t) {
return RB_ENTRY(t).Right();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_RIGHT(const T* t) {
return RB_ENTRY(t).Right();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_PARENT(T* t) {
return RB_ENTRY(t).Parent();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_PARENT(const T* t) {
return RB_ENTRY(t).Parent();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_LEFT(T* t, T* e) {
RB_ENTRY(t).SetLeft(e);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_RIGHT(T* t, T* e) {
RB_ENTRY(t).SetRight(e);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_PARENT(T* t, T* e) {
RB_ENTRY(t).SetParent(e);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr bool RB_IS_BLACK(const T* t) {
return RB_ENTRY(t).IsBlack();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr bool RB_IS_RED(const T* t) {
return RB_ENTRY(t).IsRed();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr RBColor RB_COLOR(const T* t) {
return RB_ENTRY(t).Color();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_COLOR(T* t, RBColor c) {
RB_ENTRY(t).SetColor(c);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET(T* elm, T* parent) {
auto& rb_entry = RB_ENTRY(elm);
rb_entry.SetParent(parent);
@@ -223,14 +223,14 @@ constexpr void RB_SET(T* elm, T* parent) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_BLACKRED(T* black, T* red) {
RB_SET_COLOR(black, RBColor::RB_BLACK);
RB_SET_COLOR(red, RBColor::RB_RED);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) {
tmp = RB_RIGHT(elm);
if (RB_SET_RIGHT(elm, RB_LEFT(tmp)); RB_RIGHT(elm) != nullptr) {
@@ -252,7 +252,7 @@ constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) {
tmp = RB_LEFT(elm);
if (RB_SET_LEFT(elm, RB_RIGHT(tmp)); RB_LEFT(elm) != nullptr) {
@@ -274,7 +274,7 @@ constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) {
T* tmp;
while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head.Root()) {
@@ -358,7 +358,7 @@ constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) {
T* child = nullptr;
T* parent = nullptr;
@@ -451,7 +451,7 @@ constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) {
T *parent = nullptr, *tmp = nullptr;
while ((parent = RB_PARENT(elm)) != nullptr && RB_IS_RED(parent)) {
@@ -499,7 +499,7 @@ constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) {
}
template <typename T, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) {
T* parent = nullptr;
T* tmp = head.Root();
@@ -534,7 +534,7 @@ constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
@@ -553,7 +553,7 @@ constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
T* res = nullptr;
@@ -574,7 +574,7 @@ constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename U, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
@@ -593,7 +593,7 @@ constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T, typename U, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
T* res = nullptr;
@@ -614,7 +614,7 @@ constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
@@ -631,7 +631,7 @@ constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename U, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
@@ -648,7 +648,7 @@ constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_NEXT(T* elm) {
if (RB_RIGHT(elm)) {
elm = RB_RIGHT(elm);
@@ -669,7 +669,7 @@ constexpr T* RB_NEXT(T* elm) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_PREV(T* elm) {
if (RB_LEFT(elm)) {
elm = RB_LEFT(elm);
@@ -690,7 +690,7 @@ constexpr T* RB_PREV(T* elm) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_MIN(RBHead<T>& head) {
T* tmp = head.Root();
T* parent = nullptr;
@@ -704,7 +704,7 @@ constexpr T* RB_MIN(RBHead<T>& head) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_MAX(RBHead<T>& head) {
T* tmp = head.Root();
T* parent = nullptr;
+5 -11
View File
@@ -348,9 +348,7 @@ public:
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
// component names (x<->r) and permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
[[nodiscard]] constexpr Vec2<T> name() const { \
return Vec2<T>(a, b); \
}
[[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
_DEFINE_SWIZZLER2(a, b, a##b); \
_DEFINE_SWIZZLER2(a, b, a2##b2); \
@@ -543,9 +541,7 @@ public:
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
// permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
[[nodiscard]] constexpr Vec2<T> name() const { \
return Vec2<T>(a, b); \
}
[[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
_DEFINE_SWIZZLER2(a, a, a##a); \
_DEFINE_SWIZZLER2(a, a, a2##a2)
@@ -570,9 +566,7 @@ public:
#undef _DEFINE_SWIZZLER2
#define _DEFINE_SWIZZLER3(a, b, c, name) \
[[nodiscard]] constexpr Vec3<T> name() const { \
return Vec3<T>(a, b, c); \
}
[[nodiscard]] constexpr Vec3<T> name() const { return Vec3<T>(a, b, c); }
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
_DEFINE_SWIZZLER3(a, a, a, a##a##a); \
_DEFINE_SWIZZLER3(a, a, a, a2##a2##a2)
@@ -641,8 +635,8 @@ template <typename T>
// linear interpolation via float: 0.0=begin, 1.0=end
template <typename X>
[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{})
Lerp(const X& begin, const X& end, const float t) {
[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
const float t) {
return begin * (1.f - t) + end * t;
}
+2
View File
@@ -182,6 +182,8 @@ add_library(core STATIC
hle/kernel/k_auto_object_container.cpp
hle/kernel/k_auto_object_container.h
hle/kernel/k_affinity_mask.h
hle/kernel/k_capabilities.cpp
hle/kernel/k_capabilities.h
hle/kernel/k_class_token.cpp
hle/kernel/k_class_token.h
hle/kernel/k_client_port.cpp
+4 -18
View File
@@ -1,14 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef _MSC_VER
#include <cxxabi.h>
#endif
#include <map>
#include <optional>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/demangle.h"
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/arm/symbols.h"
@@ -71,20 +69,8 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
const auto symbol_set = symbols.find(entry.module);
if (symbol_set != symbols.end()) {
const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
if (symbol.has_value()) {
#ifdef _MSC_VER
// TODO(DarkLordZach): Add demangling of symbol names.
entry.name = *symbol;
#else
int status{-1};
char* demangled{abi::__cxa_demangle(symbol->c_str(), nullptr, nullptr, &status)};
if (status == 0 && demangled != nullptr) {
entry.name = demangled;
std::free(demangled);
} else {
entry.name = *symbol;
}
#endif
if (symbol) {
entry.name = Common::DemangleSymbol(*symbol);
}
}
}
@@ -229,7 +229,11 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
config.enable_cycle_counting = true;
// Code cache size
#ifdef ARCHITECTURE_arm64
config.code_cache_size = 128_MiB;
#else
config.code_cache_size = 512_MiB;
#endif
// Allow memory fault handling to work
if (system.DebuggerEnabled()) {
@@ -288,7 +288,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
config.enable_cycle_counting = true;
// Code cache size
#ifdef ARCHITECTURE_arm64
config.code_cache_size = 128_MiB;
#else
config.code_cache_size = 512_MiB;
#endif
// Allow memory fault handling to work
if (system.DebuggerEnabled()) {
+17 -23
View File
@@ -142,16 +142,24 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
}
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data) {
std::scoped_lock scope{basic_lock};
const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
return e.type.lock().get() == event_type.get() && e.user_data == user_data;
});
std::uintptr_t user_data, bool wait) {
{
std::scoped_lock lk{basic_lock};
const auto itr =
std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
return e.type.lock().get() == event_type.get() && e.user_data == user_data;
});
// Removing random items breaks the invariant so we have to re-establish it.
if (itr != event_queue.end()) {
event_queue.erase(itr, event_queue.end());
std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
// Removing random items breaks the invariant so we have to re-establish it.
if (itr != event_queue.end()) {
event_queue.erase(itr, event_queue.end());
std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
}
// Force any in-progress events to finish
if (wait) {
std::scoped_lock lk{advance_lock};
}
}
@@ -190,20 +198,6 @@ u64 CoreTiming::GetClockTicks() const {
return CpuCyclesToClockCycles(ticks);
}
void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
std::scoped_lock lock{basic_lock};
const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
return e.type.lock().get() == event_type.get();
});
// Removing random items breaks the invariant so we have to re-establish it.
if (itr != event_queue.end()) {
event_queue.erase(itr, event_queue.end());
std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
}
std::optional<s64> CoreTiming::Advance() {
std::scoped_lock lock{advance_lock, basic_lock};
global_timer = GetGlobalTimeNs().count();
+6 -3
View File
@@ -98,10 +98,13 @@ public:
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data = 0, bool absolute_time = false);
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data,
bool wait = true);
/// We only permit one event of each type in the queue at a time.
void RemoveEvent(const std::shared_ptr<EventType>& event_type);
void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data) {
UnscheduleEvent(event_type, user_data, false);
}
void AddTicks(u64 ticks_to_add);
+23 -3
View File
@@ -11,6 +11,7 @@
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/debugger/gdbstub.h"
@@ -731,7 +732,25 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
auto* process = system.CurrentProcess();
auto& page_table = process->PageTable();
if (command_str == "get info") {
const char* commands = "Commands:\n"
" get fastmem\n"
" get info\n"
" get mappings\n";
if (command_str == "get fastmem") {
if (Settings::IsFastmemEnabled()) {
const auto& impl = page_table.PageTableImpl();
const auto region = reinterpret_cast<uintptr_t>(impl.fastmem_arena);
const auto region_bits = impl.current_address_space_width_in_bits;
const auto region_size = 1ULL << region_bits;
reply = fmt::format("Region bits: {}\n"
"Host address: {:#x} - {:#x}\n",
region_bits, region, region + region_size - 1);
} else {
reply = "Fastmem is not enabled.\n";
}
} else if (command_str == "get info") {
Loader::AppLoader::Modules modules;
system.GetAppLoader().ReadNSOModules(modules);
@@ -787,9 +806,10 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
cur_addr = next_address;
}
} else if (command_str == "help") {
reply = "Commands:\n get info\n get mappings\n";
reply = commands;
} else {
reply = "Unknown command.\nCommands:\n get info\n get mappings\n";
reply = "Unknown command.\n";
reply += commands;
}
std::span<const u8> reply_span{reinterpret_cast<u8*>(&reply.front()), reply.size()};
+20
View File
@@ -25,6 +25,26 @@ constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
};
static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>();
static constexpr inline u64 VirtualCoreMask = [] {
u64 mask = 0;
for (size_t i = 0; i < NumVirtualCores; ++i) {
mask |= (UINT64_C(1) << i);
}
return mask;
}();
static constexpr inline u64 ConvertVirtualCoreMaskToPhysical(u64 v_core_mask) {
u64 p_core_mask = 0;
while (v_core_mask != 0) {
const u64 next = std::countr_zero(v_core_mask);
v_core_mask &= ~(static_cast<u64>(1) << next);
p_core_mask |= (static_cast<u64>(1) << VirtualToPhysicalCoreMap[next]);
}
return p_core_mask;
}
// Cortex-A57 supports 4 memory watchpoints
constexpr u64 NUM_WATCHPOINTS = 4;
+301 -100
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <common/scope_exit.h>
#include "common/polyfill_ranges.h"
#include "common/thread.h"
@@ -11,6 +12,12 @@
namespace Core::HID {
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
constexpr u32 TURBO_BUTTON_DELAY = 4;
// Use a common UUID for TAS and Virtual Gamepad
constexpr Common::UUID TAS_UUID =
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
constexpr Common::UUID VIRTUAL_UUID =
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
EmulatedController::EmulatedController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {}
@@ -88,6 +95,7 @@ void EmulatedController::ReloadFromSettings() {
motion_params[index] = Common::ParamPackage(player.motions[index]);
}
controller.color_values = {};
controller.colors_state.fullkey = {
.body = GetNpadColor(player.body_color_left),
.button = GetNpadColor(player.button_color_left),
@@ -101,6 +109,8 @@ void EmulatedController::ReloadFromSettings() {
.button = GetNpadColor(player.button_color_right),
};
ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs);
// Other or debug controller should always be a pro controller
if (npad_id_type != NpadIdType::Other) {
SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
@@ -127,18 +137,28 @@ void EmulatedController::LoadDevices() {
trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];
trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR];
color_params[LeftIndex] = left_joycon;
color_params[RightIndex] = right_joycon;
color_params[LeftIndex].Set("color", true);
color_params[RightIndex].Set("color", true);
battery_params[LeftIndex] = left_joycon;
battery_params[RightIndex] = right_joycon;
battery_params[LeftIndex].Set("battery", true);
battery_params[RightIndex].Set("battery", true);
camera_params = Common::ParamPackage{"engine:camera,camera:1"};
nfc_params = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
camera_params[0] = right_joycon;
camera_params[0].Set("camera", true);
camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"};
ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"};
nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
nfc_params[1] = right_joycon;
nfc_params[1].Set("nfc", true);
output_params[LeftIndex] = left_joycon;
output_params[RightIndex] = right_joycon;
output_params[2] = camera_params;
output_params[3] = nfc_params;
output_params[2] = camera_params[1];
output_params[3] = nfc_params[0];
output_params[LeftIndex].Set("output", true);
output_params[RightIndex].Set("output", true);
output_params[2].Set("output", true);
@@ -154,8 +174,11 @@ void EmulatedController::LoadDevices() {
Common::Input::CreateInputDevice);
std::ranges::transform(battery_params, battery_devices.begin(),
Common::Input::CreateInputDevice);
camera_devices = Common::Input::CreateInputDevice(camera_params);
nfc_devices = Common::Input::CreateInputDevice(nfc_params);
std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice);
std::ranges::transform(camera_params, camera_devices.begin(), Common::Input::CreateInputDevice);
std::ranges::transform(ring_params, ring_analog_devices.begin(),
Common::Input::CreateInputDevice);
std::ranges::transform(nfc_params, nfc_devices.begin(), Common::Input::CreateInputDevice);
std::ranges::transform(output_params, output_devices.begin(),
Common::Input::CreateOutputDevice);
@@ -317,6 +340,19 @@ void EmulatedController::ReloadInput() {
battery_devices[index]->ForceUpdate();
}
for (std::size_t index = 0; index < color_devices.size(); ++index) {
if (!color_devices[index]) {
continue;
}
color_devices[index]->SetCallback({
.on_change =
[this, index](const Common::Input::CallbackStatus& callback) {
SetColors(callback, index);
},
});
color_devices[index]->ForceUpdate();
}
for (std::size_t index = 0; index < motion_devices.size(); ++index) {
if (!motion_devices[index]) {
continue;
@@ -330,27 +366,38 @@ void EmulatedController::ReloadInput() {
motion_devices[index]->ForceUpdate();
}
if (camera_devices) {
camera_devices->SetCallback({
for (std::size_t index = 0; index < camera_devices.size(); ++index) {
if (!camera_devices[index]) {
continue;
}
camera_devices[index]->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); },
});
camera_devices->ForceUpdate();
camera_devices[index]->ForceUpdate();
}
if (nfc_devices) {
if (npad_id_type == NpadIdType::Handheld || npad_id_type == NpadIdType::Player1) {
nfc_devices->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); },
});
nfc_devices->ForceUpdate();
for (std::size_t index = 0; index < ring_analog_devices.size(); ++index) {
if (!ring_analog_devices[index]) {
continue;
}
ring_analog_devices[index]->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); },
});
ring_analog_devices[index]->ForceUpdate();
}
// Use a common UUID for TAS
static constexpr Common::UUID TAS_UUID = Common::UUID{
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
for (std::size_t index = 0; index < nfc_devices.size(); ++index) {
if (!nfc_devices[index]) {
continue;
}
nfc_devices[index]->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); },
});
nfc_devices[index]->ForceUpdate();
}
// Register TAS devices. No need to force update
for (std::size_t index = 0; index < tas_button_devices.size(); ++index) {
@@ -377,10 +424,6 @@ void EmulatedController::ReloadInput() {
});
}
// Use a common UUID for Virtual Gamepad
static constexpr Common::UUID VIRTUAL_UUID = Common::UUID{
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
// Register virtual devices. No need to force update
for (std::size_t index = 0; index < virtual_button_devices.size(); ++index) {
if (!virtual_button_devices[index]) {
@@ -405,6 +448,7 @@ void EmulatedController::ReloadInput() {
},
});
}
turbo_button_state = 0;
}
void EmulatedController::UnloadInput() {
@@ -423,6 +467,9 @@ void EmulatedController::UnloadInput() {
for (auto& battery : battery_devices) {
battery.reset();
}
for (auto& color : color_devices) {
color.reset();
}
for (auto& output : output_devices) {
output.reset();
}
@@ -438,8 +485,15 @@ void EmulatedController::UnloadInput() {
for (auto& stick : virtual_stick_devices) {
stick.reset();
}
camera_devices.reset();
nfc_devices.reset();
for (auto& camera : camera_devices) {
camera.reset();
}
for (auto& ring : ring_analog_devices) {
ring.reset();
}
for (auto& nfc : nfc_devices) {
nfc.reset();
}
}
void EmulatedController::EnableConfiguration() {
@@ -451,6 +505,11 @@ void EmulatedController::EnableConfiguration() {
void EmulatedController::DisableConfiguration() {
is_configuring = false;
// Get Joycon colors before turning on the controller
for (const auto& color_device : color_devices) {
color_device->ForceUpdate();
}
// Apply temporary npad type to the real controller
if (tmp_npad_type != npad_type) {
if (is_connected) {
@@ -504,6 +563,9 @@ void EmulatedController::SaveCurrentConfig() {
for (std::size_t index = 0; index < player.motions.size(); ++index) {
player.motions[index] = motion_params[index].Serialize();
}
if (npad_id_type == NpadIdType::Player1) {
Settings::values.ringcon_analogs = ring_params[0].Serialize();
}
}
void EmulatedController::RestoreConfig() {
@@ -627,6 +689,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
}
current_status.toggle = new_status.toggle;
current_status.turbo = new_status.turbo;
current_status.uuid = uuid;
// Update button status with current
@@ -775,12 +838,21 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
if (index >= controller.stick_values.size()) {
return;
}
std::unique_lock lock{mutex};
auto trigger_guard =
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
std::scoped_lock lock{mutex};
const auto stick_value = TransformToStick(callback);
// Only read stick values that have the same uuid or are over the threshold to avoid flapping
if (controller.stick_values[index].uuid != uuid) {
if (!stick_value.down && !stick_value.up && !stick_value.left && !stick_value.right) {
const bool is_tas = uuid == TAS_UUID;
if (is_tas && stick_value.x.value == 0 && stick_value.y.value == 0) {
trigger_guard.Cancel();
return;
}
if (!is_tas && !stick_value.down && !stick_value.up && !stick_value.left &&
!stick_value.right) {
trigger_guard.Cancel();
return;
}
}
@@ -791,8 +863,6 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
if (is_configuring) {
controller.analog_stick_state.left = {};
controller.analog_stick_state.right = {};
lock.unlock();
TriggerOnChange(ControllerTriggerType::Stick, false);
return;
}
@@ -817,9 +887,6 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down);
break;
}
lock.unlock();
TriggerOnChange(ControllerTriggerType::Stick, true);
}
void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback,
@@ -827,7 +894,9 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
if (index >= controller.trigger_values.size()) {
return;
}
std::unique_lock lock{mutex};
auto trigger_guard =
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
std::scoped_lock lock{mutex};
const auto trigger_value = TransformToTrigger(callback);
// Only read trigger values that have the same uuid or are pressed once
@@ -843,13 +912,12 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
if (is_configuring) {
controller.gc_trigger_state.left = 0;
controller.gc_trigger_state.right = 0;
lock.unlock();
TriggerOnChange(ControllerTriggerType::Trigger, false);
return;
}
// Only GC controllers have analog triggers
if (npad_type != NpadStyleIndex::GameCube) {
trigger_guard.Cancel();
return;
}
@@ -866,9 +934,6 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
controller.npad_button_state.zr.Assign(trigger.pressed.value);
break;
}
lock.unlock();
TriggerOnChange(ControllerTriggerType::Trigger, true);
}
void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback,
@@ -876,7 +941,8 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
if (index >= controller.motion_values.size()) {
return;
}
std::unique_lock lock{mutex};
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); });
std::scoped_lock lock{mutex};
auto& raw_status = controller.motion_values[index].raw_status;
auto& emulated = controller.motion_values[index].emulated;
@@ -897,8 +963,6 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
force_update_motion = raw_status.force_update;
if (is_configuring) {
lock.unlock();
TriggerOnChange(ControllerTriggerType::Motion, false);
return;
}
@@ -908,9 +972,56 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
motion.rotation = emulated.GetRotations();
motion.orientation = emulated.GetOrientation();
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
}
lock.unlock();
TriggerOnChange(ControllerTriggerType::Motion, true);
void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback,
std::size_t index) {
if (index >= controller.color_values.size()) {
return;
}
auto trigger_guard =
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); });
std::scoped_lock lock{mutex};
controller.color_values[index] = TransformToColor(callback);
if (is_configuring) {
return;
}
if (controller.color_values[index].body == 0) {
trigger_guard.Cancel();
return;
}
controller.colors_state.fullkey = {
.body = GetNpadColor(controller.color_values[index].body),
.button = GetNpadColor(controller.color_values[index].buttons),
};
if (npad_type == NpadStyleIndex::ProController) {
controller.colors_state.left = {
.body = GetNpadColor(controller.color_values[index].left_grip),
.button = GetNpadColor(controller.color_values[index].buttons),
};
controller.colors_state.right = {
.body = GetNpadColor(controller.color_values[index].right_grip),
.button = GetNpadColor(controller.color_values[index].buttons),
};
} else {
switch (index) {
case LeftIndex:
controller.colors_state.left = {
.body = GetNpadColor(controller.color_values[index].body),
.button = GetNpadColor(controller.color_values[index].buttons),
};
break;
case RightIndex:
controller.colors_state.right = {
.body = GetNpadColor(controller.color_values[index].body),
.button = GetNpadColor(controller.color_values[index].buttons),
};
break;
}
}
}
void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
@@ -918,12 +1029,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
if (index >= controller.battery_values.size()) {
return;
}
std::unique_lock lock{mutex};
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); });
std::scoped_lock lock{mutex};
controller.battery_values[index] = TransformToBattery(callback);
if (is_configuring) {
lock.unlock();
TriggerOnChange(ControllerTriggerType::Battery, false);
return;
}
@@ -979,18 +1089,14 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
};
break;
}
lock.unlock();
TriggerOnChange(ControllerTriggerType::Battery, true);
}
void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
std::unique_lock lock{mutex};
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); });
std::scoped_lock lock{mutex};
controller.camera_values = TransformToCamera(callback);
if (is_configuring) {
lock.unlock();
TriggerOnChange(ControllerTriggerType::IrSensor, false);
return;
}
@@ -998,18 +1104,28 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback
controller.camera_state.format =
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format);
controller.camera_state.data = controller.camera_values.data;
}
lock.unlock();
TriggerOnChange(ControllerTriggerType::IrSensor, true);
void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); });
std::scoped_lock lock{mutex};
const auto force_value = TransformToStick(callback);
controller.ring_analog_value = force_value.x;
if (is_configuring) {
return;
}
controller.ring_analog_state.force = force_value.x.value;
}
void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
std::unique_lock lock{mutex};
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); });
std::scoped_lock lock{mutex};
controller.nfc_values = TransformToNfc(callback);
if (is_configuring) {
lock.unlock();
TriggerOnChange(ControllerTriggerType::Nfc, false);
return;
}
@@ -1017,9 +1133,6 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
controller.nfc_values.state,
controller.nfc_values.data,
};
lock.unlock();
TriggerOnChange(ControllerTriggerType::Nfc, true);
}
bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
@@ -1051,7 +1164,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
.type = type,
};
return output_devices[device_index]->SetVibration(status) ==
Common::Input::VibrationError::None;
Common::Input::DriverResult::Success;
}
bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
@@ -1073,16 +1186,32 @@ bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
return output_devices[device_index]->IsVibrationEnabled();
}
bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
LOG_INFO(Service_HID, "Set polling mode {}", polling_mode);
auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
Common::Input::DriverResult EmulatedController::SetPollingMode(
EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) {
LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index);
auto& left_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Left)];
auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
auto& nfc_output_device = output_devices[3];
const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
const auto mapped_nfc_result = output_device->SetPollingMode(polling_mode);
if (device_index == EmulatedDeviceIndex::LeftIndex) {
return left_output_device->SetPollingMode(polling_mode);
}
return virtual_nfc_result == Common::Input::PollingError::None ||
mapped_nfc_result == Common::Input::PollingError::None;
if (device_index == EmulatedDeviceIndex::RightIndex) {
const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode);
if (virtual_nfc_result == Common::Input::DriverResult::Success) {
return virtual_nfc_result;
}
return mapped_nfc_result;
}
left_output_device->SetPollingMode(polling_mode);
right_output_device->SetPollingMode(polling_mode);
nfc_output_device->SetPollingMode(polling_mode);
return Common::Input::DriverResult::Success;
}
bool EmulatedController::SetCameraFormat(
@@ -1093,13 +1222,22 @@ bool EmulatedController::SetCameraFormat(
auto& camera_output_device = output_devices[2];
if (right_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>(
camera_format)) == Common::Input::CameraError::None) {
camera_format)) == Common::Input::DriverResult::Success) {
return true;
}
// Fallback to Qt camera if native device doesn't have support
return camera_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>(
camera_format)) == Common::Input::CameraError::None;
camera_format)) == Common::Input::DriverResult::Success;
}
Common::ParamPackage EmulatedController::GetRingParam() const {
return ring_params[0];
}
void EmulatedController::SetRingParam(Common::ParamPackage param) {
ring_params[0] = std::move(param);
ReloadInput();
}
bool EmulatedController::HasNfc() const {
@@ -1253,39 +1391,35 @@ void EmulatedController::Connect(bool use_temporary_value) {
return;
}
std::unique_lock lock{mutex};
auto trigger_guard =
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); });
std::scoped_lock lock{mutex};
if (is_configuring) {
tmp_is_connected = true;
lock.unlock();
TriggerOnChange(ControllerTriggerType::Connected, false);
return;
}
if (is_connected) {
trigger_guard.Cancel();
return;
}
is_connected = true;
lock.unlock();
TriggerOnChange(ControllerTriggerType::Connected, true);
}
void EmulatedController::Disconnect() {
std::unique_lock lock{mutex};
auto trigger_guard =
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); });
std::scoped_lock lock{mutex};
if (is_configuring) {
tmp_is_connected = false;
lock.unlock();
TriggerOnChange(ControllerTriggerType::Disconnected, false);
return;
}
if (!is_connected) {
trigger_guard.Cancel();
return;
}
is_connected = false;
lock.unlock();
TriggerOnChange(ControllerTriggerType::Disconnected, true);
}
bool EmulatedController::IsConnected(bool get_temporary_value) const {
@@ -1310,19 +1444,21 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c
}
void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
std::unique_lock lock{mutex};
auto trigger_guard =
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); });
std::scoped_lock lock{mutex};
if (is_configuring) {
if (tmp_npad_type == npad_type_) {
trigger_guard.Cancel();
return;
}
tmp_npad_type = npad_type_;
lock.unlock();
TriggerOnChange(ControllerTriggerType::Type, false);
return;
}
if (npad_type == npad_type_) {
trigger_guard.Cancel();
return;
}
if (is_connected) {
@@ -1330,9 +1466,6 @@ void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
NpadIdTypeToIndex(npad_id_type));
}
npad_type = npad_type_;
lock.unlock();
TriggerOnChange(ControllerTriggerType::Type, true);
}
LedPattern EmulatedController::GetLedPattern() const {
@@ -1393,6 +1526,10 @@ CameraValues EmulatedController::GetCameraValues() const {
return controller.camera_values;
}
RingAnalogValue EmulatedController::GetRingSensorValues() const {
return controller.ring_analog_value;
}
HomeButtonState EmulatedController::GetHomeButtons() const {
std::scoped_lock lock{mutex};
if (is_configuring) {
@@ -1414,7 +1551,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
if (is_configuring) {
return {};
}
return controller.npad_button_state;
return {controller.npad_button_state.raw & GetTurboButtonMask()};
}
DebugPadButton EmulatedController::GetDebugPadButtons() const {
@@ -1426,22 +1563,12 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const {
}
AnalogSticks EmulatedController::GetSticks() const {
std::unique_lock lock{mutex};
std::scoped_lock lock{mutex};
if (is_configuring) {
return {};
}
// Some drivers like stick from buttons need constant refreshing
for (auto& device : stick_devices) {
if (!device) {
continue;
}
lock.unlock();
device->SoftUpdate();
lock.lock();
}
return controller.analog_stick_state;
}
@@ -1486,6 +1613,10 @@ const CameraState& EmulatedController::GetCamera() const {
return controller.camera_state;
}
RingSensorForce EmulatedController::GetRingSensorForce() const {
return controller.ring_analog_state;
}
const NfcState& EmulatedController::GetNfc() const {
std::scoped_lock lock{mutex};
return controller.nfc_state;
@@ -1528,4 +1659,74 @@ void EmulatedController::DeleteCallback(int key) {
}
callback_list.erase(iterator);
}
void EmulatedController::TurboButtonUpdate() {
turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2);
}
NpadButton EmulatedController::GetTurboButtonMask() const {
// Apply no mask when disabled
if (turbo_button_state < TURBO_BUTTON_DELAY) {
return {NpadButton::All};
}
NpadButtonState button_mask{};
for (std::size_t index = 0; index < controller.button_values.size(); ++index) {
if (!controller.button_values[index].turbo) {
continue;
}
switch (index) {
case Settings::NativeButton::A:
button_mask.a.Assign(1);
break;
case Settings::NativeButton::B:
button_mask.b.Assign(1);
break;
case Settings::NativeButton::X:
button_mask.x.Assign(1);
break;
case Settings::NativeButton::Y:
button_mask.y.Assign(1);
break;
case Settings::NativeButton::L:
button_mask.l.Assign(1);
break;
case Settings::NativeButton::R:
button_mask.r.Assign(1);
break;
case Settings::NativeButton::ZL:
button_mask.zl.Assign(1);
break;
case Settings::NativeButton::ZR:
button_mask.zr.Assign(1);
break;
case Settings::NativeButton::DLeft:
button_mask.left.Assign(1);
break;
case Settings::NativeButton::DUp:
button_mask.up.Assign(1);
break;
case Settings::NativeButton::DRight:
button_mask.right.Assign(1);
break;
case Settings::NativeButton::DDown:
button_mask.down.Assign(1);
break;
case Settings::NativeButton::SL:
button_mask.left_sl.Assign(1);
button_mask.right_sl.Assign(1);
break;
case Settings::NativeButton::SR:
button_mask.left_sr.Assign(1);
button_mask.right_sr.Assign(1);
break;
default:
break;
}
}
return static_cast<NpadButton>(~button_mask.raw);
}
} // namespace Core::HID
+63 -7
View File
@@ -35,19 +35,27 @@ using ControllerMotionDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;
using TriggerDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
using ColorDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using BatteryDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using CameraDevices = std::unique_ptr<Common::Input::InputDevice>;
using NfcDevices = std::unique_ptr<Common::Input::InputDevice>;
using CameraDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using RingAnalogDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using NfcDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices_size>;
using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using CameraParams = Common::ParamPackage;
using NfcParams = Common::ParamPackage;
using CameraParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using OutputParams = std::array<Common::ParamPackage, output_devices_size>;
using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
@@ -58,6 +66,7 @@ using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::Native
using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>;
using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>;
using CameraValues = Common::Input::CameraStatus;
using RingAnalogValue = Common::Input::AnalogStatus;
using NfcValues = Common::Input::NfcStatus;
using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>;
@@ -84,6 +93,10 @@ struct CameraState {
std::size_t sample{};
};
struct RingSensorForce {
f32 force;
};
struct NfcState {
Common::Input::NfcState state{};
std::vector<u8> data{};
@@ -116,6 +129,7 @@ struct ControllerStatus {
BatteryValues battery_values{};
VibrationValues vibration_values{};
CameraValues camera_values{};
RingAnalogValue ring_analog_value{};
NfcValues nfc_values{};
// Data for HID serices
@@ -129,6 +143,7 @@ struct ControllerStatus {
ControllerColors colors_state{};
BatteryLevelState battery_state{};
CameraState camera_state{};
RingSensorForce ring_analog_state{};
NfcState nfc_state{};
};
@@ -141,6 +156,7 @@ enum class ControllerTriggerType {
Battery,
Vibration,
IrSensor,
RingController,
Nfc,
Connected,
Disconnected,
@@ -294,6 +310,9 @@ public:
/// Returns the latest camera status from the controller with parameters
CameraValues GetCameraValues() const;
/// Returns the latest status of analog input from the ring sensor with parameters
RingAnalogValue GetRingSensorValues() const;
/// Returns the latest status of button input for the hid::HomeButton service
HomeButtonState GetHomeButtons() const;
@@ -324,6 +343,9 @@ public:
/// Returns the latest camera status from the controller
const CameraState& GetCamera() const;
/// Returns the latest ringcon force sensor value
RingSensorForce GetRingSensorForce() const;
/// Returns the latest ntag status from the controller
const NfcState& GetNfc() const;
@@ -341,10 +363,12 @@ public:
/**
* Sets the desired data to be polled from a controller
* @param device_index index of the controller to set the polling mode
* @param polling_mode type of input desired buttons, gyro, nfc, ir, etc.
* @return true if SetPollingMode was successfull
* @return driver result from this command
*/
bool SetPollingMode(Common::Input::PollingMode polling_mode);
Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index,
Common::Input::PollingMode polling_mode);
/**
* Sets the desired camera format to be polled from a controller
@@ -353,6 +377,15 @@ public:
*/
bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format);
// Returns the current mapped ring device
Common::ParamPackage GetRingParam() const;
/**
* Updates the current mapped ring device
* @param param ParamPackage with ring sensor data to be mapped
*/
void SetRingParam(Common::ParamPackage param);
/// Returns true if the device has nfc support
bool HasNfc() const;
@@ -378,6 +411,9 @@ public:
*/
void DeleteCallback(int key);
/// Swaps the state of the turbo buttons
void TurboButtonUpdate();
private:
/// creates input devices from params
void LoadDevices();
@@ -432,10 +468,17 @@ private:
*/
void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);
/**
* Updates the color status of the controller
* @param callback A CallbackStatus containing the color status
* @param index color ID of the to be updated
*/
void SetColors(const Common::Input::CallbackStatus& callback, std::size_t index);
/**
* Updates the battery status of the controller
* @param callback A CallbackStatus containing the battery status
* @param index Button ID of the to be updated
* @param index battery ID of the to be updated
*/
void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index);
@@ -445,6 +488,12 @@ private:
*/
void SetCamera(const Common::Input::CallbackStatus& callback);
/**
* Updates the ring analog sensor status of the ring controller
* @param callback A CallbackStatus containing the force status
*/
void SetRingAnalog(const Common::Input::CallbackStatus& callback);
/**
* Updates the nfc status of the controller
* @param callback A CallbackStatus containing the nfc status
@@ -465,6 +514,8 @@ private:
*/
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
NpadButton GetTurboButtonMask() const;
const NpadIdType npad_id_type;
NpadStyleIndex npad_type{NpadStyleIndex::None};
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
@@ -474,6 +525,7 @@ private:
bool system_buttons_enabled{true};
f32 motion_sensitivity{0.01f};
bool force_update_motion{false};
u32 turbo_button_state{0};
// Temporary values to avoid doing changes while the controller is in configuring mode
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
@@ -484,7 +536,9 @@ private:
ControllerMotionParams motion_params;
TriggerParams trigger_params;
BatteryParams battery_params;
ColorParams color_params;
CameraParams camera_params;
RingAnalogParams ring_params;
NfcParams nfc_params;
OutputParams output_params;
@@ -493,7 +547,9 @@ private:
ControllerMotionDevices motion_devices;
TriggerDevices trigger_devices;
BatteryDevices battery_devices;
ColorDevices color_devices;
CameraDevices camera_devices;
RingAnalogDevices ring_analog_devices;
NfcDevices nfc_devices;
OutputDevices output_devices;
-46
View File
@@ -14,7 +14,6 @@ EmulatedDevices::EmulatedDevices() = default;
EmulatedDevices::~EmulatedDevices() = default;
void EmulatedDevices::ReloadFromSettings() {
ring_params = Common::ParamPackage(Settings::values.ringcon_analogs);
ReloadInput();
}
@@ -66,8 +65,6 @@ void EmulatedDevices::ReloadInput() {
key_index++;
}
ring_analog_device = Common::Input::CreateInputDevice(ring_params);
for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
if (!mouse_button_devices[index]) {
continue;
@@ -122,13 +119,6 @@ void EmulatedDevices::ReloadInput() {
},
});
}
if (ring_analog_device) {
ring_analog_device->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); },
});
}
}
void EmulatedDevices::UnloadInput() {
@@ -145,7 +135,6 @@ void EmulatedDevices::UnloadInput() {
for (auto& button : keyboard_modifier_devices) {
button.reset();
}
ring_analog_device.reset();
}
void EmulatedDevices::EnableConfiguration() {
@@ -165,7 +154,6 @@ void EmulatedDevices::SaveCurrentConfig() {
if (!is_configuring) {
return;
}
Settings::values.ringcon_analogs = ring_params.Serialize();
}
void EmulatedDevices::RestoreConfig() {
@@ -175,15 +163,6 @@ void EmulatedDevices::RestoreConfig() {
ReloadFromSettings();
}
Common::ParamPackage EmulatedDevices::GetRingParam() const {
return ring_params;
}
void EmulatedDevices::SetRingParam(Common::ParamPackage param) {
ring_params = std::move(param);
ReloadInput();
}
void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback,
std::size_t index) {
if (index >= device_status.keyboard_values.size()) {
@@ -430,23 +409,6 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac
TriggerOnChange(DeviceTriggerType::Mouse);
}
void EmulatedDevices::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
std::lock_guard lock{mutex};
const auto force_value = TransformToStick(callback);
device_status.ring_analog_value = force_value.x;
if (is_configuring) {
device_status.ring_analog_value = {};
TriggerOnChange(DeviceTriggerType::RingController);
return;
}
device_status.ring_analog_state.force = force_value.x.value;
TriggerOnChange(DeviceTriggerType::RingController);
}
KeyboardValues EmulatedDevices::GetKeyboardValues() const {
std::scoped_lock lock{mutex};
return device_status.keyboard_values;
@@ -462,10 +424,6 @@ MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
return device_status.mouse_button_values;
}
RingAnalogValue EmulatedDevices::GetRingSensorValues() const {
return device_status.ring_analog_value;
}
KeyboardKey EmulatedDevices::GetKeyboard() const {
std::scoped_lock lock{mutex};
return device_status.keyboard_state;
@@ -491,10 +449,6 @@ AnalogStickState EmulatedDevices::GetMouseWheel() const {
return device_status.mouse_wheel_state;
}
RingSensorForce EmulatedDevices::GetRingSensorForce() const {
return device_status.ring_analog_state;
}
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
std::scoped_lock lock{callback_mutex};
for (const auto& poller_pair : callback_list) {
-18
View File
@@ -26,11 +26,9 @@ using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice
using MouseAnalogDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>;
using RingAnalogDevice = std::unique_ptr<Common::Input::InputDevice>;
using MouseButtonParams =
std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>;
using RingAnalogParams = Common::ParamPackage;
using KeyboardValues =
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardKeys>;
@@ -41,17 +39,12 @@ using MouseButtonValues =
using MouseAnalogValues =
std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickValue = Common::Input::TouchStatus;
using RingAnalogValue = Common::Input::AnalogStatus;
struct MousePosition {
f32 x;
f32 y;
};
struct RingSensorForce {
f32 force;
};
struct DeviceStatus {
// Data from input_common
KeyboardValues keyboard_values{};
@@ -59,7 +52,6 @@ struct DeviceStatus {
MouseButtonValues mouse_button_values{};
MouseAnalogValues mouse_analog_values{};
MouseStickValue mouse_stick_value{};
RingAnalogValue ring_analog_value{};
// Data for HID serices
KeyboardKey keyboard_state{};
@@ -67,7 +59,6 @@ struct DeviceStatus {
MouseButton mouse_button_state{};
MousePosition mouse_position_state{};
AnalogStickState mouse_wheel_state{};
RingSensorForce ring_analog_state{};
};
enum class DeviceTriggerType {
@@ -138,9 +129,6 @@ public:
/// Returns the latest status of button input from the mouse with parameters
MouseButtonValues GetMouseButtonsValues() const;
/// Returns the latest status of analog input from the ring sensor with parameters
RingAnalogValue GetRingSensorValues() const;
/// Returns the latest status of button input from the keyboard
KeyboardKey GetKeyboard() const;
@@ -156,9 +144,6 @@ public:
/// Returns the latest mouse wheel change
AnalogStickState GetMouseWheel() const;
/// Returns the latest ringcon force sensor value
RingSensorForce GetRingSensorForce() const;
/**
* Adds a callback to the list of events
* @param update_callback InterfaceUpdateCallback that will be triggered
@@ -224,14 +209,11 @@ private:
bool is_configuring{false};
RingAnalogParams ring_params;
KeyboardDevices keyboard_devices;
KeyboardModifierDevices keyboard_modifier_devices;
MouseButtonDevices mouse_button_devices;
MouseAnalogDevices mouse_analog_devices;
MouseStickDevice mouse_stick_device;
RingAnalogDevice ring_analog_device;
mutable std::mutex mutex;
mutable std::mutex callback_mutex;
+12
View File
@@ -304,6 +304,18 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal
return nfc;
}
Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) {
switch (callback.type) {
case Common::Input::InputType::Color:
return callback.color_status;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type);
return {};
break;
}
}
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
const auto& properties = analog.properties;
float& raw_value = analog.raw_value;
+9 -1
View File
@@ -88,10 +88,18 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu
* Converts raw input data into a valid nfc status.
*
* @param callback Supported callbacks: Nfc.
* @return A valid CameraObject object.
* @return A valid data tag vector.
*/
Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid color status.
*
* @param callback Supported callbacks: Color.
* @return A valid Color object.
*/
Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback);
/**
* Converts raw analog data into a valid analog value
* @param analog An analog object containing raw data and properties
+29 -1
View File
@@ -11,6 +11,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/scratch_buffer.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_auto_object.h"
@@ -325,7 +326,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
return ResultSuccess;
}
std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) const {
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
BufferDescriptorA()[buffer_index].Size()};
if (is_buffer_a) {
@@ -345,6 +346,33 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
}
}
std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a;
static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x;
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
BufferDescriptorA()[buffer_index].Size()};
if (is_buffer_a) {
ASSERT_OR_EXECUTE_MSG(
BufferDescriptorA().size() > buffer_index, { return {}; },
"BufferDescriptorA invalid buffer_index {}", buffer_index);
auto& read_buffer = read_buffer_a[buffer_index];
read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size());
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(),
read_buffer.size());
return read_buffer;
} else {
ASSERT_OR_EXECUTE_MSG(
BufferDescriptorX().size() > buffer_index, { return {}; },
"BufferDescriptorX invalid buffer_index {}", buffer_index);
auto& read_buffer = read_buffer_x[buffer_index];
read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size());
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(),
read_buffer.size());
return read_buffer;
}
}
std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
std::size_t buffer_index) const {
if (size == 0) {
+6 -2
View File
@@ -7,6 +7,7 @@
#include <functional>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <type_traits>
#include <vector>
@@ -270,8 +271,11 @@ public:
return domain_message_header.has_value();
}
/// Helper function to read a buffer using the appropriate buffer descriptor
[[nodiscard]] std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const;
/// Helper function to get a span of a buffer using the appropriate buffer descriptor
[[nodiscard]] std::span<const u8> ReadBuffer(std::size_t buffer_index = 0) const;
/// Helper function to read a copy of a buffer using the appropriate buffer descriptor
[[nodiscard]] std::vector<u8> ReadBufferCopy(std::size_t buffer_index = 0) const;
/// Helper function to write a buffer using the appropriate buffer descriptor
std::size_t WriteBuffer(const void* buffer, std::size_t size,
+6 -14
View File
@@ -24,9 +24,7 @@ private:
friend class ::Kernel::KClassTokenGenerator; \
static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \
static constexpr inline const char* const TypeName = #CLASS; \
static constexpr inline ClassTokenType ClassToken() { \
return ::Kernel::ClassToken<CLASS>; \
} \
static constexpr inline ClassTokenType ClassToken() { return ::Kernel::ClassToken<CLASS>; } \
\
public: \
YUZU_NON_COPYABLE(CLASS); \
@@ -37,15 +35,9 @@ public:
constexpr ClassTokenType Token = ClassToken(); \
return TypeObj(TypeName, Token); \
} \
static constexpr const char* GetStaticTypeName() { \
return TypeName; \
} \
virtual TypeObj GetTypeObj() ATTRIBUTE { \
return GetStaticTypeObj(); \
} \
virtual const char* GetTypeName() ATTRIBUTE { \
return GetStaticTypeName(); \
} \
static constexpr const char* GetStaticTypeName() { return TypeName; } \
virtual TypeObj GetTypeObj() ATTRIBUTE { return GetStaticTypeObj(); } \
virtual const char* GetTypeName() ATTRIBUTE { return GetStaticTypeName(); } \
\
private: \
constexpr bool operator!=(const TypeObj& rhs)
@@ -245,8 +237,8 @@ public:
}
template <typename U>
requires(std::derived_from<T, U> ||
std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
requires(std::derived_from<T, U> || std::derived_from<U, T>)
constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
if constexpr (std::derived_from<U, T>) {
// Upcast.
m_obj = rhs.m_obj;
+358
View File
@@ -0,0 +1,358 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hardware_properties.h"
#include "core/hle/kernel/k_capabilities.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_version.h"
namespace Kernel {
Result KCapabilities::InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table) {
// We're initializing an initial process.
m_svc_access_flags.reset();
m_irq_access_flags.reset();
m_debug_capabilities = 0;
m_handle_table_size = 0;
m_intended_kernel_version = 0;
m_program_type = 0;
// Initial processes may run on all cores.
constexpr u64 VirtMask = Core::Hardware::VirtualCoreMask;
constexpr u64 PhysMask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(VirtMask);
m_core_mask = VirtMask;
m_phys_core_mask = PhysMask;
// Initial processes may use any user priority they like.
m_priority_mask = ~0xFULL;
// Here, Nintendo sets the kernel version to the current kernel version.
// We will follow suit and set the version to the highest supported kernel version.
KernelVersion intended_kernel_version{};
intended_kernel_version.major_version.Assign(Svc::SupportedKernelMajorVersion);
intended_kernel_version.minor_version.Assign(Svc::SupportedKernelMinorVersion);
m_intended_kernel_version = intended_kernel_version.raw;
// Parse the capabilities array.
R_RETURN(this->SetCapabilities(kern_caps, page_table));
}
Result KCapabilities::InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table) {
// We're initializing a user process.
m_svc_access_flags.reset();
m_irq_access_flags.reset();
m_debug_capabilities = 0;
m_handle_table_size = 0;
m_intended_kernel_version = 0;
m_program_type = 0;
// User processes must specify what cores/priorities they can use.
m_core_mask = 0;
m_priority_mask = 0;
// Parse the user capabilities array.
R_RETURN(this->SetCapabilities(user_caps, page_table));
}
Result KCapabilities::SetCorePriorityCapability(const u32 cap) {
// We can't set core/priority if we've already set them.
R_UNLESS(m_core_mask == 0, ResultInvalidArgument);
R_UNLESS(m_priority_mask == 0, ResultInvalidArgument);
// Validate the core/priority.
CorePriority pack{cap};
const u32 min_core = pack.minimum_core_id;
const u32 max_core = pack.maximum_core_id;
const u32 max_prio = pack.lowest_thread_priority;
const u32 min_prio = pack.highest_thread_priority;
R_UNLESS(min_core <= max_core, ResultInvalidCombination);
R_UNLESS(min_prio <= max_prio, ResultInvalidCombination);
R_UNLESS(max_core < Core::Hardware::NumVirtualCores, ResultInvalidCoreId);
ASSERT(max_prio < Common::BitSize<u64>());
// Set core mask.
for (auto core_id = min_core; core_id <= max_core; core_id++) {
m_core_mask |= (1ULL << core_id);
}
ASSERT((m_core_mask & Core::Hardware::VirtualCoreMask) == m_core_mask);
// Set physical core mask.
m_phys_core_mask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(m_core_mask);
// Set priority mask.
for (auto prio = min_prio; prio <= max_prio; prio++) {
m_priority_mask |= (1ULL << prio);
}
// We must have some core/priority we can use.
R_UNLESS(m_core_mask != 0, ResultInvalidArgument);
R_UNLESS(m_priority_mask != 0, ResultInvalidArgument);
// Processes must not have access to kernel thread priorities.
R_UNLESS((m_priority_mask & 0xF) == 0, ResultInvalidArgument);
R_SUCCEED();
}
Result KCapabilities::SetSyscallMaskCapability(const u32 cap, u32& set_svc) {
// Validate the index.
SyscallMask pack{cap};
const u32 mask = pack.mask;
const u32 index = pack.index;
const u32 index_flag = (1U << index);
R_UNLESS((set_svc & index_flag) == 0, ResultInvalidCombination);
set_svc |= index_flag;
// Set SVCs.
for (size_t i = 0; i < decltype(SyscallMask::mask)::bits; i++) {
const u32 svc_id = static_cast<u32>(decltype(SyscallMask::mask)::bits * index + i);
if (mask & (1U << i)) {
R_UNLESS(this->SetSvcAllowed(svc_id), ResultOutOfRange);
}
}
R_SUCCEED();
}
Result KCapabilities::MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table) {
const auto range_pack = MapRange{cap};
const auto size_pack = MapRangeSize{size_cap};
// Get/validate address/size
const u64 phys_addr = range_pack.address.Value() * PageSize;
// Validate reserved bits are unused.
R_UNLESS(size_pack.reserved.Value() == 0, ResultOutOfRange);
const size_t num_pages = size_pack.pages;
const size_t size = num_pages * PageSize;
R_UNLESS(num_pages != 0, ResultInvalidSize);
R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
// Do the mapping.
[[maybe_unused]] const KMemoryPermission perm = range_pack.read_only.Value()
? KMemoryPermission::UserRead
: KMemoryPermission::UserReadWrite;
if (MapRangeSize{size_cap}.normal) {
// R_RETURN(page_table->MapStatic(phys_addr, size, perm));
} else {
// R_RETURN(page_table->MapIo(phys_addr, size, perm));
}
UNIMPLEMENTED();
R_SUCCEED();
}
Result KCapabilities::MapIoPage_(const u32 cap, KPageTable* page_table) {
// Get/validate address/size
const u64 phys_addr = MapIoPage{cap}.address.Value() * PageSize;
const size_t num_pages = 1;
const size_t size = num_pages * PageSize;
R_UNLESS(num_pages != 0, ResultInvalidSize);
R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
// Do the mapping.
// R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission_UserReadWrite));
UNIMPLEMENTED();
R_SUCCEED();
}
template <typename F>
Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) {
// Define the allowed memory regions.
constexpr std::array<KMemoryRegionType, 4> MemoryRegions{
KMemoryRegionType_None,
KMemoryRegionType_KernelTraceBuffer,
KMemoryRegionType_OnMemoryBootImage,
KMemoryRegionType_DTB,
};
// Extract regions/read only.
const MapRegion pack{cap};
const std::array<RegionType, 3> types{pack.region0, pack.region1, pack.region2};
const std::array<u32, 3> ro{pack.read_only0, pack.read_only1, pack.read_only2};
for (size_t i = 0; i < types.size(); i++) {
const auto type = types[i];
const auto perm = ro[i] ? KMemoryPermission::UserRead : KMemoryPermission::UserReadWrite;
switch (type) {
case RegionType::NoMapping:
break;
case RegionType::KernelTraceBuffer:
case RegionType::OnMemoryBootImage:
case RegionType::DTB:
R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
break;
default:
R_THROW(ResultNotFound);
}
}
R_SUCCEED();
}
Result KCapabilities::MapRegion_(const u32 cap, KPageTable* page_table) {
// Map each region into the process's page table.
R_RETURN(ProcessMapRegionCapability(
cap, [](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
// R_RETURN(page_table->MapRegion(region_type, perm));
UNIMPLEMENTED();
R_SUCCEED();
}));
}
Result KCapabilities::CheckMapRegion(KernelCore& kernel, const u32 cap) {
// Check that each region has a physical backing store.
R_RETURN(ProcessMapRegionCapability(
cap, [&](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
R_UNLESS(kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived(
region_type) != nullptr,
ResultOutOfRange);
R_SUCCEED();
}));
}
Result KCapabilities::SetInterruptPairCapability(const u32 cap) {
// Extract interrupts.
const InterruptPair pack{cap};
const std::array<u32, 2> ids{pack.interrupt_id0, pack.interrupt_id1};
for (size_t i = 0; i < ids.size(); i++) {
if (ids[i] != PaddingInterruptId) {
UNIMPLEMENTED();
// R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(ids[i]), ResultOutOfRange);
// R_UNLESS(this->SetInterruptPermitted(ids[i]), ResultOutOfRange);
}
}
R_SUCCEED();
}
Result KCapabilities::SetProgramTypeCapability(const u32 cap) {
// Validate.
const ProgramType pack{cap};
R_UNLESS(pack.reserved == 0, ResultReservedUsed);
m_program_type = pack.type;
R_SUCCEED();
}
Result KCapabilities::SetKernelVersionCapability(const u32 cap) {
// Ensure we haven't set our version before.
R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version == 0, ResultInvalidArgument);
// Set, ensure that we set a valid version.
m_intended_kernel_version = cap;
R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version != 0, ResultInvalidArgument);
R_SUCCEED();
}
Result KCapabilities::SetHandleTableCapability(const u32 cap) {
// Validate.
const HandleTable pack{cap};
R_UNLESS(pack.reserved == 0, ResultReservedUsed);
m_handle_table_size = pack.size;
R_SUCCEED();
}
Result KCapabilities::SetDebugFlagsCapability(const u32 cap) {
// Validate.
const DebugFlags pack{cap};
R_UNLESS(pack.reserved == 0, ResultReservedUsed);
DebugFlags debug_capabilities{m_debug_capabilities};
debug_capabilities.allow_debug.Assign(pack.allow_debug);
debug_capabilities.force_debug.Assign(pack.force_debug);
m_debug_capabilities = debug_capabilities.raw;
R_SUCCEED();
}
Result KCapabilities::SetCapability(const u32 cap, u32& set_flags, u32& set_svc,
KPageTable* page_table) {
// Validate this is a capability we can act on.
const auto type = GetCapabilityType(cap);
R_UNLESS(type != CapabilityType::Invalid, ResultInvalidArgument);
// If the type is padding, we have no work to do.
R_SUCCEED_IF(type == CapabilityType::Padding);
// Check that we haven't already processed this capability.
const auto flag = GetCapabilityFlag(type);
R_UNLESS(((set_flags & InitializeOnceFlags) & flag) == 0, ResultInvalidCombination);
set_flags |= flag;
// Process the capability.
switch (type) {
case CapabilityType::CorePriority:
R_RETURN(this->SetCorePriorityCapability(cap));
case CapabilityType::SyscallMask:
R_RETURN(this->SetSyscallMaskCapability(cap, set_svc));
case CapabilityType::MapIoPage:
R_RETURN(this->MapIoPage_(cap, page_table));
case CapabilityType::MapRegion:
R_RETURN(this->MapRegion_(cap, page_table));
case CapabilityType::InterruptPair:
R_RETURN(this->SetInterruptPairCapability(cap));
case CapabilityType::ProgramType:
R_RETURN(this->SetProgramTypeCapability(cap));
case CapabilityType::KernelVersion:
R_RETURN(this->SetKernelVersionCapability(cap));
case CapabilityType::HandleTable:
R_RETURN(this->SetHandleTableCapability(cap));
case CapabilityType::DebugFlags:
R_RETURN(this->SetDebugFlagsCapability(cap));
default:
R_THROW(ResultInvalidArgument);
}
}
Result KCapabilities::SetCapabilities(std::span<const u32> caps, KPageTable* page_table) {
u32 set_flags = 0, set_svc = 0;
for (size_t i = 0; i < caps.size(); i++) {
const u32 cap{caps[i]};
if (GetCapabilityType(cap) == CapabilityType::MapRange) {
// Check that the pair cap exists.
R_UNLESS((++i) < caps.size(), ResultInvalidCombination);
// Check the pair cap is a map range cap.
const u32 size_cap{caps[i]};
R_UNLESS(GetCapabilityType(size_cap) == CapabilityType::MapRange,
ResultInvalidCombination);
// Map the range.
R_TRY(this->MapRange_(cap, size_cap, page_table));
} else {
R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
}
}
R_SUCCEED();
}
Result KCapabilities::CheckCapabilities(KernelCore& kernel, std::span<const u32> caps) {
for (auto cap : caps) {
// Check the capability refers to a valid region.
if (GetCapabilityType(cap) == CapabilityType::MapRegion) {
R_TRY(CheckMapRegion(kernel, cap));
}
}
R_SUCCEED();
}
} // namespace Kernel
+295
View File
@@ -0,0 +1,295 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <bitset>
#include <span>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
namespace Kernel {
class KPageTable;
class KernelCore;
class KCapabilities {
public:
constexpr explicit KCapabilities() = default;
Result InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table);
Result InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table);
static Result CheckCapabilities(KernelCore& kernel, std::span<const u32> user_caps);
constexpr u64 GetCoreMask() const {
return m_core_mask;
}
constexpr u64 GetPhysicalCoreMask() const {
return m_phys_core_mask;
}
constexpr u64 GetPriorityMask() const {
return m_priority_mask;
}
constexpr s32 GetHandleTableSize() const {
return m_handle_table_size;
}
constexpr const Svc::SvcAccessFlagSet& GetSvcPermissions() const {
return m_svc_access_flags;
}
constexpr bool IsPermittedSvc(u32 id) const {
return (id < m_svc_access_flags.size()) && m_svc_access_flags[id];
}
constexpr bool IsPermittedInterrupt(u32 id) const {
return (id < m_irq_access_flags.size()) && m_irq_access_flags[id];
}
constexpr bool IsPermittedDebug() const {
return DebugFlags{m_debug_capabilities}.allow_debug.Value() != 0;
}
constexpr bool CanForceDebug() const {
return DebugFlags{m_debug_capabilities}.force_debug.Value() != 0;
}
constexpr u32 GetIntendedKernelMajorVersion() const {
return KernelVersion{m_intended_kernel_version}.major_version;
}
constexpr u32 GetIntendedKernelMinorVersion() const {
return KernelVersion{m_intended_kernel_version}.minor_version;
}
private:
static constexpr size_t InterruptIdCount = 0x400;
using InterruptFlagSet = std::bitset<InterruptIdCount>;
enum class CapabilityType : u32 {
CorePriority = (1U << 3) - 1,
SyscallMask = (1U << 4) - 1,
MapRange = (1U << 6) - 1,
MapIoPage = (1U << 7) - 1,
MapRegion = (1U << 10) - 1,
InterruptPair = (1U << 11) - 1,
ProgramType = (1U << 13) - 1,
KernelVersion = (1U << 14) - 1,
HandleTable = (1U << 15) - 1,
DebugFlags = (1U << 16) - 1,
Invalid = 0U,
Padding = ~0U,
};
using RawCapabilityValue = u32;
static constexpr CapabilityType GetCapabilityType(const RawCapabilityValue value) {
return static_cast<CapabilityType>((~value & (value + 1)) - 1);
}
static constexpr u32 GetCapabilityFlag(CapabilityType type) {
return static_cast<u32>(type) + 1;
}
template <CapabilityType Type>
static constexpr inline u32 CapabilityFlag = static_cast<u32>(Type) + 1;
template <CapabilityType Type>
static constexpr inline u32 CapabilityId = std::countr_zero(CapabilityFlag<Type>);
union CorePriority {
static_assert(CapabilityId<CapabilityType::CorePriority> + 1 == 4);
RawCapabilityValue raw;
BitField<0, 4, CapabilityType> id;
BitField<4, 6, u32> lowest_thread_priority;
BitField<10, 6, u32> highest_thread_priority;
BitField<16, 8, u32> minimum_core_id;
BitField<24, 8, u32> maximum_core_id;
};
union SyscallMask {
static_assert(CapabilityId<CapabilityType::SyscallMask> + 1 == 5);
RawCapabilityValue raw;
BitField<0, 5, CapabilityType> id;
BitField<5, 24, u32> mask;
BitField<29, 3, u32> index;
};
// #undef MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES
static constexpr u64 PhysicalMapAllowedMask = (1ULL << 36) - 1;
union MapRange {
static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7);
RawCapabilityValue raw;
BitField<0, 7, CapabilityType> id;
BitField<7, 24, u32> address;
BitField<31, 1, u32> read_only;
};
union MapRangeSize {
static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7);
RawCapabilityValue raw;
BitField<0, 7, CapabilityType> id;
BitField<7, 20, u32> pages;
BitField<27, 4, u32> reserved;
BitField<31, 1, u32> normal;
};
union MapIoPage {
static_assert(CapabilityId<CapabilityType::MapIoPage> + 1 == 8);
RawCapabilityValue raw;
BitField<0, 8, CapabilityType> id;
BitField<8, 24, u32> address;
};
enum class RegionType : u32 {
NoMapping = 0,
KernelTraceBuffer = 1,
OnMemoryBootImage = 2,
DTB = 3,
};
union MapRegion {
static_assert(CapabilityId<CapabilityType::MapRegion> + 1 == 11);
RawCapabilityValue raw;
BitField<0, 11, CapabilityType> id;
BitField<11, 6, RegionType> region0;
BitField<17, 1, u32> read_only0;
BitField<18, 6, RegionType> region1;
BitField<24, 1, u32> read_only1;
BitField<25, 6, RegionType> region2;
BitField<31, 1, u32> read_only2;
};
union InterruptPair {
static_assert(CapabilityId<CapabilityType::InterruptPair> + 1 == 12);
RawCapabilityValue raw;
BitField<0, 12, CapabilityType> id;
BitField<12, 10, u32> interrupt_id0;
BitField<22, 10, u32> interrupt_id1;
};
union ProgramType {
static_assert(CapabilityId<CapabilityType::ProgramType> + 1 == 14);
RawCapabilityValue raw;
BitField<0, 14, CapabilityType> id;
BitField<14, 3, u32> type;
BitField<17, 15, u32> reserved;
};
union KernelVersion {
static_assert(CapabilityId<CapabilityType::KernelVersion> + 1 == 15);
RawCapabilityValue raw;
BitField<0, 15, CapabilityType> id;
BitField<15, 4, u32> major_version;
BitField<19, 13, u32> minor_version;
};
union HandleTable {
static_assert(CapabilityId<CapabilityType::HandleTable> + 1 == 16);
RawCapabilityValue raw;
BitField<0, 16, CapabilityType> id;
BitField<16, 10, u32> size;
BitField<26, 6, u32> reserved;
};
union DebugFlags {
static_assert(CapabilityId<CapabilityType::DebugFlags> + 1 == 17);
RawCapabilityValue raw;
BitField<0, 17, CapabilityType> id;
BitField<17, 1, u32> allow_debug;
BitField<18, 1, u32> force_debug;
BitField<19, 13, u32> reserved;
};
static_assert(sizeof(CorePriority) == 4);
static_assert(sizeof(SyscallMask) == 4);
static_assert(sizeof(MapRange) == 4);
static_assert(sizeof(MapRangeSize) == 4);
static_assert(sizeof(MapIoPage) == 4);
static_assert(sizeof(MapRegion) == 4);
static_assert(sizeof(InterruptPair) == 4);
static_assert(sizeof(ProgramType) == 4);
static_assert(sizeof(KernelVersion) == 4);
static_assert(sizeof(HandleTable) == 4);
static_assert(sizeof(DebugFlags) == 4);
static constexpr u32 InitializeOnceFlags =
CapabilityFlag<CapabilityType::CorePriority> | CapabilityFlag<CapabilityType::ProgramType> |
CapabilityFlag<CapabilityType::KernelVersion> |
CapabilityFlag<CapabilityType::HandleTable> | CapabilityFlag<CapabilityType::DebugFlags>;
static const u32 PaddingInterruptId = 0x3FF;
static_assert(PaddingInterruptId < InterruptIdCount);
private:
constexpr bool SetSvcAllowed(u32 id) {
if (id < m_svc_access_flags.size()) [[likely]] {
m_svc_access_flags[id] = true;
return true;
} else {
return false;
}
}
constexpr bool SetInterruptPermitted(u32 id) {
if (id < m_irq_access_flags.size()) [[likely]] {
m_irq_access_flags[id] = true;
return true;
} else {
return false;
}
}
Result SetCorePriorityCapability(const u32 cap);
Result SetSyscallMaskCapability(const u32 cap, u32& set_svc);
Result MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table);
Result MapIoPage_(const u32 cap, KPageTable* page_table);
Result MapRegion_(const u32 cap, KPageTable* page_table);
Result SetInterruptPairCapability(const u32 cap);
Result SetProgramTypeCapability(const u32 cap);
Result SetKernelVersionCapability(const u32 cap);
Result SetHandleTableCapability(const u32 cap);
Result SetDebugFlagsCapability(const u32 cap);
template <typename F>
static Result ProcessMapRegionCapability(const u32 cap, F f);
static Result CheckMapRegion(KernelCore& kernel, const u32 cap);
Result SetCapability(const u32 cap, u32& set_flags, u32& set_svc, KPageTable* page_table);
Result SetCapabilities(std::span<const u32> caps, KPageTable* page_table);
private:
Svc::SvcAccessFlagSet m_svc_access_flags{};
InterruptFlagSet m_irq_access_flags{};
u64 m_core_mask{};
u64 m_phys_core_mask{};
u64 m_priority_mask{};
u32 m_debug_capabilities{};
s32 m_handle_table_size{};
u32 m_intended_kernel_version{};
u32 m_program_type{};
};
} // namespace Kernel
+6 -6
View File
@@ -74,7 +74,7 @@ Result KCodeMemory::Map(VAddr address, size_t size) {
R_UNLESS(!m_is_mapped, ResultInvalidState);
// Map the memory.
R_TRY(kernel.CurrentProcess()->PageTable().MapPages(
R_TRY(kernel.CurrentProcess()->PageTable().MapPageGroup(
address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
// Mark ourselves as mapped.
@@ -91,8 +91,8 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) {
KScopedLightLock lk(m_lock);
// Unmap the memory.
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, *m_page_group,
KMemoryState::CodeOut));
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPageGroup(address, *m_page_group,
KMemoryState::CodeOut));
// Mark ourselves as unmapped.
m_is_mapped = false;
@@ -125,8 +125,8 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission
}
// Map the memory.
R_TRY(
m_owner->PageTable().MapPages(address, *m_page_group, KMemoryState::GeneratedCode, k_perm));
R_TRY(m_owner->PageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode,
k_perm));
// Mark ourselves as mapped.
m_is_owner_mapped = true;
@@ -142,7 +142,7 @@ Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
KScopedLightLock lk(m_lock);
// Unmap the memory.
R_TRY(m_owner->PageTable().UnmapPages(address, *m_page_group, KMemoryState::GeneratedCode));
R_TRY(m_owner->PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode));
// Mark ourselves as unmapped.
m_is_owner_mapped = false;
+1 -1
View File
@@ -171,7 +171,7 @@ Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value)
R_UNLESS(owner_thread != nullptr, ResultInvalidHandle);
// Update the lock.
cur_thread->SetAddressKey(addr, value);
cur_thread->SetUserAddressKey(addr, value);
owner_thread->AddWaiter(cur_thread);
// Begin waiting.
+4 -2
View File
@@ -18,7 +18,8 @@ void KHardwareTimer::Initialize() {
}
void KHardwareTimer::Finalize() {
this->DisableInterrupt();
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
m_wakeup_time = std::numeric_limits<s64>::max();
m_event_type.reset();
}
@@ -59,7 +60,8 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
}
void KHardwareTimer::DisableInterrupt() {
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type,
reinterpret_cast<uintptr_t>(this));
m_wakeup_time = std::numeric_limits<s64>::max();
}
+1 -1
View File
@@ -68,7 +68,7 @@ bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
// Add the current thread as a waiter on the owner.
KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL);
cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
owner_thread->AddWaiter(cur_thread);
// Begin waiting to hold the lock.
+3 -3
View File
@@ -67,9 +67,9 @@ constexpr size_t KernelPageBufferAdditionalSize = 0x33C000;
constexpr std::size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize +
KernelSlabHeapSize + KernelPageBufferHeapSize;
constexpr bool IsKernelAddressKey(VAddr key) {
return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
}
//! NB: Use KThread::GetAddressKeyIsKernel().
//! See explanation for deviation of GetAddressKey.
bool IsKernelAddressKey(VAddr key) = delete;
constexpr bool IsKernelAddress(VAddr address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
+385 -179
View File
@@ -435,6 +435,9 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si
KPageGroup pg{m_kernel, m_block_info_manager};
AddRegionToPages(src_address, num_pages, pg);
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Reprotect the source as kernel-read/not mapped.
const auto new_perm = static_cast<KMemoryPermission>(KMemoryPermission::KernelRead |
KMemoryPermission::NotMapped);
@@ -447,7 +450,10 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si
});
// Map the alias pages.
R_TRY(MapPages(dst_address, pg, new_perm));
const KPageProperties dst_properties = {new_perm, false, false,
DisableMergeAttribute::DisableHead};
R_TRY(
this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_properties, false));
// We successfully mapped the alias pages, so we don't need to unprotect the src pages on
// failure.
@@ -1881,7 +1887,8 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
R_SUCCEED();
}
Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size) {
Result KPageTable::MapMemory(KProcessAddress dst_address, KProcessAddress src_address,
size_t size) {
// Lock the table.
KScopedLightLock lk(m_general_lock);
@@ -1902,53 +1909,73 @@ Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size)
KMemoryAttribute::None));
// Create an update allocator for the source.
Result src_allocator_result{ResultSuccess};
Result src_allocator_result;
KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
m_memory_block_slab_manager,
num_src_allocator_blocks);
R_TRY(src_allocator_result);
// Create an update allocator for the destination.
Result dst_allocator_result{ResultSuccess};
Result dst_allocator_result;
KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
m_memory_block_slab_manager,
num_dst_allocator_blocks);
R_TRY(dst_allocator_result);
// Map the memory.
KPageGroup page_linked_list{m_kernel, m_block_info_manager};
const size_t num_pages{size / PageSize};
const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(
KMemoryPermission::KernelRead | KMemoryPermission::NotMapped);
const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked;
AddRegionToPages(src_address, num_pages, page_linked_list);
{
// Determine the number of pages being operated on.
const size_t num_pages = size / PageSize;
// Create page groups for the memory being unmapped.
KPageGroup pg{m_kernel, m_block_info_manager};
// Create the page group representing the source.
R_TRY(this->MakePageGroup(pg, src_address, num_pages));
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Reprotect the source as kernel-read/not mapped.
auto block_guard = detail::ScopeExit([&] {
Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
OperationType::ChangePermissions);
});
R_TRY(Operate(src_address, num_pages, new_src_perm, OperationType::ChangePermissions));
R_TRY(MapPages(dst_address, page_linked_list, KMemoryPermission::UserReadWrite));
const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(
KMemoryPermission::KernelRead | KMemoryPermission::NotMapped);
const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked;
const KPageProperties src_properties = {new_src_perm, false, false,
DisableMergeAttribute::DisableHeadBodyTail};
R_TRY(this->Operate(src_address, num_pages, src_properties.perm,
OperationType::ChangePermissions));
block_guard.Cancel();
// Ensure that we unprotect the source pages on failure.
ON_RESULT_FAILURE {
const KPageProperties unprotect_properties = {
KMemoryPermission::UserReadWrite, false, false,
DisableMergeAttribute::EnableHeadBodyTail};
ASSERT(this->Operate(src_address, num_pages, unprotect_properties.perm,
OperationType::ChangePermissions) == ResultSuccess);
};
// Map the alias pages.
const KPageProperties dst_map_properties = {KMemoryPermission::UserReadWrite, false, false,
DisableMergeAttribute::DisableHead};
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_map_properties,
false));
// Apply the memory block updates.
m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages,
src_state, new_src_perm, new_src_attr,
KMemoryBlockDisableMergeAttribute::Locked,
KMemoryBlockDisableMergeAttribute::None);
m_memory_block_manager.Update(
std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::Stack,
KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
KMemoryBlockDisableMergeAttribute::Normal, KMemoryBlockDisableMergeAttribute::None);
}
// Apply the memory block updates.
m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state,
new_src_perm, new_src_attr,
KMemoryBlockDisableMergeAttribute::Locked,
KMemoryBlockDisableMergeAttribute::None);
m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages,
KMemoryState::Stack, KMemoryPermission::UserReadWrite,
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
KMemoryBlockDisableMergeAttribute::None);
R_SUCCEED();
}
Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size) {
Result KPageTable::UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address,
size_t size) {
// Lock the table.
KScopedLightLock lk(m_general_lock);
@@ -1970,108 +1997,208 @@ Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
// Create an update allocator for the source.
Result src_allocator_result{ResultSuccess};
Result src_allocator_result;
KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
m_memory_block_slab_manager,
num_src_allocator_blocks);
R_TRY(src_allocator_result);
// Create an update allocator for the destination.
Result dst_allocator_result{ResultSuccess};
Result dst_allocator_result;
KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
m_memory_block_slab_manager,
num_dst_allocator_blocks);
R_TRY(dst_allocator_result);
KPageGroup src_pages{m_kernel, m_block_info_manager};
KPageGroup dst_pages{m_kernel, m_block_info_manager};
const size_t num_pages{size / PageSize};
AddRegionToPages(src_address, num_pages, src_pages);
AddRegionToPages(dst_address, num_pages, dst_pages);
R_UNLESS(dst_pages.IsEquivalentTo(src_pages), ResultInvalidMemoryRegion);
// Unmap the memory.
{
auto block_guard = detail::ScopeExit([&] { MapPages(dst_address, dst_pages, dst_perm); });
// Determine the number of pages being operated on.
const size_t num_pages = size / PageSize;
R_TRY(Operate(dst_address, num_pages, KMemoryPermission::None, OperationType::Unmap));
R_TRY(Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
OperationType::ChangePermissions));
// Create page groups for the memory being unmapped.
KPageGroup pg{m_kernel, m_block_info_manager};
block_guard.Cancel();
// Create the page group representing the destination.
R_TRY(this->MakePageGroup(pg, dst_address, num_pages));
// Ensure the page group is the valid for the source.
R_UNLESS(this->IsValidPageGroup(pg, src_address, num_pages), ResultInvalidMemoryRegion);
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Unmap the aliased copy of the pages.
const KPageProperties dst_unmap_properties = {KMemoryPermission::None, false, false,
DisableMergeAttribute::None};
R_TRY(
this->Operate(dst_address, num_pages, dst_unmap_properties.perm, OperationType::Unmap));
// Ensure that we re-map the aliased pages on failure.
ON_RESULT_FAILURE {
this->RemapPageGroup(updater.GetPageList(), dst_address, size, pg);
};
// Try to set the permissions for the source pages back to what they should be.
const KPageProperties src_properties = {KMemoryPermission::UserReadWrite, false, false,
DisableMergeAttribute::EnableAndMergeHeadBodyTail};
R_TRY(this->Operate(src_address, num_pages, src_properties.perm,
OperationType::ChangePermissions));
// Apply the memory block updates.
m_memory_block_manager.Update(
std::addressof(src_allocator), src_address, num_pages, src_state,
KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Locked);
m_memory_block_manager.Update(
std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::None,
KMemoryPermission::None, KMemoryAttribute::None,
KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Normal);
}
// Apply the memory block updates.
m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state,
KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
KMemoryBlockDisableMergeAttribute::None,
KMemoryBlockDisableMergeAttribute::Locked);
m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages,
KMemoryState::None, KMemoryPermission::None,
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
KMemoryBlockDisableMergeAttribute::Normal);
R_SUCCEED();
}
Result KPageTable::MapPages(VAddr addr, const KPageGroup& page_linked_list,
KMemoryPermission perm) {
Result KPageTable::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
size_t num_pages, KMemoryPermission perm) {
ASSERT(this->IsLockedByCurrentThread());
VAddr cur_addr{addr};
// Create a page group to hold the pages we allocate.
KPageGroup pg{m_kernel, m_block_info_manager};
for (const auto& node : page_linked_list) {
if (const auto result{
Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
result.IsError()) {
const size_t num_pages{(addr - cur_addr) / PageSize};
// Allocate the pages.
R_TRY(
m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)
.IsSuccess());
// Ensure that the page group is closed when we're done working with it.
SCOPE_EXIT({ pg.Close(); });
R_RETURN(result);
}
cur_addr += node.GetNumPages() * PageSize;
// Clear all pages.
for (const auto& it : pg) {
std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value,
it.GetSize());
}
R_SUCCEED();
}
Result KPageTable::MapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state,
KMemoryPermission perm) {
// Check that the map is in range.
const size_t num_pages{page_linked_list.GetNumPages()};
const size_t size{num_pages * PageSize};
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
// Lock the table.
KScopedLightLock lk(m_general_lock);
// Check the memory state.
R_TRY(this->CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::None, KMemoryAttribute::None));
// Create an update allocator.
Result allocator_result{ResultSuccess};
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager);
// Map the pages.
R_TRY(MapPages(address, page_linked_list, perm));
R_RETURN(this->Operate(address, num_pages, pg, OperationType::MapGroup));
}
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
KMemoryBlockDisableMergeAttribute::None);
Result KPageTable::MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
const KPageGroup& pg, const KPageProperties properties,
bool reuse_ll) {
ASSERT(this->IsLockedByCurrentThread());
// Note the current address, so that we can iterate.
const KProcessAddress start_address = address;
KProcessAddress cur_address = address;
// Ensure that we clean up on failure.
ON_RESULT_FAILURE {
ASSERT(!reuse_ll);
if (cur_address != start_address) {
const KPageProperties unmap_properties = {KMemoryPermission::None, false, false,
DisableMergeAttribute::None};
ASSERT(this->Operate(start_address, (cur_address - start_address) / PageSize,
unmap_properties.perm, OperationType::Unmap) == ResultSuccess);
}
};
// Iterate, mapping all pages in the group.
for (const auto& block : pg) {
// Map and advance.
const KPageProperties cur_properties =
(cur_address == start_address)
? properties
: KPageProperties{properties.perm, properties.io, properties.uncached,
DisableMergeAttribute::None};
this->Operate(cur_address, block.GetNumPages(), cur_properties.perm, OperationType::Map,
block.GetAddress());
cur_address += block.GetSize();
}
// We succeeded!
R_SUCCEED();
}
Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
bool is_pa_valid, VAddr region_start, size_t region_num_pages,
void KPageTable::RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
const KPageGroup& pg) {
ASSERT(this->IsLockedByCurrentThread());
// Note the current address, so that we can iterate.
const KProcessAddress start_address = address;
const KProcessAddress last_address = start_address + size - 1;
const KProcessAddress end_address = last_address + 1;
// Iterate over the memory.
auto pg_it = pg.begin();
ASSERT(pg_it != pg.end());
KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
size_t pg_pages = pg_it->GetNumPages();
auto it = m_memory_block_manager.FindIterator(start_address);
while (true) {
// Check that the iterator is valid.
ASSERT(it != m_memory_block_manager.end());
// Get the memory info.
const KMemoryInfo info = it->GetMemoryInfo();
// Determine the range to map.
KProcessAddress map_address = std::max<VAddr>(info.GetAddress(), start_address);
const KProcessAddress map_end_address = std::min<VAddr>(info.GetEndAddress(), end_address);
ASSERT(map_end_address != map_address);
// Determine if we should disable head merge.
const bool disable_head_merge =
info.GetAddress() >= start_address &&
True(info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute::Normal);
const KPageProperties map_properties = {
info.GetPermission(), false, false,
disable_head_merge ? DisableMergeAttribute::DisableHead : DisableMergeAttribute::None};
// While we have pages to map, map them.
size_t map_pages = (map_end_address - map_address) / PageSize;
while (map_pages > 0) {
// Check if we're at the end of the physical block.
if (pg_pages == 0) {
// Ensure there are more pages to map.
ASSERT(pg_it != pg.end());
// Advance our physical block.
++pg_it;
pg_phys_addr = pg_it->GetAddress();
pg_pages = pg_it->GetNumPages();
}
// Map whatever we can.
const size_t cur_pages = std::min(pg_pages, map_pages);
ASSERT(this->Operate(map_address, map_pages, map_properties.perm, OperationType::Map,
pg_phys_addr) == ResultSuccess);
// Advance.
map_address += cur_pages * PageSize;
map_pages -= cur_pages;
pg_phys_addr += cur_pages * PageSize;
pg_pages -= cur_pages;
}
// Check if we're done.
if (last_address <= info.GetLastAddress()) {
break;
}
// Advance.
++it;
}
// Check that we re-mapped precisely the page group.
ASSERT((++pg_it) == pg.end());
}
Result KPageTable::MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
KPhysicalAddress phys_addr, bool is_pa_valid,
KProcessAddress region_start, size_t region_num_pages,
KMemoryState state, KMemoryPermission perm) {
ASSERT(Common::IsAligned(alignment, PageSize) && alignment >= PageSize);
@@ -2084,26 +2211,30 @@ Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment,
KScopedLightLock lk(m_general_lock);
// Find a random address to map at.
VAddr addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0,
this->GetNumGuardPages());
KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment,
0, this->GetNumGuardPages());
R_UNLESS(addr != 0, ResultOutOfMemory);
ASSERT(Common::IsAligned(addr, alignment));
ASSERT(this->CanContain(addr, num_pages * PageSize, state));
ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::None, KMemoryAttribute::None)
.IsSuccess());
KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess);
// Create an update allocator.
Result allocator_result{ResultSuccess};
Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager);
R_TRY(allocator_result);
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Perform mapping operation.
if (is_pa_valid) {
R_TRY(this->Operate(addr, num_pages, perm, OperationType::Map, phys_addr));
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
R_TRY(this->Operate(addr, num_pages, properties.perm, OperationType::Map, phys_addr));
} else {
UNIMPLEMENTED();
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, perm));
}
// Update the blocks.
@@ -2116,28 +2247,45 @@ Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment,
R_SUCCEED();
}
Result KPageTable::UnmapPages(VAddr addr, const KPageGroup& page_linked_list) {
ASSERT(this->IsLockedByCurrentThread());
Result KPageTable::MapPages(KProcessAddress address, size_t num_pages, KMemoryState state,
KMemoryPermission perm) {
// Check that the map is in range.
const size_t size = num_pages * PageSize;
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
VAddr cur_addr{addr};
// Lock the table.
KScopedLightLock lk(m_general_lock);
for (const auto& node : page_linked_list) {
if (const auto result{Operate(cur_addr, node.GetNumPages(), KMemoryPermission::None,
OperationType::Unmap)};
result.IsError()) {
R_RETURN(result);
}
// Check the memory state.
size_t num_allocator_blocks;
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::None,
KMemoryAttribute::None));
cur_addr += node.GetNumPages() * PageSize;
}
// Create an update allocator.
Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Map the pages.
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, perm));
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
KMemoryBlockDisableMergeAttribute::None);
R_SUCCEED();
}
Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state) {
Result KPageTable::UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state) {
// Check that the unmap is in range.
const size_t num_pages{page_linked_list.GetNumPages()};
const size_t size{num_pages * PageSize};
const size_t size = num_pages * PageSize;
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
// Lock the table.
@@ -2151,13 +2299,18 @@ Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemo
KMemoryAttribute::None));
// Create an update allocator.
Result allocator_result{ResultSuccess};
Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Perform the unmap.
R_TRY(UnmapPages(address, page_linked_list));
const KPageProperties unmap_properties = {KMemoryPermission::None, false, false,
DisableMergeAttribute::None};
R_TRY(this->Operate(address, num_pages, unmap_properties.perm, OperationType::Unmap));
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
@@ -2168,29 +2321,130 @@ Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemo
R_SUCCEED();
}
Result KPageTable::UnmapPages(VAddr address, size_t num_pages, KMemoryState state) {
// Check that the unmap is in range.
const size_t size = num_pages * PageSize;
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
Result KPageTable::MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
KProcessAddress region_start, size_t region_num_pages,
KMemoryState state, KMemoryPermission perm) {
ASSERT(!this->IsLockedByCurrentThread());
// Ensure this is a valid map request.
const size_t num_pages = pg.GetNumPages();
R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state),
ResultInvalidCurrentMemory);
R_UNLESS(num_pages < region_num_pages, ResultOutOfMemory);
// Lock the table.
KScopedLightLock lk(m_general_lock);
// Check the memory state.
size_t num_allocator_blocks{};
// Find a random address to map at.
KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, PageSize,
0, this->GetNumGuardPages());
R_UNLESS(addr != 0, ResultOutOfMemory);
ASSERT(this->CanContain(addr, num_pages * PageSize, state));
ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess);
// Create an update allocator.
Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager);
R_TRY(allocator_result);
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Perform mapping operation.
const KPageProperties properties = {perm, state == KMemoryState::Io, false,
DisableMergeAttribute::DisableHead};
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
KMemoryBlockDisableMergeAttribute::None);
// We successfully mapped the pages.
*out_addr = addr;
R_SUCCEED();
}
Result KPageTable::MapPageGroup(KProcessAddress addr, const KPageGroup& pg, KMemoryState state,
KMemoryPermission perm) {
ASSERT(!this->IsLockedByCurrentThread());
// Ensure this is a valid map request.
const size_t num_pages = pg.GetNumPages();
const size_t size = num_pages * PageSize;
R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
// Lock the table.
KScopedLightLock lk(m_general_lock);
// Check if state allows us to map.
size_t num_allocator_blocks;
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), addr, size,
KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::None,
KMemoryAttribute::None));
// Create an update allocator.
Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Perform mapping operation.
const KPageProperties properties = {perm, state == KMemoryState::Io, false,
DisableMergeAttribute::DisableHead};
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
KMemoryBlockDisableMergeAttribute::None);
// We successfully mapped the pages.
R_SUCCEED();
}
Result KPageTable::UnmapPageGroup(KProcessAddress address, const KPageGroup& pg,
KMemoryState state) {
ASSERT(!this->IsLockedByCurrentThread());
// Ensure this is a valid unmap request.
const size_t num_pages = pg.GetNumPages();
const size_t size = num_pages * PageSize;
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
// Lock the table.
KScopedLightLock lk(m_general_lock);
// Check if state allows us to unmap.
size_t num_allocator_blocks;
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
KMemoryState::All, state, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::All,
KMemoryAttribute::None));
// Check that the page group is valid.
R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), ResultInvalidCurrentMemory);
// Create an update allocator.
Result allocator_result{ResultSuccess};
Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
// Perform the unmap.
R_TRY(Operate(address, num_pages, KMemoryPermission::None, OperationType::Unmap));
// We're going to perform an update, so create a helper.
KScopedPageTableUpdater updater(this);
// Perform unmapping operation.
const KPageProperties properties = {KMemoryPermission::None, false, false,
DisableMergeAttribute::None};
R_TRY(this->Operate(address, num_pages, properties.perm, OperationType::Unmap));
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
@@ -2550,54 +2804,6 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
}
}
ResultVal<VAddr> KPageTable::AllocateAndMapMemory(size_t needed_num_pages, size_t align,
bool is_map_only, VAddr region_start,
size_t region_num_pages, KMemoryState state,
KMemoryPermission perm, PAddr map_addr) {
KScopedLightLock lk(m_general_lock);
R_UNLESS(CanContain(region_start, region_num_pages * PageSize, state),
ResultInvalidCurrentMemory);
R_UNLESS(region_num_pages > needed_num_pages, ResultOutOfMemory);
const VAddr addr{
AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)};
R_UNLESS(addr, ResultOutOfMemory);
// Create an update allocator.
Result allocator_result{ResultSuccess};
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager);
if (is_map_only) {
R_TRY(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
} else {
// Create a page group tohold the pages we allocate.
KPageGroup pg{m_kernel, m_block_info_manager};
R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(
&pg, needed_num_pages,
KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option)));
// Ensure that the page group is closed when we're done working with it.
SCOPE_EXIT({ pg.Close(); });
// Clear all pages.
for (const auto& it : pg) {
std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()),
m_heap_fill_value, it.GetSize());
}
R_TRY(Operate(addr, needed_num_pages, pg, OperationType::MapGroup));
}
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), addr, needed_num_pages, state, perm,
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
KMemoryBlockDisableMergeAttribute::None);
return addr;
}
Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
KMemoryPermission perm, bool is_aligned,
bool check_heap) {
+66 -20
View File
@@ -24,12 +24,36 @@ class System;
namespace Kernel {
enum class DisableMergeAttribute : u8 {
None = (0U << 0),
DisableHead = (1U << 0),
DisableHeadAndBody = (1U << 1),
EnableHeadAndBody = (1U << 2),
DisableTail = (1U << 3),
EnableTail = (1U << 4),
EnableAndMergeHeadBodyTail = (1U << 5),
EnableHeadBodyTail = EnableHeadAndBody | EnableTail,
DisableHeadBodyTail = DisableHeadAndBody | DisableTail,
};
struct KPageProperties {
KMemoryPermission perm;
bool io;
bool uncached;
DisableMergeAttribute disable_merge_attributes;
};
static_assert(std::is_trivial_v<KPageProperties>);
static_assert(sizeof(KPageProperties) == sizeof(u32));
class KBlockInfoManager;
class KMemoryBlockManager;
class KResourceLimit;
class KSystemResource;
class KPageTable final {
protected:
struct PageLinkedList;
public:
enum class ICacheInvalidationStrategy : u32 { InvalidateRange, InvalidateAll };
@@ -57,27 +81,12 @@ public:
Result UnmapPhysicalMemory(VAddr addr, size_t size);
Result MapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
Result UnmapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
Result MapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state,
KMemoryPermission perm);
Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
KMemoryState state, KMemoryPermission perm) {
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true,
this->GetRegionAddress(state),
this->GetRegionSize(state) / PageSize, state, perm));
}
Result UnmapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state);
Result UnmapPages(VAddr address, size_t num_pages, KMemoryState state);
Result SetProcessMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission svc_perm);
KMemoryInfo QueryInfo(VAddr addr);
Result SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission perm);
Result SetMemoryAttribute(VAddr addr, size_t size, u32 mask, u32 attr);
Result SetMaxHeapSize(size_t size);
Result SetHeapSize(VAddr* out, size_t size);
ResultVal<VAddr> AllocateAndMapMemory(size_t needed_num_pages, size_t align, bool is_map_only,
VAddr region_start, size_t region_num_pages,
KMemoryState state, KMemoryPermission perm,
PAddr map_addr = 0);
Result LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
KMemoryPermission perm, bool is_aligned, bool check_heap);
Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap);
@@ -113,6 +122,40 @@ public:
bool CanContain(VAddr addr, size_t size, KMemoryState state) const;
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
KPhysicalAddress phys_addr, KProcessAddress region_start,
size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start,
region_num_pages, state, perm));
}
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) {
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true,
this->GetRegionAddress(state),
this->GetRegionSize(state) / PageSize, state, perm));
}
Result MapPages(KProcessAddress* out_addr, size_t num_pages, KMemoryState state,
KMemoryPermission perm) {
R_RETURN(this->MapPages(out_addr, num_pages, PageSize, 0, false,
this->GetRegionAddress(state),
this->GetRegionSize(state) / PageSize, state, perm));
}
Result MapPages(KProcessAddress address, size_t num_pages, KMemoryState state,
KMemoryPermission perm);
Result UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state);
Result MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
KProcessAddress region_start, size_t region_num_pages, KMemoryState state,
KMemoryPermission perm);
Result MapPageGroup(KProcessAddress address, const KPageGroup& pg, KMemoryState state,
KMemoryPermission perm);
Result UnmapPageGroup(KProcessAddress address, const KPageGroup& pg, KMemoryState state);
void RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
const KPageGroup& pg);
protected:
struct PageLinkedList {
private:
@@ -166,11 +209,9 @@ private:
static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr =
KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared;
Result MapPages(VAddr addr, const KPageGroup& page_linked_list, KMemoryPermission perm);
Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
bool is_pa_valid, VAddr region_start, size_t region_num_pages,
KMemoryState state, KMemoryPermission perm);
Result UnmapPages(VAddr addr, const KPageGroup& page_linked_list);
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start,
size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
bool IsRegionContiguous(VAddr addr, u64 size) const;
void AddRegionToPages(VAddr start, size_t num_pages, KPageGroup& page_linked_list);
KMemoryInfo QueryInfoImpl(VAddr addr);
@@ -265,6 +306,11 @@ private:
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address,
size_t size, KMemoryPermission prot_perm);
Result AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
size_t num_pages, KMemoryPermission perm);
Result MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
const KPageGroup& pg, const KPageProperties properties, bool reuse_ll);
mutable KLightLock m_general_lock;
mutable KLightLock m_map_physical_memory_lock;
+28 -22
View File
@@ -17,35 +17,41 @@ namespace Kernel {
class KThread;
template <typename T>
concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
{ t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
{t.SetAffinityMask(0)};
concept KPriorityQueueAffinityMask = !
std::is_reference_v<T>&& requires(T& t) {
{ t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
{ t.SetAffinityMask(0) };
{ t.GetAffinity(0) } -> std::same_as<bool>;
{t.SetAffinity(0, false)};
{t.SetAll()};
};
{ t.GetAffinity(0) } -> std::same_as<bool>;
{ t.SetAffinity(0, false) };
{ t.SetAll() };
};
template <typename T>
concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
{typename T::QueueEntry()};
{(typename T::QueueEntry()).Initialize()};
{(typename T::QueueEntry()).SetPrev(std::addressof(t))};
{(typename T::QueueEntry()).SetNext(std::addressof(t))};
{ (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
{ (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
{ t.GetPriorityQueueEntry(0) } -> std::same_as<typename T::QueueEntry&>;
concept KPriorityQueueMember = !
std::is_reference_v<T>&& requires(T& t) {
{ typename T::QueueEntry() };
{ (typename T::QueueEntry()).Initialize() };
{ (typename T::QueueEntry()).SetPrev(std::addressof(t)) };
{ (typename T::QueueEntry()).SetNext(std::addressof(t)) };
{ (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
{ (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
{
t.GetPriorityQueueEntry(0)
} -> std::same_as<typename T::QueueEntry&>;
{t.GetAffinityMask()};
{ std::remove_cvref_t<decltype(t.GetAffinityMask())>() } -> KPriorityQueueAffinityMask;
{ t.GetAffinityMask() };
{
std::remove_cvref_t<decltype(t.GetAffinityMask())>()
} -> KPriorityQueueAffinityMask;
{ t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
{ t.GetPriority() } -> Common::ConvertibleTo<s32>;
{ t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
};
{ t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
{ t.GetPriority() } -> Common::ConvertibleTo<s32>;
{ t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
};
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
requires KPriorityQueueMember<Member>
requires KPriorityQueueMember<Member>
class KPriorityQueue {
public:
using AffinityMaskType = std::remove_cv_t<
+22 -12
View File
@@ -417,9 +417,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
}
void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
AllocateMainThreadStack(stack_size);
ASSERT(AllocateMainThreadStack(stack_size) == ResultSuccess);
resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size);
const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError());
@@ -675,20 +674,31 @@ void KProcess::ChangeState(State new_state) {
}
Result KProcess::AllocateMainThreadStack(std::size_t stack_size) {
ASSERT(stack_size);
// Ensure that we haven't already allocated stack.
ASSERT(main_thread_stack_size == 0);
// The kernel always ensures that the given stack size is page aligned.
main_thread_stack_size = Common::AlignUp(stack_size, PageSize);
// Ensure that we're allocating a valid stack.
stack_size = Common::AlignUp(stack_size, PageSize);
// R_UNLESS(stack_size + image_size <= m_max_process_memory, ResultOutOfMemory);
R_UNLESS(stack_size + image_size >= image_size, ResultOutOfMemory);
const VAddr start{page_table.GetStackRegionStart()};
const std::size_t size{page_table.GetStackRegionEnd() - start};
// Place a tentative reservation of memory for our new stack.
KScopedResourceReservation mem_reservation(this, Svc::LimitableResource::PhysicalMemoryMax,
stack_size);
R_UNLESS(mem_reservation.Succeeded(), ResultLimitReached);
CASCADE_RESULT(main_thread_stack_top,
page_table.AllocateAndMapMemory(
main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize,
KMemoryState::Stack, KMemoryPermission::UserReadWrite));
// Allocate and map our stack.
if (stack_size) {
KProcessAddress stack_bottom;
R_TRY(page_table.MapPages(std::addressof(stack_bottom), stack_size / PageSize,
KMemoryState::Stack, KMemoryPermission::UserReadWrite));
main_thread_stack_top += main_thread_stack_size;
main_thread_stack_top = stack_bottom + stack_size;
main_thread_stack_size = stack_size;
}
// We succeeded! Commit our memory reservation.
mem_reservation.Commit();
R_SUCCEED();
}
+6 -5
View File
@@ -9,13 +9,14 @@
namespace Kernel {
template <typename T>
concept KLockable = !std::is_reference_v<T> && requires(T & t) {
{ t.Lock() } -> std::same_as<void>;
{ t.Unlock() } -> std::same_as<void>;
};
concept KLockable = !
std::is_reference_v<T>&& requires(T& t) {
{ t.Lock() } -> std::same_as<void>;
{ t.Unlock() } -> std::same_as<void>;
};
template <typename T>
requires KLockable<T>
requires KLockable<T>
class [[nodiscard]] KScopedLock {
public:
explicit KScopedLock(T* l) : lock_ptr(l) {

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