Compare commits

...

178 Commits

Author SHA1 Message Date
german
f5110340e6 fix minor clang error 2020-11-10 10:38:15 -06:00
german
70df449d0a Allow to dial any angle with digital joystick 2020-11-08 09:15:33 -06:00
bunnei
af477fb8c5 Merge pull request #4888 from lioncash/unicorn-remove
core: Remove usage of unicorn
2020-11-06 22:39:05 -08:00
bunnei
f6a89edb67 Merge pull request #4899 from lioncash/fiberimpl
common/fiber: Move all member variables into impl class
2020-11-06 20:01:03 -08:00
Lioncash
00fb79b2f3 common/fiber: Move all member variables into impl class
Hides all of the implementation details for users of the class. This has
the benefit of reducing includes and also making the fiber classes
movable again.
2020-11-06 20:36:32 -05:00
bunnei
91a45834fd Merge pull request #4891 from lioncash/clang2
General: Fix clang build
2020-11-06 10:33:13 -08:00
bunnei
0b75ec5316 Merge pull request #4894 from lioncash/fn
settings: Simplify initializer of resolution factor
2020-11-06 09:54:02 -08:00
Lioncash
c0ab5b79dc settings: Simplify initializer of resolution factor
This can use a braced initializer to accomplish the same thing with less
code.
2020-11-05 22:07:10 -05:00
bunnei
a111a9ae2c Merge pull request #4854 from ReinUsesLisp/cube-array-shadow
shader: Partially implement texture cube array shadow
2020-11-05 16:25:00 -08:00
Lioncash
6f006d051e General: Fix clang build
Allows building on clang to work again
2020-11-05 10:07:16 -05:00
bunnei
d62d28522b Merge pull request #4889 from lioncash/setting-global
core/settings: Move configuring_global behind an API
2020-11-04 17:09:19 -08:00
bunnei
087f52e872 Merge pull request #4858 from lioncash/initializer
General: Resolve a few missing initializer warnings
2020-11-04 12:10:10 -08:00
Lioncash
7aae6d6d2b core/settings: Move configuring_global behind an API
Rather than have directly modified global state here, we can make it an
implementation detail and have an interface that changes are queried
through.
2020-11-04 04:16:37 -05:00
Chloe
6bbbbe8f85 Merge pull request #4869 from bunnei/improve-gpu-sync
Improvements to GPU synchronization & various refactoring
2020-11-04 18:36:55 +11:00
Lioncash
fc6db97a09 core: Remove usage of unicorn
Unicorn long-since lost most of its use, due to dynarmic gaining support
for handling most instructions. At this point any further issues
encountered should be used to make dynarmic better.

This also allows us to remove our dependency on Python.
2020-11-03 20:22:05 -05:00
bunnei
4bfa411ddc Merge pull request #4874 from lioncash/nodiscard2
nvdec: Make use of [[nodiscard]] where applicable
2020-11-03 16:34:07 -08:00
bunnei
46fdc94586 Merge pull request #4887 from lioncash/common-build
microprofile: Silence warning in headers
2020-11-03 13:41:29 -08:00
Lioncash
ee21b5378b microprofile: Silence warning in headers
Silences a truncation warning by making the truncation explicit and
documenting the reason for it.
2020-11-03 15:07:13 -05:00
bunnei
222fe75401 Merge pull request #4873 from lioncash/common-error
common: Enable warnings as errors
2020-11-03 11:00:23 -08:00
bunnei
448e4d5c2a Merge pull request #4878 from bunnei/unload-nrr
hle: service: ldr: Implement UnloadNrr.
2020-11-03 08:52:40 -08:00
Lioncash
4a4b685a04 common: Enable warnings as errors
Cleans up common so that we can enable warnings as errors.
2020-11-02 15:50:58 -05:00
Lioncash
4f0f481f63 nvdec: Make use of [[nodiscard]] where applicable
Prevents bugs from occurring where the results of a function are
accidentally discarded
2020-11-02 02:45:15 -05:00
bunnei
1089d76736 Merge pull request #4865 from ameerj/async-threadcount
async_shaders: Increase Async worker thread count for >8 thread cpus
2020-11-01 01:54:01 -07:00
bunnei
848bdf8a40 fixup! hle service: nvdrv: nvhost_gpu: Update to use SyncpointManager and other improvements. 2020-11-01 01:52:38 -07:00
bunnei
7d2839d7a3 core: Initialize GPU before services. 2020-11-01 01:52:38 -07:00
bunnei
e67b8678f8 hle service: nvdrv: nvhost_gpu: Update to use SyncpointManager and other improvements.
- Refactor so that SubmitGPFIFO and KickoffPB use shared functionality.
- Implement add_wait and add_increment flags.
2020-11-01 01:52:38 -07:00
bunnei
c6e1c46ac7 video_core: dma_pusher: Add support for integrity checks.
- Log corrupted command lists, rather than crash.
2020-11-01 01:52:38 -07:00
bunnei
c64545d07a video_core: dma_pusher: Add support for prefetched command lists. 2020-11-01 01:52:38 -07:00
bunnei
1d4cbb92f2 service: hle: nvflinger: Fix potential shutdown crash when GPU is destroyed. 2020-11-01 01:52:38 -07:00
bunnei
6053b95552 video_core: gpu: Implement WaitFence and IncrementSyncPoint. 2020-11-01 01:52:37 -07:00
bunnei
66edfd61c6 hle service: nvdrv: nvhost_ctrl: Update to use SyncpointManager. 2020-11-01 01:52:37 -07:00
bunnei
4a3fd97e48 hle service: nvdrv: Update to instantiate SyncpointManager. 2020-11-01 01:52:34 -07:00
bunnei
d567b7e841 hle: service: nvdrv: Implement SyncpointManager, to manage syncpoints. 2020-11-01 01:51:54 -07:00
Levi Behunin
bca9591660 Rename to align with switchbrew and remove gpu function (#4714)
* Rename to align with switchbrew

* Rename to align with switchbrew and remove gpu function that checks if clearing should be done.
2020-11-01 01:24:17 -07:00
bunnei
98f68d06f1 Merge pull request #4853 from ReinUsesLisp/fcmp-imm
shader/arithmetic: Implement FCMP immediate + register variant
2020-10-31 01:25:02 -07:00
bunnei
a0e5cccb92 hle: service: ldr: Implement UnloadNrr.
- Used by Final Fantasy X/X-2 HD Remaster.
2020-10-31 01:22:53 -07:00
LC
6db0c0d8d9 Merge pull request #4872 from jbeich/clang
video_core: unbreak -Werror in NVDEC with Clang
2020-10-30 15:11:40 -04:00
Lioncash
14a97d082e CMakeLists: Resolve MSVC build failures
Prevents the compiler tripping up about Windows headers.
2020-10-30 14:57:58 -04:00
Jan Beich
50e52ade85 video_core: unbreak -Werror in NVDEC with Clang
src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp:41:15: error: unused variable 'OutOfMemory' [-Werror,-Wunused-const-variable]
constexpr u32 OutOfMemory{static_cast<u32>(-12)};
              ^
2020-10-30 16:43:10 +00:00
bunnei
8aa9ae5ba5 Merge pull request #4868 from lioncash/discard-error
General: Make ignoring a discarded return value an error
2020-10-30 00:35:40 -07:00
bunnei
131a75b65d Merge pull request #4867 from lioncash/vp9
VP9: Minor interface changes and safety improvements
2020-10-29 21:33:27 -07:00
Lioncash
11d0a6e7b8 General: Catch more expressions with no effect on MSVC
MSVC lets us fine-tune catching expressions with no side-effects a
little more.
2020-10-30 00:13:26 -04:00
Lioncash
26547d3e3b General: Make ignoring a discarded return value an error
Allows our CI to catch more potential bugs. This also removes the
[[nodiscard]] attribute of IOFile's Open member function. There are
cases where a file may want to be opened, but have the status of it
checked at a later time.
2020-10-30 00:13:21 -04:00
Lioncash
8049b8beb6 common/stream: Be explicit with copy and move operators 2020-10-29 22:57:35 -04:00
Lioncash
12eeffcb7c vp9: Be explicit with copy and move operators
It's deprecated in the language to autogenerate these if the destructor
for a type is specified, so we can explicitly specify how we want these
to be generated.
2020-10-29 22:57:35 -04:00
Lioncash
0d713cf8eb vp9: Mark functions with [[nodiscard]] where applicable
Prevents values from mistakenly being discarded in cases where it's a
bug to do so.
2020-10-29 22:57:32 -04:00
Lioncash
badea3b301 vp9: Provide a default initializer for "hidden" member
The API of VP9 exposes a WasFrameHidden() function which accesses this
member. Given the constructor previously didn't initialize this member,
it's a potential vector for an uninitialized read.

Instead, we can initialize this to a deterministic value to prevent that
from occurring.
2020-10-29 22:35:55 -04:00
Lioncash
f8543249f0 vp9: Make some member functions internally linked
These helper functions don't directly modify any member state and can be
hidden from view.
2020-10-29 22:34:46 -04:00
Lioncash
5553bd3ba2 General: Resolve a few missing initializer warnings
Resolves a few -Wmissing-initializer warnings.
2020-10-29 19:37:07 -04:00
bunnei
7dcf4c0018 Merge pull request #4831 from lioncash/fmt
externals: Update fmt to 7.1.0
2020-10-29 14:44:07 -07:00
bunnei
ef29bf4515 Merge pull request #4837 from lioncash/nvdec-2
nvdec: Minor tidying up
2020-10-29 12:28:07 -07:00
ameerj
3620206136 async_shaders: Increase Async worker thread count for 8+ thread cpus
Adds 1 async worker thread for every 2 available threads above 8
2020-10-29 14:16:45 -04:00
bunnei
2dbb144fc6 Merge pull request #4781 from german77/GChotplug
Add hotplug, rumble and fix 3rd party adapters for the GC adapter
2020-10-29 10:28:19 -07:00
David
89199ca215 Merge pull request #4859 from Morph1984/missing-ctime-include
kernel/process: Add missing <ctime> include
2020-10-29 19:03:19 +11:00
Morph
9cfc5fee2f kernel/process: Add missing <ctime> include
Fixes compilation on MSVC
2020-10-29 03:17:20 -04:00
LC
1a6b1bf1d7 Merge pull request #4857 from liushuyu/master
web_service: follow-up fix to #4842
2020-10-29 01:54:45 -04:00
bunnei
c5134cbf3a Merge pull request #4835 from lat9nq/rng-default-time
kernel: Use the current time as the default RNG seed
2020-10-28 22:51:29 -07:00
bunnei
c6d001c94f Merge pull request #4838 from lioncash/syncmgr
sync_manager: Amend parameter order of calls to SyncptIncr constructor
2020-10-28 22:49:22 -07:00
liushuyu
cf63eacc1a web_service: follow-up fix to #4842 ...
* The web_service http request is now fixed on Windows (R) platform.
* The issue is due to a complicated race-condition in `httplib`, a detailed
  explanation is available at https://github.com/yhirose/cpp-httplib/pull/701
* A pending Pull Request on `httplib` has been applied to remedy the
  said race-condition.
* The socket availability check is removed due to a behavioral chice of
  `httplib` that a socket will not be created before any actual request
  is sent.
2020-10-28 23:16:06 -06:00
german
5333db91c1 Add hotplug, rumble and fix 3rd party adapters for the GC adapter 2020-10-28 21:12:34 -05:00
LC
c20569ebdf Merge pull request #4856 from bunnei/webservice-socket-error
web_service: web_backend: Handle socket errors with GenericRequest.
2020-10-28 20:46:28 -04:00
bunnei
156556ddd2 web_service: web_backend: Handle socket errors with GenericRequest.
- Fixes a shutdown crash when we try to submit telemetry if there is a service issue.
2020-10-28 17:19:12 -07:00
LC
475d46bb64 Merge pull request #4855 from bunnei/cdma-pusher-log-fix
video_core: cdma_pusher: Add missing LOG_DEBUG field in ExecuteCommand.
2020-10-28 20:01:29 -04:00
bunnei
94eca09cf6 video_core: cdma_pusher: Add missing LOG_DEBUG field in ExecuteCommand. 2020-10-28 16:47:08 -07:00
bunnei
7af2cb4318 Merge pull request #4846 from lioncash/service-fn
service: Update function tables
2020-10-28 13:47:56 -07:00
ReinUsesLisp
657771bdcb shader: Partially implement texture cube array shadow
This implements texture cube arrays with shadow comparisons but doesn't
fix the asserts related to it.

Fixes out of bounds reads on swizzle constructors and makes them use
bounds checked ::at instead of the unsafe operator[].
2020-10-28 17:12:40 -03:00
ReinUsesLisp
44b552be71 shader/arithmetic: Implement FCMP immediate + register variant
Trivially add the encoding for this.
2020-10-28 17:05:41 -03:00
bunnei
663e221f99 Merge pull request #4845 from lioncash/inih
externals: Track upstream inih
2020-10-28 09:58:58 -07:00
LC
725fcbb368 Merge pull request #4851 from ReinUsesLisp/core-threads-race
hle/kernel: Remove unused registered_core_threads to fix data races
2020-10-28 04:54:35 -04:00
LC
a1f176ce52 Merge pull request #4850 from ReinUsesLisp/fiber-ptr-ref
common/fiber: Take shared_ptr<Fiber> by copy in YieldTo
2020-10-28 04:54:19 -04:00
LC
1fd22823bc Merge pull request #4849 from ReinUsesLisp/fix-fiber-test
tests: Fix data race in fibers test
2020-10-28 04:26:10 -04:00
LC
978e7897a3 Merge pull request #4848 from ReinUsesLisp/type-limits
video_core: Enforce -Werror=type-limits
2020-10-28 03:16:10 -04:00
LC
55ac6f7a2b Merge pull request #4847 from ReinUsesLisp/warn-move
video_core: Enforce -Wredundant-move and -Wpessimizing-move
2020-10-28 03:14:58 -04:00
ReinUsesLisp
79da90cea8 video_core: Enforce -Wredundant-move and -Wpessimizing-move
Silence three warnings and make them errors to avoid introducing more in the future.
2020-10-28 02:44:50 -03:00
ReinUsesLisp
4a451e5849 video_core: Enforce -Werror=type-limits
Silences one warning and avoids introducing more in the future.
2020-10-28 02:37:47 -03:00
ReinUsesLisp
cdb2480d39 common/fiber: Take shared_ptr<Fiber> by copy in YieldTo
YieldTo does not intend to modify the passed shared_ptrs.
Pass it by copy to keep a reference count while this function executes.
2020-10-28 02:02:44 -03:00
ReinUsesLisp
3fdb42e0b4 tests: Fix data race in fibers test
Previous to this commit, the tests were using operator[] from
unordered_map to query elements but this silently inserts empty elements
when they don't exist. If all threads were executed without concurrency,
this wouldn't be an issue, but the same unordered_map could be written
from two threads at the same time. This is a data race and makes some
previously inserted elements invisible for a short period of time,
causing them to insert and return an empty element. This default
constructed element (a zero) was used to index an array of fibers that
asserted when one of them was nullptr, shutting the test session off.

To address this issue, lock on thread id reads and writes. This could be
a shared mutex to allow concurrent reads, but the definition of
std::this_thread::get_id is fuzzy when using non-standard techniques
like fibers. I opted to use a standard mutex.

While we are at it, fix the included headers.
2020-10-28 01:41:24 -03:00
Lioncash
020519def8 service: Update function tables
Updates function tables according to info on SwitchBrew.
2020-10-27 21:19:46 -04:00
Lioncash
9a44c1ea27 externals: Update inih to r52 2020-10-27 19:52:48 -04:00
Lioncash
65e697de59 externals: Track mainline inih project 2020-10-27 19:52:48 -04:00
LC
7d27a7a511 Merge pull request #4842 from liushuyu/fix-web-srv
web_backend: fix a regression introduced in 39c8d18
2020-10-27 19:12:27 -04:00
liushuyu
eb84e0f63a externals: auto detect system OpenSSL 2020-10-27 14:20:20 -06:00
liushuyu
8e673cbb08 web_backend: fix a regression introduced in 39c8d18
* A regression was in 39c8d18 and token verification function was
  broken.
* The reason being `httplib` now requires OpenSSL 1.1+ API while
  LibreSSL 2.x provided OpenSSL 1.0 compatible API.
* The bundled LibreSSL has been updated to 3.2.2 so it now provides
  OpenSSL 1.1 compatible API now.
* Also the path hint has been added so that it will find the correct
  path to the CA certs on *nix systems.
* An option is provided so that *nix system distributions/providers can
  use their own SSL implementations when compiling Yuzu/Citra to
  (hopefully) complies with their maintenance guidelines.
* LURLParse is also removed since `httplib` can handle
  `scheme:host:port` string itself now.
2020-10-27 02:57:19 -06:00
Lioncash
047e77e2f0 sync_manager: Amend parameter order of calls to SyncptIncr constructor
Corrects some cases where the arguments would be incorrectly swapped.
2020-10-27 03:22:57 -04:00
Lioncash
cce14b4cd7 h264: Make WriteUe take a u32
Enforces the type of the desired value in calling code.
2020-10-27 03:21:53 -04:00
Lioncash
6291975731 vp9: std::move buffer within ComposeFrameHeader()
We can move the buffer here to avoid a heap reallocation
2020-10-27 02:27:31 -04:00
Lioncash
00decfbb07 vp9: Remove dead code 2020-10-27 02:26:17 -04:00
Lioncash
111802bbbb vp9: Join declarations with assignments 2020-10-27 02:26:03 -04:00
Lioncash
3b5d5fa86f vp9: Remove pessimizing moves
The move will already occur without std::move.
2020-10-27 02:21:40 -04:00
Lioncash
dcc26c54a5 vp9: Resolve variable shadowing 2020-10-27 02:20:17 -04:00
Lioncash
c04203b786 nvdec: Tidy up header includes
Prevents a few unnecessary inclusions.
2020-10-27 02:16:42 -04:00
bunnei
cd92a94965 Merge pull request #4805 from bunnei/update-defaults
yuzu: settings: Enable multicore, asynch GPU, and assembly shaders by default.
2020-10-26 23:14:09 -07:00
bunnei
941563f981 yuzu: settings: Enable multicore, asynch GPU, and assembly shaders by default.
- In general, this is now the preferred settings for most games.

# Conflicts:
#	src/yuzu/configuration/config.cpp
2020-10-26 23:13:05 -07:00
bunnei
d33399e1f4 Merge pull request #4729 from ameerj/nvdec-prod
video_core: NVDEC Implementation
2020-10-26 23:02:42 -07:00
ReinUsesLisp
ce69ff2890 hle/kernel: Remove unused registered_core_threads to fix data races
This member was only used on asserts and it triggered data races.
Remove it to fix them.
2020-10-27 01:55:39 -03:00
bunnei
c7f32931ee Merge pull request #4832 from bunnei/cpu-manager-microprofile-fix
core: cpu_manager: Add missing call to MicroProfileOnThreadExit().
2020-10-26 21:29:09 -07:00
bunnei
1828f82000 Merge pull request #4833 from bunnei/timezonemanager-explicit
hle: services: TimeZoneContentManager: This can be made explicit.
2020-10-26 21:28:45 -07:00
ameerj
eb67a45ca8 video_core: NVDEC Implementation
This commit aims to implement the NVDEC (Nvidia Decoder) functionality, with video frame decoding being handled by the FFmpeg library.

The process begins with Ioctl commands being sent to the NVDEC and VIC (Video Image Composer) emulated devices. These allocate the necessary GPU buffers for the frame data, along with providing information on the incoming video data. A Submit command then signals the GPU to process and decode the frame data.

To decode the frame, the respective codec's header must be manually composed from the information provided by NVDEC, then sent with the raw frame data to the ffmpeg library.

Currently, H264 and VP9 are supported, with VP9 having some minor artifacting issues related mainly to the reference frame composition in its uncompressed header.

Async GPU is not properly implemented at the moment.

Co-Authored-By: David <25727384+ogniK5377@users.noreply.github.com>
2020-10-26 23:07:36 -04:00
bunnei
9f08cea2c4 Merge pull request #4834 from lioncash/copy-fn
controller: Pass ControllerParameters by reference in ReconfigureControllers()
2020-10-26 18:49:26 -07:00
lat9nq
8bd246032a kernel: Use the current time as the default RNG seed
Use the current time, not zero, as the default RNG seed.
2020-10-26 21:42:11 -04:00
Lioncash
6b5f565324 controller: Pass ControllerParameters by reference in ReconfigureControllers()
Prevents unnecessary copies and heap reallocations from occurring.
2020-10-26 21:06:15 -04:00
bunnei
3984bb6def hle: services: TimeZoneContentManager: This can be made explicit. 2020-10-26 16:11:45 -07:00
bunnei
54aabb00b0 core: cpu_manager: Add missing call to MicroProfileOnThreadExit().
- Fixes an occasional crash when trying to launch subsequent games.
2020-10-26 16:09:15 -07:00
Lioncash
1dd4132eb1 externals: Update fmt to 7.1.0
Keeps the used version of the library up to date.
2020-10-26 18:34:44 -04:00
Rodrigo Locatti
2f6ba54483 Merge pull request #4827 from lioncash/trunc
controller: Convert led_patterns integer literals to bool literals
2020-10-25 16:56:30 -03:00
Rodrigo Locatti
ae3a755d13 Merge pull request #4828 from lioncash/lockguard
general: Use template deduction guides for lock_guard
2020-10-25 16:55:54 -03:00
Lioncash
98f4c5e7b8 general: Use template deduction guides for lock_guard
Same behavior, less code.
2020-10-25 13:53:22 -04:00
Lioncash
061a63547f controller: Convert led_patterns integer literals to bool literals
'bool' isn't always guaranteed to be the same size as an int, so this
can technically cause truncation warnings if we support other platforms.
2020-10-25 13:44:12 -04:00
LC
fe53ee26ce Merge pull request #4826 from Morph1984/resolve-warning
applets/profile_select: Resolve a warning in exec()
2020-10-25 11:47:09 -04:00
Morph
9afbcd9e8a applets/profile_select: Resolve a warning in exec()
Resolves a warning where not all control paths return a value.
2020-10-25 09:16:43 -04:00
bunnei
ab052cf684 Merge pull request #4817 from Kewlan/open-single-save-location
main/profile_select: Don't ask for profile when there's only one.
2020-10-24 03:02:19 -07:00
LC
6f6d83befa Merge pull request #4816 from Morph1984/controller-disconnect-fix
sdl_impl: Fix controller reconnection issues
2020-10-23 13:53:51 -04:00
bunnei
3e46934442 Merge pull request #4706 from ReinUsesLisp/cmake-host-shaders
video_core: Fix instances where msbuild always regenerated host shaders
2020-10-23 10:01:16 -07:00
bunnei
e7042163c8 Merge pull request #4792 from bunnei/rtc-fix
service: time: Update current time with changes to RTC setting.
2020-10-22 20:46:54 -07:00
Kewlan
85b5b816cf Don't ask for profile when there's only one. 2020-10-22 11:16:56 +02:00
Lioncash
ea20b5c970 core: Fix clang build pt.3
Should finally resolve building with clang.
2020-10-21 22:14:23 -04:00
Morph
2f852f182a sdl_impl: Fix controller reconnection issues
It turns out that after a controller is disconnected, there is a chance that events from the previous controller are sent/processed after it has been disconnected.
This causes the previously disconnected controller to reappear as connected due to GetSDLJoystickBySDLID() emplacing this controller back to the map.

Fix this by only returning an SDLJoystick if and only if it exists in the map.
2020-10-21 09:41:30 -04:00
bunnei
1fc61d09d3 Merge pull request #4811 from lioncash/warn-video
video_core: Conditially activate relevant compiler warnings
2020-10-20 20:59:37 -07:00
Lioncash
e408bd3b7c core: Fix clang build pt.2
Resolves the clang build issue in a more unintrusive way.
2020-10-20 22:16:03 -04:00
LC
2e74b79e89 Merge pull request #4814 from yuzu-emu/revert-4796-clang
Revert "core: Fix clang build"
2020-10-20 22:08:53 -04:00
bunnei
3d592972dc Revert "core: Fix clang build" 2020-10-20 19:07:39 -07:00
Lioncash
678d012c2c video_core: Conditially activate relevant compiler warnings
These compiler flags aren't shared with clang, so specifying these flags
unconditionally can lead to a bit of warning spam.

While we're in the area, we can also enable -Wunused-but-set-parameter
given this is almost always a bug.
2020-10-20 20:28:25 -04:00
Lioncash
fdd9154069 kernel: Fix build with recent compiler flag changes
This slipped through the cracks due to another change being merged
before the compiler flag changes.
2020-10-20 20:23:18 -04:00
LC
536c51912d Merge pull request #4807 from ReinUsesLisp/glasm-robust-ssbo
gl_arb_decompiler: Implement robust buffer operations
2020-10-20 19:19:38 -04:00
LC
88d5140cf2 Merge pull request #4796 from lioncash/clang
core: Fix clang build
2020-10-20 19:19:12 -04:00
bunnei
940c3bf68d Merge pull request #4390 from ogniK5377/get-applet-inf-stub
nifm: GetAppletInfo stub
2020-10-20 15:59:19 -07:00
LC
ea8345cdcd Merge pull request #4809 from Morph1984/mjolnir-p3
configure_input_player: Fix modifier buttons
2020-10-20 15:00:06 -04:00
bunnei
e03dc4d569 Merge pull request #4627 from Morph1984/fix-dinput-controller-disconnect
sdl_impl: Erase the SDLJoystick entry after removing a controller
2020-10-20 11:40:06 -07:00
Morph
ff82f3894a configure_input_player: Fix modifier buttons
Fix them for real this time, now they finally work.
2020-10-20 14:23:25 -04:00
ReinUsesLisp
f21a189148 gl_arb_decompiler: Implement robust buffer operations
This emulates the behavior we get on GLSL with regular SSBOs with a
pointer + length pair. It aims to be consistent with the crashes we
might get.

Out of bounds stores are ignored. Atomics are ignored and return zero.
Reads return zero.
2020-10-20 03:34:32 -03:00
David Marcec
298b50e220 Added remaining params 2020-10-20 16:45:01 +11:00
David Marcec
acd35e1b60 nifm: GetAppletInfo stub
Fixes crash for Catherine Full Body
2020-10-20 16:42:40 +11:00
bunnei
60bd54776a Merge pull request #4788 from ReinUsesLisp/lockfree-host-thread
kernel: Implement host thread register methods without locking
2020-10-19 22:31:52 -07:00
bunnei
e7a26ecec5 Merge pull request #4785 from Morph1984/fs-hades
filesystem: Fix CreateDirectory and DeleteFile
2020-10-19 16:04:01 -07:00
bunnei
f1ead11df7 Merge pull request #4204 from ReinUsesLisp/vulkan-1.0
renderer_vulkan: Create and properly use Vulkan 1.0 instances when 1.1 is not available
2020-10-19 14:18:54 -07:00
bunnei
598ef6b0b3 Merge pull request #4802 from lioncash/bcat
core: Add boxcat sources with target_sources
2020-10-19 12:40:49 -07:00
bunnei
54b977acaa Merge pull request #4783 from bunnei/nvdrv-freespace
hle: service: nvdrv: Implement nvhost_as_gpu::FreeSpace.
2020-10-18 12:41:18 -07:00
Lioncash
0ab7bfdfce core: Add boxcat sources with target_sources
Same behavior, minus a script variable.
2020-10-18 08:09:06 -04:00
bunnei
2190f1a2b7 Merge pull request #4801 from lioncash/missing-bound
mii/manager: Make use of unused lower bound in GetRandomValue()
2020-10-17 23:32:40 -07:00
bunnei
743fe1aea3 Merge pull request #4782 from ReinUsesLisp/remove-dyn-primitive
vk_graphics_pipeline: Manage primitive topology as fixed state
2020-10-17 22:14:17 -07:00
Lioncash
be1954e04c core: Fix clang build
Recent changes to the build system that made more warnings be flagged as
errors caused building via clang to break.

Fixes #4795
2020-10-17 19:50:39 -04:00
Lioncash
c1577f3448 mii/manager: Make use of unused lower bound in GetRandomValue()
Previously, the lower bound wasn't being used and zero was being used as
the lower bound every time this function was called.

This affects the outcome of some of the randomized entries a little bit,
for example, the lower-bound for beard and mustache flags was supposed
to be 1, not 0.

Aside from these cases, the bug didn't affect anything else.
2020-10-17 09:50:04 -04:00
bunnei
1eb908bc88 Merge pull request #4797 from bunnei/bcat-errors
service: bcat: Check client connection before interacting with socket.
2020-10-16 23:28:40 -07:00
bunnei
cb708631b6 Merge pull request #4798 from lioncash/input-copy
udp/client: Take std::function by const reference with TestCommunication()
2020-10-16 21:20:01 -07:00
bunnei
363c644730 service: bcat: Check client connection before interacting with socket.
- Fixes a crash when BCAT service is offline.
2020-10-16 21:16:56 -07:00
Lioncash
30b1e71066 udp/client: Make use of designated initializers in TestCommunication()
Same behavior, but makes the callback list nicer to look at.
2020-10-16 06:23:51 -04:00
Lioncash
36cfb234d5 udp/client: Take std::function by const reference with TestCommunication()
Avoids redundant copies.
2020-10-16 06:22:29 -04:00
Morph
7b3f5845d2 sdl_impl: Erase the SDLJoystick entry after removing a controller
Previously, disconnecting a controller still leaves a null SDLJoystick entry within the vector of SDLJoysticks mapped by GUID.
When a DirectInput device of the same GUID is reconnected, it adds that device to a new port causing non-detectable input.
Furthermore, opening the "Configure" menu would cause yuzu to crash since it first tries to resolve the name of a null SDLJoystick entry that was not removed.
Resolve this by properly erasing the SDLJoystick entry from the vector.
2020-10-16 00:04:59 -04:00
bunnei
64f967fd49 Merge pull request #4790 from lioncash/input-common
input_common/CMakeLists: Make some warnings errors
2020-10-15 20:59:34 -07:00
bunnei
dbd1662ae2 Merge pull request #4784 from bunnei/cancelbuffer
hle: service: vi: Implement BufferQueue::CancelBuffer.
2020-10-15 19:57:27 -07:00
Lioncash
046c0c91a3 input_common/CMakeLists: Make some warnings errors
Makes the input_common code warnings consistent with the rest of the
codebase.
2020-10-15 19:37:51 -04:00
bunnei
046cc81938 Merge pull request #4793 from bunnei/storeopencontext
service: acc: Stub IManagerForApplication::StoreOpenContext.
2020-10-14 20:42:18 -07:00
bunnei
1d714c8c7f service: acc: Stub IManagerForApplication::StoreOpenContext.
- Used by Super Mario 3D All-Stars.
2020-10-14 20:06:33 -07:00
bunnei
d47ac3ce09 Merge pull request #4772 from goldenx86/block-rdna
vk_device: Block VK_EXT_extended_dynamic_state for RDNA devices
2020-10-14 17:51:39 -07:00
bunnei
1f186f34a2 hle: service: vi: Implement BufferQueue::CancelBuffer.
- This is used by Super Mario 3D All-Stars.
2020-10-13 22:11:52 -07:00
bunnei
ca416a0fb8 Merge pull request #4787 from lioncash/conversion
audio_core/CMakeLists: Make warnings consistent with core
2020-10-13 15:30:30 -07:00
ReinUsesLisp
b9a9b83bee kernel: Implement host thread register methods without locking
Locks on GetCurrentHostThreadID were causing performance issues
according to Visual Studio's profiler. It was consuming twice the time
as arm_interface.Run(). The cost was not in the function itself but in
the lockinig it required.

Reimplement these functions using atomics and static storage instead of
an unordered_map. This is a side effect to avoid locking and using linked
lists for reads.

Replace unordered_map with a linear search.
2020-10-13 18:00:25 -03:00
Lioncash
9f9b64d280 audio_core/CMakeLists: Make warnings consistent with core
Normalizes the warnings shared between audio_core and core.
2020-10-13 16:36:58 -04:00
Rodrigo Locatti
c5b3c8d06b Merge pull request #4786 from lioncash/flags
core/CMakeLists: Make some warnings errors
2020-10-13 16:20:44 -03:00
Lioncash
39c8d18feb core/CMakeLists: Make some warnings errors
Makes our error coverage a little more consistent across the board by
applying it to Linux side of things as well. This also makes it more
consistent with the warning settings in other libraries in the project.

This also updates httplib to 0.7.9, as there are several warning
cleanups made that allow us to enable several warnings as errors.
2020-10-13 13:16:49 -04:00
ReinUsesLisp
e4e0abc418 vk_graphics_pipeline: Manage primitive topology as fixed state
Vulkan has requirements for primitive topologies that don't play nicely
with yuzu's. Since it's only 4 bits, we can move it to fixed state
without changing the size of the pipeline key.

- Fixes a regression on recent Nvidia drivers on Fire Emblem: Three
  Houses.
2020-10-13 04:08:33 -03:00
Morph
8db3feae19 filesystem: Fix CreateDirectory and DeleteFile
Add a check if dir is nullptr (does not exist)

Fixes save game creation in Hades
2020-10-13 00:57:04 -04:00
bunnei
62c6c9f6a6 service: time: Update current time with changes to RTC setting.
- This can be used to advance time, e.g. for Pokemon Sword/Shield pokejobs.
2020-10-12 18:09:15 -07:00
bunnei
d291fc1a51 Merge pull request #3929 from FearlessTobi/ticket-keys
file_sys/nsp: Make SetTicketKeys actually do something
2020-10-12 17:58:36 -07:00
bunnei
b260847218 hle: service: nvdrv: Implement nvhost_as_gpu::FreeSpace.
- This is used by Super Mario 3D All-Stars.
2020-10-12 17:39:14 -07:00
bunnei
4c348f4069 Merge pull request #4766 from ReinUsesLisp/tmml-cube
shader/texture: Implement CUBE texture type for TMML and fix arrays
2020-10-12 12:53:57 -07:00
bunnei
419a59a7b1 Merge pull request #4775 from ReinUsesLisp/enforce-class-memaccess
video_core: Enforce -Wclass-memaccess
2020-10-09 23:38:02 -07:00
bunnei
f250011ba0 Merge pull request #4757 from german77/BetterMotion
InputCommon: Add compatibility with only accelerometer and auto calibrate for drift
2020-10-09 23:37:08 -07:00
ReinUsesLisp
e1600b0962 video_core: Enforce -Wclass-memaccess 2020-10-09 16:46:11 -03:00
LC
61b246a3a9 Merge pull request #4771 from ReinUsesLisp/warn-unused-var
video_core: Enforce -Wunused-variable and -Wunused-but-set-variable
2020-10-08 21:10:31 -04:00
ReinUsesLisp
dffaffaac1 shader/texture: Implement CUBE texture type for TMML and fix arrays
TMML takes an array argument that has no known meaning, this one appears
as the first component in gpr8 followed by s, t and r. Skip this
component when arrays are being used. Also implement CUBE texture types.

- Used by Pikmin 3: Deluxe Demo.
2020-10-07 23:17:46 -03:00
german
a54aee290f Address comments 2020-10-04 18:15:53 -05:00
german
a220d8799e Add compatibility with only accelerometer and auto calibrate for drift 2020-10-03 22:22:01 -05:00
ReinUsesLisp
2a24b1c973 video_core: Enforce -Wunused-variable and -Wunused-but-set-variable 2020-10-02 21:19:35 -03:00
ReinUsesLisp
67af0323f0 video_core: Fix instances where msbuild always regenerated host shaders
When HEADER_GENERATOR was included in the DEPENDS section of custom
commands, msbuild assumed this was always modified. Changing this file
is not common so we can remove it from there.
2020-09-23 22:27:17 -03:00
ReinUsesLisp
c5a78f4480 vk_device: Use Vulkan 1.0 properly
Enable the required capabilities to use Vulkan 1.0 without validation
errors and disable those that are not compatible with it.
2020-08-20 16:55:22 -03:00
ReinUsesLisp
29a0ca2391 renderer_vulkan: Create a Vulkan 1.0 instance when 1.1 is not available
This commit doesn't make yuzu compatible with Vulkan 1.0 yet, it only
creates an 1.0 instance.
2020-08-20 16:55:22 -03:00
FearlessTobi
4d4bbe756f file_sys/nsp: Make SetTicketKeys actually do something
Previously, the method wasn't modifying any class state and therefore not having any effects when called.
Since this has been the case for a very long time now, I'm not sure if we couldn't just remove this method altogether.
2020-07-18 02:02:39 +02:00
230 changed files with 10257 additions and 4321 deletions

5
.gitmodules vendored
View File

@@ -1,15 +1,12 @@
[submodule "inih"]
path = externals/inih/inih
url = https://github.com/svn2github/inih
url = https://github.com/benhoyt/inih.git
[submodule "cubeb"]
path = externals/cubeb
url = https://github.com/kinetiknz/cubeb.git
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git
[submodule "unicorn"]
path = externals/unicorn
url = https://github.com/yuzu-emu/unicorn
[submodule "soundtouch"]
path = externals/soundtouch
url = https://github.com/citra-emu/ext-soundtouch.git

View File

@@ -4,16 +4,8 @@ cd /yuzu
# override Travis CI unreasonable ccache size
echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf"
# Dirty hack to trick unicorn makefile into believing we are in a MINGW system
mv /bin/uname /bin/uname1 && echo -e '#!/bin/sh\necho MINGW64' >> /bin/uname
chmod +x /bin/uname
# Dirty hack to trick unicorn makefile into believing we have cmd
echo '' >> /bin/cmd
chmod +x /bin/cmd
mkdir build && cd build
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
ninja
# Clean up the dirty hacks

View File

@@ -3,7 +3,7 @@
cd /yuzu
mkdir build && cd build
cmake .. -G Ninja -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
cmake .. -G Ninja -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
ninja
ccache -s

View File

@@ -4,13 +4,12 @@ set -o pipefail
export MACOSX_DEPLOYMENT_TARGET=10.14
export Qt5_DIR=$(brew --prefix)/opt/qt5
export UNICORNDIR=$(pwd)/externals/unicorn
export PATH="/usr/local/opt/ccache/libexec:$PATH"
# TODO: Build using ninja instead of make
mkdir build && cd build
cmake --version
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
cmake .. -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
make -j4
ccache -s

View File

@@ -18,8 +18,6 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "EN
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON)
@@ -161,7 +159,7 @@ macro(yuzu_find_packages)
# Cmake Pkg Prefix Version Conan Pkg
"Boost 1.73 boost/1.73.0"
"Catch2 2.13 catch2/2.13.0"
"fmt 7.0 fmt/7.0.3"
"fmt 7.1 fmt/7.1.0"
# can't use until https://github.com/bincrafters/community/issues/1173
#"libzip 1.5 libzip/1.5.2@bincrafters/stable"
"lz4 1.8 lz4/1.9.2"
@@ -263,6 +261,7 @@ if (CONAN_REQUIRED_LIBS)
libzip:with_openssl=False
libzip:enable_windows_crypto=False
)
conan_check(VERSION 1.24.0 REQUIRED)
# Add the bincrafters remote
conan_add_remote(NAME bincrafters
@@ -354,85 +353,23 @@ if (NOT LIBUSB_FOUND)
set(LIBUSB_LIBRARIES usb)
endif()
# Use system installed ffmpeg.
if (NOT MSVC)
find_package(FFmpeg REQUIRED)
else()
set(FFMPEG_EXT_NAME "ffmpeg-4.2.1")
set(FFMPEG_PATH "${CMAKE_BINARY_DIR}/externals/${FFMPEG_EXT_NAME}")
download_bundled_external("ffmpeg/" ${FFMPEG_EXT_NAME} "")
set(FFMPEG_FOUND YES)
set(FFMPEG_INCLUDE_DIR "${FFMPEG_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
set(FFMPEG_LIBRARY_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg library" FORCE)
set(FFMPEG_DLL_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
endif()
# Prefer the -pthread flag on Linux.
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
# If unicorn isn't found, msvc -> download bundled unicorn; everyone else -> build external
if (YUZU_USE_BUNDLED_UNICORN)
if (MSVC)
message(STATUS "unicorn not found, falling back to bundled")
# Detect toolchain and platform
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
set(UNICORN_VER "unicorn-yuzu")
else()
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
endif()
if (DEFINED UNICORN_VER)
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
endif()
if (DEFINED UNICORN_VER)
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
endif()
set(UNICORN_FOUND YES)
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/lib/x64/unicorn_dynload.lib" CACHE PATH "Path to Unicorn library" FORCE)
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/lib/x64/" CACHE PATH "Path to unicorn.dll" FORCE)
else()
message(STATUS "unicorn not found, falling back to externals")
if (MINGW)
set(UNICORN_LIB_NAME "unicorn.a")
else()
set(UNICORN_LIB_NAME "libunicorn.a")
endif()
set(UNICORN_FOUND YES)
set(UNICORN_PREFIX ${PROJECT_SOURCE_DIR}/externals/unicorn)
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/${UNICORN_LIB_NAME}" CACHE PATH "Path to Unicorn library" FORCE)
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/" CACHE PATH "Path to unicorn dynamic library" FORCE)
find_package(PythonInterp 2.7 REQUIRED)
if (MINGW)
# Intentionally call the unicorn makefile directly instead of using make.sh so that we can override the
# UNAME_S makefile variable to MINGW. This way we don't have to hack at the uname binary to build
# Additionally, overriding DO_WINDOWS_EXPORT prevents unicorn from patching the static unicorn.a by using msvc and cmd,
# which are both things we don't have in a mingw cross compiling environment.
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-gcc-ar RANLIB=x86_64-w64-mingw32-gcc-ranlib make UNAME_S=MINGW DO_WINDOWS_EXPORT=0
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
else()
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
endif()
# ALL makes this custom target build every time
# but it won't actually build if LIBUNICORN_LIBRARY is up to date
add_custom_target(unicorn-build ALL
DEPENDS ${LIBUNICORN_LIBRARY}
)
unset(UNICORN_LIB_NAME)
endif()
else()
find_package(Unicorn REQUIRED)
endif()
if (UNICORN_FOUND)
add_library(unicorn INTERFACE)
add_dependencies(unicorn unicorn-build)
target_link_libraries(unicorn INTERFACE "${LIBUNICORN_LIBRARY}")
target_include_directories(unicorn INTERFACE "${LIBUNICORN_INCLUDE_DIR}")
else()
message(FATAL_ERROR "Could not find or build unicorn which is required.")
endif()
# Platform-specific library requirements
# ======================================

View File

@@ -0,0 +1,10 @@
function(copy_yuzu_FFmpeg_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
windows_copy_files(${target_dir} ${FFMPEG_DLL_DIR} ${DLL_DEST}
avcodec-58.dll
avutil-56.dll
swresample-3.dll
swscale-5.dll
)
endfunction(copy_yuzu_FFmpeg_deps)

View File

@@ -1,9 +0,0 @@
function(copy_yuzu_unicorn_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
windows_copy_files(${target_dir} ${UNICORN_DLL_DIR} ${DLL_DEST}
libgcc_s_seh-1.dll
libwinpthread-1.dll
unicorn.dll
)
endfunction(copy_yuzu_unicorn_deps)

View File

@@ -73,23 +73,29 @@ if (NOT LIBZIP_FOUND)
endif()
if (ENABLE_WEB_SERVICE)
# LibreSSL
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
add_subdirectory(libressl EXCLUDE_FROM_ALL)
target_include_directories(ssl INTERFACE ./libressl/include)
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
get_directory_property(OPENSSL_LIBRARIES
DIRECTORY libressl
DEFINITION OPENSSL_LIBS)
# lurlparser
add_subdirectory(lurlparser EXCLUDE_FROM_ALL)
find_package(OpenSSL 1.1)
if (OPENSSL_FOUND)
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
else()
# LibreSSL
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
set(OPENSSLDIR "/etc/ssl/")
add_subdirectory(libressl EXCLUDE_FROM_ALL)
target_include_directories(ssl INTERFACE ./libressl/include)
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
get_directory_property(OPENSSL_LIBRARIES
DIRECTORY libressl
DEFINITION OPENSSL_LIBS)
endif()
# httplib
add_library(httplib INTERFACE)
target_include_directories(httplib INTERFACE ./httplib)
target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
if (WIN32)
target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32)
endif()
endif()
# Opus

100
externals/find-modules/FindFFmpeg.cmake vendored Normal file
View File

@@ -0,0 +1,100 @@
# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil)
# Once done this will define
#
# FFMPEG_FOUND - system has ffmpeg or libav
# FFMPEG_INCLUDE_DIR - the ffmpeg include directory
# FFMPEG_LIBRARIES - Link these to use ffmpeg
# FFMPEG_LIBAVCODEC
# FFMPEG_LIBAVFORMAT
# FFMPEG_LIBAVUTIL
#
# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org>
# Modified for other libraries by Lasse Kärkkäinen <tronic>
# Modified for Hedgewars by Stepik777
# Modified for FFmpeg-example Tuukka Pasanen 2018
# Modified for yuzu toastUnlimted 2020
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
#
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FFMPEG
FOUND_VAR FFMPEG_FOUND
REQUIRED_VARS
FFMPEG_LIBRARY
FFMPEG_INCLUDE_DIR
VERSION_VAR FFMPEG_VERSION
)
if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
# in cache already
set(FFMPEG_FOUND TRUE)
else()
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
pkg_check_modules(_FFMPEG_AVUTIL libavutil)
pkg_check_modules(_FFMPEG_SWSCALE libswscale)
endif()
find_path(FFMPEG_AVCODEC_INCLUDE_DIR
NAMES libavcodec/avcodec.h
PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS}
/usr/include
/usr/local/include
/opt/local/include
/sw/include
PATH_SUFFIXES ffmpeg libav)
find_library(FFMPEG_LIBAVCODEC
NAMES avcodec
PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib)
find_library(FFMPEG_LIBAVUTIL
NAMES avutil
PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib)
find_library(FFMPEG_LIBSWSCALE
NAMES swscale
PATHS ${_FFMPEG_SWSCALE_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib)
if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVUTIL AND FFMPEG_LIBSWSCALE)
set(FFMPEG_FOUND TRUE)
endif()
if(FFMPEG_FOUND)
set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR})
set(FFMPEG_LIBRARIES
${FFMPEG_LIBAVCODEC}
${FFMPEG_LIBAVUTIL}
${FFMPEG_LIBSWSCALE})
endif()
if(FFMPEG_FOUND)
if(NOT FFMPEG_FIND_QUIETLY)
message(STATUS
"Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}")
endif()
else()
if(FFMPEG_FIND_REQUIRED)
message(FATAL_ERROR
"Could not find libavcodec or libavutil or libswscale")
endif()
endif()
endif()

View File

@@ -1,4 +1,4 @@
From https://github.com/yhirose/cpp-httplib/tree/fce8e6fefdab4ad48bc5b25c98e5ebfda4f3cf53
From https://github.com/yhirose/cpp-httplib/tree/ff5677ad197947177c158fe857caff4f0e242045 with https://github.com/yhirose/cpp-httplib/pull/701
MIT License

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
add_library(lurlparser
LUrlParser.cpp
LUrlParser.h
)
create_target_directory_groups(lurlparser)
target_include_directories(lurlparser INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -1,265 +0,0 @@
/*
* Lightweight URL & URI parser (RFC 1738, RFC 3986)
* https://github.com/corporateshark/LUrlParser
*
* The MIT License (MIT)
*
* Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "LUrlParser.h"
#include <algorithm>
#include <cstring>
#include <stdlib.h>
// check if the scheme name is valid
static bool IsSchemeValid( const std::string& SchemeName )
{
for ( auto c : SchemeName )
{
if ( !isalpha( c ) && c != '+' && c != '-' && c != '.' ) return false;
}
return true;
}
bool LUrlParser::clParseURL::GetPort( int* OutPort ) const
{
if ( !IsValid() ) { return false; }
int Port = atoi( m_Port.c_str() );
if ( Port <= 0 || Port > 65535 ) { return false; }
if ( OutPort ) { *OutPort = Port; }
return true;
}
// based on RFC 1738 and RFC 3986
LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL )
{
LUrlParser::clParseURL Result;
const char* CurrentString = URL.c_str();
/*
* <scheme>:<scheme-specific-part>
* <scheme> := [a-z\+\-\.]+
* For resiliency, programs interpreting URLs should treat upper case letters as equivalent to lower case in scheme names
*/
// try to read scheme
{
const char* LocalString = strchr( CurrentString, ':' );
if ( !LocalString )
{
return clParseURL( LUrlParserError_NoUrlCharacter );
}
// save the scheme name
Result.m_Scheme = std::string( CurrentString, LocalString - CurrentString );
if ( !IsSchemeValid( Result.m_Scheme ) )
{
return clParseURL( LUrlParserError_InvalidSchemeName );
}
// scheme should be lowercase
std::transform( Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower );
// skip ':'
CurrentString = LocalString+1;
}
/*
* //<user>:<password>@<host>:<port>/<url-path>
* any ":", "@" and "/" must be normalized
*/
// skip "//"
if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash );
if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash );
// check if the user name and password are specified
bool bHasUserName = false;
const char* LocalString = CurrentString;
while ( *LocalString )
{
if ( *LocalString == '@' )
{
// user name and password are specified
bHasUserName = true;
break;
}
else if ( *LocalString == '/' )
{
// end of <host>:<port> specification
bHasUserName = false;
break;
}
LocalString++;
}
// user name and password
LocalString = CurrentString;
if ( bHasUserName )
{
// read user name
while ( *LocalString && *LocalString != ':' && *LocalString != '@' ) LocalString++;
Result.m_UserName = std::string( CurrentString, LocalString - CurrentString );
// proceed with the current pointer
CurrentString = LocalString;
if ( *CurrentString == ':' )
{
// skip ':'
CurrentString++;
// read password
LocalString = CurrentString;
while ( *LocalString && *LocalString != '@' ) LocalString++;
Result.m_Password = std::string( CurrentString, LocalString - CurrentString );
CurrentString = LocalString;
}
// skip '@'
if ( *CurrentString != '@' )
{
return clParseURL( LUrlParserError_NoAtSign );
}
CurrentString++;
}
bool bHasBracket = ( *CurrentString == '[' );
// go ahead, read the host name
LocalString = CurrentString;
while ( *LocalString )
{
if ( bHasBracket && *LocalString == ']' )
{
// end of IPv6 address
LocalString++;
break;
}
else if ( !bHasBracket && ( *LocalString == ':' || *LocalString == '/' ) )
{
// port number is specified
break;
}
LocalString++;
}
Result.m_Host = std::string( CurrentString, LocalString - CurrentString );
CurrentString = LocalString;
// is port number specified?
if ( *CurrentString == ':' )
{
CurrentString++;
// read port number
LocalString = CurrentString;
while ( *LocalString && *LocalString != '/' ) LocalString++;
Result.m_Port = std::string( CurrentString, LocalString - CurrentString );
CurrentString = LocalString;
}
// end of string
if ( !*CurrentString )
{
Result.m_ErrorCode = LUrlParserError_Ok;
return Result;
}
// skip '/'
if ( *CurrentString != '/' )
{
return clParseURL( LUrlParserError_NoSlash );
}
CurrentString++;
// parse the path
LocalString = CurrentString;
while ( *LocalString && *LocalString != '#' && *LocalString != '?' ) LocalString++;
Result.m_Path = std::string( CurrentString, LocalString - CurrentString );
CurrentString = LocalString;
// check for query
if ( *CurrentString == '?' )
{
// skip '?'
CurrentString++;
// read query
LocalString = CurrentString;
while ( *LocalString && *LocalString != '#' ) LocalString++;
Result.m_Query = std::string( CurrentString, LocalString - CurrentString );
CurrentString = LocalString;
}
// check for fragment
if ( *CurrentString == '#' )
{
// skip '#'
CurrentString++;
// read fragment
LocalString = CurrentString;
while ( *LocalString ) LocalString++;
Result.m_Fragment = std::string( CurrentString, LocalString - CurrentString );
CurrentString = LocalString;
}
Result.m_ErrorCode = LUrlParserError_Ok;
return Result;
}

View File

@@ -1,78 +0,0 @@
/*
* Lightweight URL & URI parser (RFC 1738, RFC 3986)
* https://github.com/corporateshark/LUrlParser
*
* The MIT License (MIT)
*
* Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <string>
namespace LUrlParser
{
enum LUrlParserError
{
LUrlParserError_Ok = 0,
LUrlParserError_Uninitialized = 1,
LUrlParserError_NoUrlCharacter = 2,
LUrlParserError_InvalidSchemeName = 3,
LUrlParserError_NoDoubleSlash = 4,
LUrlParserError_NoAtSign = 5,
LUrlParserError_UnexpectedEndOfLine = 6,
LUrlParserError_NoSlash = 7,
};
class clParseURL
{
public:
LUrlParserError m_ErrorCode;
std::string m_Scheme;
std::string m_Host;
std::string m_Port;
std::string m_Path;
std::string m_Query;
std::string m_Fragment;
std::string m_UserName;
std::string m_Password;
clParseURL()
: m_ErrorCode( LUrlParserError_Uninitialized )
{}
/// return 'true' if the parsing was successful
bool IsValid() const { return m_ErrorCode == LUrlParserError_Ok; }
/// helper to convert the port number to int, return 'true' if the port is valid (within the 0..65535 range)
bool GetPort( int* OutPort ) const;
/// parse the URL
static clParseURL ParseURL( const std::string& URL );
private:
explicit clParseURL( LUrlParserError ErrorCode )
: m_ErrorCode( ErrorCode )
{}
};
} // namespace LUrlParser

View File

@@ -1,19 +0,0 @@
From https://github.com/corporateshark/LUrlParser/commit/455d5e2d27e3946f11ad0328fee9ee2628e6a8e2
MIT License
===
Lightweight URL & URI parser (RFC 1738, RFC 3986)
(C) Sergey Kosarevsky, 2015
@corporateshark sk@linderdaum.com
http://www.linderdaum.com
http://blog.linderdaum.com
=============================
A tiny and lightweight URL & URI parser (RFC 1738, RFC 3986) written in C++.

View File

@@ -902,8 +902,10 @@ inline uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)
#include <windows.h>
#define snprintf _snprintf
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4244)
#endif
int64_t MicroProfileTicksPerSecondCpu()
{
static int64_t nTicksPerSecond = 0;
@@ -946,7 +948,11 @@ typedef HANDLE MicroProfileThread;
DWORD _stdcall ThreadTrampoline(void* pFunc)
{
MicroProfileThreadFunc F = (MicroProfileThreadFunc)pFunc;
return (uint32_t)F(0);
// The return value of F will always return a void*, however, this is for
// compatibility with pthreads. The underlying "address" of the pointer
// is always a 32-bit value, so this cast is safe to perform.
return static_cast<DWORD>(reinterpret_cast<uint64_t>(F(0)));
}
inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
@@ -1742,10 +1748,10 @@ void MicroProfileFlip()
}
}
}
for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
{
pLog->nGroupTicks[i] += nGroupTicks[i];
pFrameGroup[i] += nGroupTicks[i];
pLog->nGroupTicks[j] += nGroupTicks[j];
pFrameGroup[j] += nGroupTicks[j];
}
pLog->nStackPos = nStackPos;
}
@@ -3328,7 +3334,7 @@ bool MicroProfileIsLocalThread(uint32_t nThreadId)
#endif
#else
bool MicroProfileIsLocalThread(uint32_t nThreadId){return false;}
bool MicroProfileIsLocalThread([[maybe_unused]] uint32_t nThreadId) { return false; }
void MicroProfileStopContextSwitchTrace(){}
void MicroProfileStartContextSwitchTrace(){}
@@ -3576,7 +3582,7 @@ int MicroProfileGetGpuTickReference(int64_t* pOutCpu, int64_t* pOutGpu)
#undef S
#ifdef _WIN32
#ifdef _MSC_VER
#pragma warning(pop)
#endif

1
externals/unicorn vendored

Submodule externals/unicorn deleted from 73f4573535

View File

@@ -32,7 +32,6 @@ if (MSVC)
# /Zc:inline - Let codegen omit inline functions in object files
# /Zc:throwingNew - Let codegen assume `operator new` (without std::nothrow) will never return null
add_compile_options(
/W3
/MP
/Zi
/Zo
@@ -43,6 +42,13 @@ if (MSVC)
/Zc:externConstexpr
/Zc:inline
/Zc:throwingNew
# Warnings
/W3
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
/we4555 # Expression has no effect; expected expression with side-effect
/we4834 # Discarding return value of function with 'nodiscard' attribute
)
# /GS- - No stack buffer overflow checks
@@ -56,6 +62,7 @@ else()
-Werror=implicit-fallthrough
-Werror=missing-declarations
-Werror=reorder
-Werror=unused-result
-Wextra
-Wmissing-declarations
-Wno-attributes

View File

@@ -46,11 +46,17 @@ create_target_directory_groups(audio_core)
if (NOT MSVC)
target_compile_options(audio_core PRIVATE
-Werror=conversion
-Werror=ignored-qualifiers
-Werror=implicit-fallthrough
-Werror=reorder
-Werror=sign-compare
-Werror=unused-variable
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
-Wno-sign-conversion
)
endif()

View File

@@ -55,7 +55,8 @@ void Filter::Process(std::vector<s16>& signal) {
/// @param total_count The total number of biquads to be cascaded.
/// @param index 0-index of the biquad to calculate the Q value for.
static double CascadingBiquadQ(std::size_t total_count, std::size_t index) {
const double pole = M_PI * (2 * index + 1) / (4.0 * total_count);
const auto pole =
M_PI * static_cast<double>(2 * index + 1) / (4.0 * static_cast<double>(total_count));
return 1.0 / (2.0 * std::cos(pole));
}

View File

@@ -146,7 +146,7 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
return {};
if (ratio <= 0) {
LOG_CRITICAL(Audio, "Nonsensical interpolation ratio {}", ratio);
LOG_ERROR(Audio, "Nonsensical interpolation ratio {}", ratio);
return input;
}
@@ -164,7 +164,8 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
const std::size_t num_frames{input.size() / 2};
std::vector<s16> output;
output.reserve(static_cast<std::size_t>(input.size() / ratio + InterpolationState::taps));
output.reserve(static_cast<std::size_t>(static_cast<double>(input.size()) / ratio +
InterpolationState::taps));
for (std::size_t frame{}; frame < num_frames; ++frame) {
const std::size_t lut_index{(state.fraction >> 8) * InterpolationState::taps};

View File

@@ -793,7 +793,6 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
// Decode entire frame
if (remaining_samples >= static_cast<int>(SAMPLES_PER_FRAME)) {
for (std::size_t i = 0; i < SAMPLES_PER_FRAME / 2; i++) {
// Sample 1
const s32 s0 = SIGNED_NIBBLES[buffer[buffer_offset] >> 4];
const s32 s1 = SIGNED_NIBBLES[buffer[buffer_offset++] & 0xf];
@@ -802,7 +801,7 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
sample_buffer[cur_mix_offset++] = sample_1;
sample_buffer[cur_mix_offset++] = sample_2;
}
remaining_samples -= SAMPLES_PER_FRAME;
remaining_samples -= static_cast<int>(SAMPLES_PER_FRAME);
position_in_frame += SAMPLES_PER_FRAME;
continue;
}

View File

@@ -93,8 +93,10 @@ public:
constexpr s32 clev{707}; // center mixing level coefficient
constexpr s32 slev{707}; // surround mixing level coefficient
buf.push_back(left + (clev * center / 1000) + (slev * surround_left / 1000));
buf.push_back(right + (clev * center / 1000) + (slev * surround_right / 1000));
buf.push_back(static_cast<s16>(left + (clev * center / 1000) +
(slev * surround_left / 1000)));
buf.push_back(static_cast<s16>(right + (clev * center / 1000) +
(slev * surround_right / 1000)));
}
queue.Push(buf);
return;

View File

@@ -128,7 +128,10 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in,
in_params.wave_buffer_count = voice_in.wave_buffer_count;
in_params.wave_bufffer_head = voice_in.wave_buffer_head;
if (behavior_info.IsFlushVoiceWaveBuffersSupported()) {
in_params.wave_buffer_flush_request_count += voice_in.wave_buffer_flush_request_count;
const auto in_request_count = in_params.wave_buffer_flush_request_count;
const auto voice_request_count = voice_in.wave_buffer_flush_request_count;
in_params.wave_buffer_flush_request_count =
static_cast<u8>(in_request_count + voice_request_count);
}
in_params.mix_id = voice_in.mix_id;
if (behavior_info.IsSplitterSupported()) {

View File

@@ -150,6 +150,8 @@ add_library(common STATIC
scope_exit.h
spin_lock.cpp
spin_lock.h
stream.cpp
stream.h
string_util.cpp
string_util.h
swap.h
@@ -188,6 +190,22 @@ if(ARCHITECTURE_x86_64)
)
endif()
if (MSVC)
target_compile_definitions(common PRIVATE
# The standard library doesn't provide any replacement for codecvt yet
# so we can disable this deprecation warning for the time being.
_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
)
target_compile_options(common PRIVATE
/W4
/WX
)
else()
target_compile_options(common PRIVATE
-Werror
)
endif()
create_target_directory_groups(common)
find_package(Boost 1.71 COMPONENTS context headers REQUIRED)

View File

@@ -4,6 +4,8 @@
#include "common/assert.h"
#include "common/fiber.h"
#include "common/spin_lock.h"
#if defined(_WIN32) || defined(WIN32)
#include <windows.h>
#else
@@ -14,18 +16,45 @@ namespace Common {
constexpr std::size_t default_stack_size = 256 * 1024; // 256kb
#if defined(_WIN32) || defined(WIN32)
struct Fiber::FiberImpl {
SpinLock guard{};
std::function<void(void*)> entry_point;
std::function<void(void*)> rewind_point;
void* rewind_parameter{};
void* start_parameter{};
std::shared_ptr<Fiber> previous_fiber;
bool is_thread_fiber{};
bool released{};
#if defined(_WIN32) || defined(WIN32)
LPVOID handle = nullptr;
LPVOID rewind_handle = nullptr;
#else
alignas(64) std::array<u8, default_stack_size> stack;
alignas(64) std::array<u8, default_stack_size> rewind_stack;
u8* stack_limit;
u8* rewind_stack_limit;
boost::context::detail::fcontext_t context;
boost::context::detail::fcontext_t rewind_context;
#endif
};
void Fiber::SetStartParameter(void* new_parameter) {
impl->start_parameter = new_parameter;
}
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
impl->rewind_point = std::move(rewind_func);
impl->rewind_parameter = rewind_param;
}
#if defined(_WIN32) || defined(WIN32)
void Fiber::Start() {
ASSERT(previous_fiber != nullptr);
previous_fiber->guard.unlock();
previous_fiber.reset();
entry_point(start_parameter);
ASSERT(impl->previous_fiber != nullptr);
impl->previous_fiber->impl->guard.unlock();
impl->previous_fiber.reset();
impl->entry_point(impl->start_parameter);
UNREACHABLE();
}
@@ -34,99 +63,86 @@ void Fiber::OnRewind() {
DeleteFiber(impl->handle);
impl->handle = impl->rewind_handle;
impl->rewind_handle = nullptr;
rewind_point(rewind_parameter);
impl->rewind_point(impl->rewind_parameter);
UNREACHABLE();
}
void Fiber::FiberStartFunc(void* fiber_parameter) {
auto fiber = static_cast<Fiber*>(fiber_parameter);
auto* fiber = static_cast<Fiber*>(fiber_parameter);
fiber->Start();
}
void Fiber::RewindStartFunc(void* fiber_parameter) {
auto fiber = static_cast<Fiber*>(fiber_parameter);
auto* fiber = static_cast<Fiber*>(fiber_parameter);
fiber->OnRewind();
}
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
: entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} {
impl = std::make_unique<FiberImpl>();
: impl{std::make_unique<FiberImpl>()} {
impl->entry_point = std::move(entry_point_func);
impl->start_parameter = start_parameter;
impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this);
}
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
Fiber::~Fiber() {
if (released) {
if (impl->released) {
return;
}
// Make sure the Fiber is not being used
const bool locked = guard.try_lock();
const bool locked = impl->guard.try_lock();
ASSERT_MSG(locked, "Destroying a fiber that's still running");
if (locked) {
guard.unlock();
impl->guard.unlock();
}
DeleteFiber(impl->handle);
}
void Fiber::Exit() {
ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber");
if (!is_thread_fiber) {
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
if (!impl->is_thread_fiber) {
return;
}
ConvertFiberToThread();
guard.unlock();
released = true;
}
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) {
rewind_point = std::move(rewind_func);
rewind_parameter = start_parameter;
impl->guard.unlock();
impl->released = true;
}
void Fiber::Rewind() {
ASSERT(rewind_point);
ASSERT(impl->rewind_point);
ASSERT(impl->rewind_handle == nullptr);
impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this);
SwitchToFiber(impl->rewind_handle);
}
void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) {
void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
ASSERT_MSG(to != nullptr, "Next fiber is null!");
to->guard.lock();
to->previous_fiber = from;
to->impl->guard.lock();
to->impl->previous_fiber = from;
SwitchToFiber(to->impl->handle);
ASSERT(from->previous_fiber != nullptr);
from->previous_fiber->guard.unlock();
from->previous_fiber.reset();
ASSERT(from->impl->previous_fiber != nullptr);
from->impl->previous_fiber->impl->guard.unlock();
from->impl->previous_fiber.reset();
}
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
fiber->guard.lock();
fiber->impl->guard.lock();
fiber->impl->handle = ConvertThreadToFiber(nullptr);
fiber->is_thread_fiber = true;
fiber->impl->is_thread_fiber = true;
return fiber;
}
#else
struct Fiber::FiberImpl {
alignas(64) std::array<u8, default_stack_size> stack;
alignas(64) std::array<u8, default_stack_size> rewind_stack;
u8* stack_limit;
u8* rewind_stack_limit;
boost::context::detail::fcontext_t context;
boost::context::detail::fcontext_t rewind_context;
};
void Fiber::Start(boost::context::detail::transfer_t& transfer) {
ASSERT(previous_fiber != nullptr);
previous_fiber->impl->context = transfer.fctx;
previous_fiber->guard.unlock();
previous_fiber.reset();
entry_point(start_parameter);
ASSERT(impl->previous_fiber != nullptr);
impl->previous_fiber->impl->context = transfer.fctx;
impl->previous_fiber->impl->guard.unlock();
impl->previous_fiber.reset();
impl->entry_point(impl->start_parameter);
UNREACHABLE();
}
@@ -137,23 +153,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
u8* tmp = impl->stack_limit;
impl->stack_limit = impl->rewind_stack_limit;
impl->rewind_stack_limit = tmp;
rewind_point(rewind_parameter);
impl->rewind_point(impl->rewind_parameter);
UNREACHABLE();
}
void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) {
auto fiber = static_cast<Fiber*>(transfer.data);
auto* fiber = static_cast<Fiber*>(transfer.data);
fiber->Start(transfer);
}
void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
auto fiber = static_cast<Fiber*>(transfer.data);
auto* fiber = static_cast<Fiber*>(transfer.data);
fiber->OnRewind(transfer);
}
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
: entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} {
impl = std::make_unique<FiberImpl>();
: impl{std::make_unique<FiberImpl>()} {
impl->entry_point = std::move(entry_point_func);
impl->start_parameter = start_parameter;
impl->stack_limit = impl->stack.data();
impl->rewind_stack_limit = impl->rewind_stack.data();
u8* stack_base = impl->stack_limit + default_stack_size;
@@ -161,37 +178,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete
boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc);
}
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) {
rewind_point = std::move(rewind_func);
rewind_parameter = start_parameter;
}
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
Fiber::~Fiber() {
if (released) {
if (impl->released) {
return;
}
// Make sure the Fiber is not being used
const bool locked = guard.try_lock();
const bool locked = impl->guard.try_lock();
ASSERT_MSG(locked, "Destroying a fiber that's still running");
if (locked) {
guard.unlock();
impl->guard.unlock();
}
}
void Fiber::Exit() {
ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber");
if (!is_thread_fiber) {
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
if (!impl->is_thread_fiber) {
return;
}
guard.unlock();
released = true;
impl->guard.unlock();
impl->released = true;
}
void Fiber::Rewind() {
ASSERT(rewind_point);
ASSERT(impl->rewind_point);
ASSERT(impl->rewind_context == nullptr);
u8* stack_base = impl->rewind_stack_limit + default_stack_size;
impl->rewind_context =
@@ -199,22 +210,22 @@ void Fiber::Rewind() {
boost::context::detail::jump_fcontext(impl->rewind_context, this);
}
void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) {
void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
ASSERT_MSG(to != nullptr, "Next fiber is null!");
to->guard.lock();
to->previous_fiber = from;
to->impl->guard.lock();
to->impl->previous_fiber = from;
auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get());
ASSERT(from->previous_fiber != nullptr);
from->previous_fiber->impl->context = transfer.fctx;
from->previous_fiber->guard.unlock();
from->previous_fiber.reset();
ASSERT(from->impl->previous_fiber != nullptr);
from->impl->previous_fiber->impl->context = transfer.fctx;
from->impl->previous_fiber->impl->guard.unlock();
from->impl->previous_fiber.reset();
}
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
fiber->guard.lock();
fiber->is_thread_fiber = true;
fiber->impl->guard.lock();
fiber->impl->is_thread_fiber = true;
return fiber;
}

View File

@@ -7,9 +7,6 @@
#include <functional>
#include <memory>
#include "common/common_types.h"
#include "common/spin_lock.h"
#if !defined(_WIN32) && !defined(WIN32)
namespace boost::context::detail {
struct transfer_t;
@@ -46,10 +43,10 @@ public:
/// Yields control from Fiber 'from' to Fiber 'to'
/// Fiber 'from' must be the currently running fiber.
static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to);
static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to);
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter);
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);
void Rewind();
@@ -57,9 +54,7 @@ public:
void Exit();
/// Changes the start parameter of the fiber. Has no effect if the fiber already started
void SetStartParameter(void* new_parameter) {
start_parameter = new_parameter;
}
void SetStartParameter(void* new_parameter);
private:
Fiber();
@@ -77,16 +72,7 @@ private:
#endif
struct FiberImpl;
SpinLock guard{};
std::function<void(void*)> entry_point;
std::function<void(void*)> rewind_point;
void* rewind_parameter{};
void* start_parameter{};
std::shared_ptr<Fiber> previous_fiber;
std::unique_ptr<FiberImpl> impl;
bool is_thread_fiber{};
bool released{};
};
} // namespace Common

View File

@@ -472,13 +472,14 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
}
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) {
const auto callback = [recursion](u64* num_entries_out, const std::string& directory,
const std::string& virtual_name) -> bool {
std::string new_path = directory + DIR_SEP_CHR + virtual_name;
const auto callback = [recursion](u64*, const std::string& directory,
const std::string& virtual_name) {
const std::string new_path = directory + DIR_SEP_CHR + virtual_name;
if (IsDirectory(new_path)) {
if (recursion == 0)
if (recursion == 0) {
return false;
}
return DeleteDirRecursively(new_path, recursion - 1);
}
return Delete(new_path);
@@ -492,7 +493,8 @@ bool DeleteDirRecursively(const std::string& directory, unsigned int recursion)
return true;
}
void CopyDir(const std::string& source_path, const std::string& dest_path) {
void CopyDir([[maybe_unused]] const std::string& source_path,
[[maybe_unused]] const std::string& dest_path) {
#ifndef _WIN32
if (source_path == dest_path) {
return;
@@ -553,7 +555,7 @@ std::optional<std::string> GetCurrentDir() {
std::string strDir = dir;
#endif
free(dir);
return std::move(strDir);
return strDir;
}
bool SetCurrentDir(const std::string& directory) {
@@ -772,21 +774,23 @@ std::size_t ReadFileToString(bool text_file, const std::string& filename, std::s
void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
std::array<char, 4>& extension) {
const std::string forbidden_characters = ".\"/\\[]:;=, ";
static constexpr std::string_view forbidden_characters = ".\"/\\[]:;=, ";
// On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces.
short_name = {{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}};
extension = {{' ', ' ', ' ', '\0'}};
std::string::size_type point = filename.rfind('.');
if (point == filename.size() - 1)
auto point = filename.rfind('.');
if (point == filename.size() - 1) {
point = filename.rfind('.', point);
}
// Get short name.
int j = 0;
for (char letter : filename.substr(0, point)) {
if (forbidden_characters.find(letter, 0) != std::string::npos)
if (forbidden_characters.find(letter, 0) != std::string::npos) {
continue;
}
if (j == 8) {
// TODO(Link Mauve): also do that for filenames containing a space.
// TODO(Link Mauve): handle multiple files having the same short name.
@@ -794,14 +798,15 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
short_name[7] = '1';
break;
}
short_name[j++] = toupper(letter);
short_name[j++] = static_cast<char>(std::toupper(letter));
}
// Get extension.
if (point != std::string::npos) {
j = 0;
for (char letter : filename.substr(point + 1, 3))
extension[j++] = toupper(letter);
for (char letter : filename.substr(point + 1, 3)) {
extension[j++] = static_cast<char>(std::toupper(letter));
}
}
}

View File

@@ -232,7 +232,7 @@ public:
void Swap(IOFile& other) noexcept;
[[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0);
bool Open(const std::string& filename, const char openmode[], int flags = 0);
bool Close();
template <typename T>

View File

@@ -16,14 +16,14 @@ namespace Common {
[[nodiscard]] constexpr u8 ToHexNibble(char c) {
if (c >= 65 && c <= 70) {
return c - 55;
return static_cast<u8>(c - 55);
}
if (c >= 97 && c <= 102) {
return c - 87;
return static_cast<u8>(c - 87);
}
return c - 48;
return static_cast<u8>(c - 48);
}
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
@@ -33,11 +33,11 @@ template <std::size_t Size, bool le = false>
std::array<u8, Size> out{};
if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
}
} else {
for (std::size_t i = 0; i < 2 * Size; i += 2) {
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
}
}
return out;

View File

@@ -274,7 +274,6 @@ const char* GetLogClassName(Class log_class) {
case Class::Count:
break;
}
UNREACHABLE();
return "Invalid";
}
@@ -293,7 +292,6 @@ const char* GetLevelName(Level log_level) {
break;
}
#undef LVL
UNREACHABLE();
return "Invalid";
}

View File

@@ -20,14 +20,14 @@ struct Rectangle {
constexpr Rectangle() = default;
constexpr Rectangle(T left, T top, T right, T bottom)
: left(left), top(top), right(right), bottom(bottom) {}
constexpr Rectangle(T left_, T top_, T right_, T bottom_)
: left(left_), top(top_), right(right_), bottom(bottom_) {}
[[nodiscard]] T GetWidth() const {
if constexpr (std::is_floating_point_v<T>) {
return std::abs(right - left);
} else {
return std::abs(static_cast<std::make_signed_t<T>>(right - left));
return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(right - left)));
}
}
@@ -35,7 +35,7 @@ struct Rectangle {
if constexpr (std::is_floating_point_v<T>) {
return std::abs(bottom - top);
} else {
return std::abs(static_cast<std::make_signed_t<T>>(bottom - top));
return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(bottom - top)));
}
}

View File

@@ -16,16 +16,23 @@
// Call directly after the command or use the error num.
// This function might change the error code.
std::string GetLastErrorMsg() {
static const std::size_t buff_size = 255;
static constexpr std::size_t buff_size = 255;
char err_str[buff_size];
#ifdef _WIN32
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
return std::string(err_str, buff_size);
#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
// Thread safe (GNU-specific)
const char* str = strerror_r(errno, err_str, buff_size);
return std::string(str);
#else
// Thread safe (XSI-compliant)
strerror_r(errno, err_str, buff_size);
const int success = strerror_r(errno, err_str, buff_size);
if (success != 0) {
return {};
}
return std::string(err_str);
#endif
return std::string(err_str, buff_size);
}

View File

@@ -15,6 +15,14 @@ namespace Common {
*/
class SpinLock {
public:
SpinLock() = default;
SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete;
SpinLock(SpinLock&&) = delete;
SpinLock& operator=(SpinLock&&) = delete;
void lock();
void unlock();
[[nodiscard]] bool try_lock();

47
src/common/stream.cpp Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <stdexcept>
#include "common/common_types.h"
#include "common/stream.h"
namespace Common {
Stream::Stream() = default;
Stream::~Stream() = default;
void Stream::Seek(s32 offset, SeekOrigin origin) {
if (origin == SeekOrigin::SetOrigin) {
if (offset < 0) {
position = 0;
} else if (position >= buffer.size()) {
position = buffer.size();
} else {
position = offset;
}
} else if (origin == SeekOrigin::FromCurrentPos) {
Seek(static_cast<s32>(position) + offset, SeekOrigin::SetOrigin);
} else if (origin == SeekOrigin::FromEnd) {
Seek(static_cast<s32>(buffer.size()) - offset, SeekOrigin::SetOrigin);
}
}
u8 Stream::ReadByte() {
if (position < buffer.size()) {
return buffer[position++];
} else {
throw std::out_of_range("Attempting to read a byte not within the buffer range");
}
}
void Stream::WriteByte(u8 byte) {
if (position == buffer.size()) {
buffer.push_back(byte);
position++;
} else {
buffer.insert(buffer.begin() + position, byte);
}
}
} // namespace Common

56
src/common/stream.h Normal file
View File

@@ -0,0 +1,56 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include "common/common_types.h"
namespace Common {
enum class SeekOrigin {
SetOrigin,
FromCurrentPos,
FromEnd,
};
class Stream {
public:
/// Stream creates a bitstream and provides common functionality on the stream.
explicit Stream();
~Stream();
Stream(const Stream&) = delete;
Stream& operator=(const Stream&) = delete;
Stream(Stream&&) = default;
Stream& operator=(Stream&&) = default;
/// Reposition bitstream "cursor" to the specified offset from origin
void Seek(s32 offset, SeekOrigin origin);
/// Reads next byte in the stream buffer and increments position
u8 ReadByte();
/// Writes byte at current position
void WriteByte(u8 byte);
[[nodiscard]] std::size_t GetPosition() const {
return position;
}
[[nodiscard]] std::vector<u8>& GetBuffer() {
return buffer;
}
[[nodiscard]] const std::vector<u8>& GetBuffer() const {
return buffer;
}
private:
std::vector<u8> buffer;
std::size_t position{0};
};
} // namespace Common

View File

@@ -8,6 +8,7 @@
#include <cstdlib>
#include <locale>
#include <sstream>
#include "common/common_paths.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -21,14 +22,14 @@ namespace Common {
/// Make a string lowercase
std::string ToLower(std::string str) {
std::transform(str.begin(), str.end(), str.begin(),
[](unsigned char c) { return std::tolower(c); });
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return str;
}
/// Make a string uppercase
std::string ToUpper(std::string str) {
std::transform(str.begin(), str.end(), str.begin(),
[](unsigned char c) { return std::toupper(c); });
[](unsigned char c) { return static_cast<char>(std::toupper(c)); });
return str;
}

View File

@@ -142,20 +142,18 @@ std::string Timer::GetTimeFormatted() {
// ----------------
double Timer::GetDoubleTime() {
// Get continuous timestamp
u64 TmpSeconds = static_cast<u64>(Common::Timer::GetTimeSinceJan1970().count());
double ms = static_cast<u64>(GetTimeMs().count()) % 1000;
auto tmp_seconds = static_cast<u64>(GetTimeSinceJan1970().count());
const auto ms = static_cast<double>(static_cast<u64>(GetTimeMs().count()) % 1000);
// Remove a few years. We only really want enough seconds to make
// sure that we are detecting actual actions, perhaps 60 seconds is
// enough really, but I leave a year of seconds anyway, in case the
// user's clock is incorrect or something like that.
TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60);
tmp_seconds = tmp_seconds - (38 * 365 * 24 * 60 * 60);
// Make a smaller integer that fits in the double
u32 Seconds = static_cast<u32>(TmpSeconds);
double TmpTime = Seconds + ms;
return TmpTime;
const auto seconds = static_cast<u32>(tmp_seconds);
return seconds + ms;
}
} // Namespace Common

View File

@@ -87,7 +87,13 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
return {x * f, y * f};
using TV = decltype(T{} * V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
};
}
template <typename V>
@@ -98,7 +104,13 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
return {x / f, y / f};
using TV = decltype(T{} / V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
};
}
template <typename V>
@@ -168,7 +180,10 @@ public:
template <typename T, typename V>
[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
return Vec2<T>(f * vec.x, f * vec.y);
using C = std::common_type_t<T, V>;
return Vec2<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)));
}
using Vec2f = Vec2<float>;
@@ -237,7 +252,14 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
return {x * f, y * f, z * f};
using TV = decltype(T{} * V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
};
}
template <typename V>
@@ -247,7 +269,14 @@ public:
}
template <typename V>
[[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
return {x / f, y / f, z / f};
using TV = decltype(T{} / V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
};
}
template <typename V>
@@ -367,7 +396,11 @@ public:
template <typename T, typename V>
[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
using C = std::common_type_t<T, V>;
return Vec3<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)),
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.z)));
}
template <>
@@ -446,7 +479,15 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
return {x * f, y * f, z * f, w * f};
using TV = decltype(T{} * V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(w) * static_cast<C>(f)),
};
}
template <typename V>
@@ -457,7 +498,15 @@ public:
template <typename V>
[[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
return {x / f, y / f, z / f, w / f};
using TV = decltype(T{} / V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(w) / static_cast<C>(f)),
};
}
template <typename V>
@@ -582,7 +631,15 @@ public:
template <typename T, typename V>
[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
using TV = decltype(V{} * T{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.x)),
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.y)),
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.z)),
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.w)),
};
}
using Vec4f = Vec4<float>;

View File

@@ -53,7 +53,7 @@ public:
return Common::Divide128On32(temporary, 1000000000).first;
}
void Pause(bool is_paused) override {
void Pause([[maybe_unused]] bool is_paused) override {
// Do nothing in this clock type.
}

View File

@@ -34,7 +34,7 @@ private:
/// value used to reduce the native clocks accuracy as some apss rely on
/// undefined behavior where the level of accuracy in the clock shouldn't
/// be higher.
static constexpr u64 inaccuracy_mask = ~(0x400 - 1);
static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1);
SpinLock rtsc_serialize{};
u64 last_measure{};

View File

@@ -1,9 +1,3 @@
if (YUZU_ENABLE_BOXCAT)
set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h)
else()
set(BCAT_BOXCAT_ADDITIONAL_SOURCES)
endif()
add_library(core STATIC
arm/arm_interface.h
arm/arm_interface.cpp
@@ -19,8 +13,6 @@ add_library(core STATIC
arm/dynarmic/arm_exclusive_monitor.h
arm/exclusive_monitor.cpp
arm/exclusive_monitor.h
arm/unicorn/arm_unicorn.cpp
arm/unicorn/arm_unicorn.h
constants.cpp
constants.h
core.cpp
@@ -303,7 +295,6 @@ add_library(core STATIC
hle/service/audio/hwopus.h
hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h
${BCAT_BOXCAT_ADDITIONAL_SOURCES}
hle/service/bcat/bcat.cpp
hle/service/bcat/bcat.h
hle/service/bcat/module.cpp
@@ -446,6 +437,8 @@ add_library(core STATIC
hle/service/nvdrv/devices/nvhost_gpu.h
hle/service/nvdrv/devices/nvhost_nvdec.cpp
hle/service/nvdrv/devices/nvhost_nvdec.h
hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
hle/service/nvdrv/devices/nvhost_nvdec_common.h
hle/service/nvdrv/devices/nvhost_nvjpg.cpp
hle/service/nvdrv/devices/nvhost_nvjpg.h
hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -459,6 +452,8 @@ add_library(core STATIC
hle/service/nvdrv/nvdrv.h
hle/service/nvdrv/nvmemp.cpp
hle/service/nvdrv/nvmemp.h
hle/service/nvdrv/syncpoint_manager.cpp
hle/service/nvdrv/syncpoint_manager.h
hle/service/nvflinger/buffer_queue.cpp
hle/service/nvflinger/buffer_queue.h
hle/service/nvflinger/nvflinger.cpp
@@ -608,6 +603,13 @@ add_library(core STATIC
tools/freezer.h
)
if (YUZU_ENABLE_BOXCAT)
target_sources(core PRIVATE
hle/service/bcat/backend/boxcat.cpp
hle/service/bcat/backend/boxcat.h
)
endif()
if (MSVC)
target_compile_options(core PRIVATE
# 'expression' : signed/unsigned mismatch
@@ -623,12 +625,26 @@ if (MSVC)
# 'context' : truncation from 'type1' to 'type2'
/we4305
)
else()
target_compile_options(core PRIVATE
-Werror=conversion
-Werror=ignored-qualifiers
-Werror=implicit-fallthrough
-Werror=reorder
-Werror=sign-compare
-Werror=unused-variable
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
-Wno-sign-conversion
)
endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus unicorn zip)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip)
if (YUZU_ENABLE_BOXCAT)
target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)

View File

@@ -147,10 +147,18 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex
auto fp = ctx.cpu_registers[29];
auto lr = ctx.cpu_registers[30];
while (true) {
out.push_back({"", 0, lr, 0});
if (!fp) {
out.push_back({
.module = "",
.address = 0,
.original_address = lr,
.offset = 0,
.name = {},
});
if (fp == 0) {
break;
}
lr = memory.Read64(fp + 8) - 4;
fp = memory.Read64(fp);
}

View File

@@ -7,6 +7,7 @@
#include <dynarmic/A32/a32.h>
#include <dynarmic/A32/config.h>
#include <dynarmic/A32/context.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "core/arm/cpu_interrupt_handler.h"

View File

@@ -6,6 +6,7 @@
#include <memory>
#include <dynarmic/A64/a64.h>
#include <dynarmic/A64/config.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "core/arm/cpu_interrupt_handler.h"
@@ -13,7 +14,6 @@
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/process.h"
@@ -82,16 +82,9 @@ public:
}
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, MemoryReadCode(pc));
ARM_Interface::ThreadContext64 ctx;
parent.SaveContext(ctx);
parent.inner_unicorn.LoadContext(ctx);
parent.inner_unicorn.ExecuteInstructions(num_instructions);
parent.inner_unicorn.SaveContext(ctx);
parent.LoadContext(ctx);
num_interpreted_instructions += num_instructions;
LOG_ERROR(Core_ARM,
"Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, MemoryReadCode(pc));
}
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
@@ -127,18 +120,17 @@ public:
if (parent.uses_wall_clock) {
return;
}
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
// rough approximation of the amount of executed ticks in the system, it may be thrown off
// if not all cores are doing a similar amount of work. Instead of doing this, we should
// device a way so that timing is consistent across all cores without increasing the ticks 4
// times.
u64 amortized_ticks =
(ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
// Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1);
parent.system.CoreTiming().AddTicks(amortized_ticks);
num_interpreted_instructions = 0;
}
u64 GetTicksRemaining() override {
@@ -156,7 +148,6 @@ public:
}
ARM_Dynarmic_64& parent;
std::size_t num_interpreted_instructions = 0;
u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0;
static constexpr u64 minimum_run_cycles = 1000U;
@@ -248,12 +239,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index)
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handlers,
uses_wall_clock,
ARM_Unicorn::Arch::AArch64,
core_index},
core_index{core_index}, exclusive_monitor{
dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;

View File

@@ -12,7 +12,6 @@
#include "common/hash.h"
#include "core/arm/arm_interface.h"
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
namespace Core::Memory {
class Memory;
@@ -71,7 +70,6 @@ private:
std::unique_ptr<DynarmicCallbacks64> cb;
JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A64::Jit> jit;
ARM_Unicorn inner_unicorn;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;

View File

@@ -1,295 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <unicorn/arm64.h>
#include "common/assert.h"
#include "common/microprofile.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
namespace Core {
// Load Unicorn DLL once on Windows using RAII
#ifdef _MSC_VER
#include <unicorn_dynload.h>
struct LoadDll {
private:
LoadDll() {
ASSERT(uc_dyn_load(NULL, 0));
}
~LoadDll() {
ASSERT(uc_dyn_free());
}
static LoadDll g_load_dll;
};
LoadDll LoadDll::g_load_dll;
#endif
#define CHECKED(expr) \
do { \
if (auto _cerr = (expr)) { \
ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \
uc_strerror(_cerr)); \
} \
} while (0)
static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
GDBStub::BreakpointAddress bkpt =
GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute);
if (GDBStub::IsMemoryBreak() ||
(bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) {
auto core = static_cast<ARM_Unicorn*>(user_data);
core->RecordBreak(bkpt);
uc_emu_stop(uc);
}
}
static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
void* user_data) {
auto* const system = static_cast<System*>(user_data);
ARM_Interface::ThreadContext64 ctx{};
system->CurrentArmInterface().SaveContext(ctx);
ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
ctx.pc, ctx.cpu_registers[30]);
return false;
}
ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
Arch architecture, std::size_t core_index)
: ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} {
const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64;
CHECKED(uc_open(arch, UC_MODE_ARM, &uc));
auto fpv = 3 << 20;
CHECKED(uc_reg_write(uc, UC_ARM64_REG_CPACR_EL1, &fpv));
uc_hook hook{};
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, UINT64_MAX));
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0,
UINT64_MAX));
if (GDBStub::IsServerEnabled()) {
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, UINT64_MAX));
last_bkpt_hit = false;
}
}
ARM_Unicorn::~ARM_Unicorn() {
CHECKED(uc_close(uc));
}
void ARM_Unicorn::SetPC(u64 pc) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
}
u64 ARM_Unicorn::GetPC() const {
u64 val{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &val));
return val;
}
u64 ARM_Unicorn::GetReg(int regn) const {
u64 val{};
auto treg = UC_ARM64_REG_SP;
if (regn <= 28) {
treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
} else if (regn < 31) {
treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
}
CHECKED(uc_reg_read(uc, treg, &val));
return val;
}
void ARM_Unicorn::SetReg(int regn, u64 val) {
auto treg = UC_ARM64_REG_SP;
if (regn <= 28) {
treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
} else if (regn < 31) {
treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
}
CHECKED(uc_reg_write(uc, treg, &val));
}
u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
UNIMPLEMENTED();
static constexpr u128 res{};
return res;
}
void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
UNIMPLEMENTED();
}
u32 ARM_Unicorn::GetPSTATE() const {
u64 nzcv{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
return static_cast<u32>(nzcv);
}
void ARM_Unicorn::SetPSTATE(u32 pstate) {
u64 nzcv = pstate;
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
}
VAddr ARM_Unicorn::GetTlsAddress() const {
u64 base{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
return base;
}
void ARM_Unicorn::SetTlsAddress(VAddr base) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
}
u64 ARM_Unicorn::GetTPIDR_EL0() const {
u64 value{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
return value;
}
void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
}
void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) {
core_index = new_core_id;
}
void ARM_Unicorn::Run() {
if (GDBStub::IsServerEnabled()) {
ExecuteInstructions(std::max(4000000U, 0U));
} else {
while (true) {
if (interrupt_handlers[core_index].IsInterrupted()) {
return;
}
ExecuteInstructions(10);
}
}
}
void ARM_Unicorn::Step() {
ExecuteInstructions(1);
}
MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
// Temporarily map the code page for Unicorn
u64 map_addr{GetPC() & ~Memory::PAGE_MASK};
std::vector<u8> page_buffer(Memory::PAGE_SIZE);
system.Memory().ReadBlock(map_addr, page_buffer.data(), page_buffer.size());
CHECKED(uc_mem_map_ptr(uc, map_addr, page_buffer.size(),
UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, page_buffer.data()));
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
CHECKED(uc_mem_unmap(uc, map_addr, page_buffer.size()));
if (GDBStub::IsServerEnabled()) {
if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
}
Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread();
SaveContext(thread->GetContext64());
if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
last_bkpt_hit = false;
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
}
}
}
void ARM_Unicorn::SaveContext(ThreadContext64& ctx) {
int uregs[32];
void* tregs[32];
CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
for (auto i = 0; i < 29; ++i) {
uregs[i] = UC_ARM64_REG_X0 + i;
tregs[i] = &ctx.cpu_registers[i];
}
uregs[29] = UC_ARM64_REG_X29;
tregs[29] = (void*)&ctx.cpu_registers[29];
uregs[30] = UC_ARM64_REG_X30;
tregs[30] = (void*)&ctx.cpu_registers[30];
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31));
for (int i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
tregs[i] = &ctx.vector_registers[i];
}
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
}
void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) {
int uregs[32];
void* tregs[32];
CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
for (int i = 0; i < 29; ++i) {
uregs[i] = UC_ARM64_REG_X0 + i;
tregs[i] = (void*)&ctx.cpu_registers[i];
}
uregs[29] = UC_ARM64_REG_X29;
tregs[29] = (void*)&ctx.cpu_registers[29];
uregs[30] = UC_ARM64_REG_X30;
tregs[30] = (void*)&ctx.cpu_registers[30];
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31));
for (auto i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
tregs[i] = (void*)&ctx.vector_registers[i];
}
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));
}
void ARM_Unicorn::PrepareReschedule() {
CHECKED(uc_emu_stop(uc));
}
void ARM_Unicorn::ClearExclusiveState() {}
void ARM_Unicorn::ClearInstructionCache() {}
void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
last_bkpt = bkpt;
last_bkpt_hit = true;
}
void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
u32 esr{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
const auto ec = esr >> 26;
const auto iss = esr & 0xFFFFFF;
auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
switch (ec) {
case 0x15: // SVC
Kernel::Svc::Call(arm_instance->system, iss);
break;
}
}
} // namespace Core

View File

@@ -1,63 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <unicorn/unicorn.h>
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/gdbstub/gdbstub.h"
namespace Core {
class System;
class ARM_Unicorn final : public ARM_Interface {
public:
enum class Arch {
AArch32, // 32-bit ARM
AArch64, // 64-bit ARM
};
explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
Arch architecture, std::size_t core_index);
~ARM_Unicorn() override;
void SetPC(u64 pc) override;
u64 GetPC() const override;
u64 GetReg(int index) const override;
void SetReg(int index, u64 value) override;
u128 GetVectorReg(int index) const override;
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
void ChangeProcessorID(std::size_t new_core_id) override;
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ExecuteInstructions(std::size_t num_instructions);
void Run() override;
void Step() override;
void ClearInstructionCache() override;
void PageTableChanged(Common::PageTable&, std::size_t) override {}
void RecordBreak(GDBStub::BreakpointAddress bkpt);
void SaveContext(ThreadContext32& ctx) override {}
void SaveContext(ThreadContext64& ctx) override;
void LoadContext(const ThreadContext32& ctx) override {}
void LoadContext(const ThreadContext64& ctx) override;
private:
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
uc_engine* uc{};
GDBStub::BreakpointAddress last_bkpt{};
bool last_bkpt_hit = false;
std::size_t core_index;
};
} // namespace Core

View File

@@ -40,6 +40,7 @@
#include "core/hle/service/lm/manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/time/time_manager.h"
#include "core/loader/loader.h"
#include "core/memory.h"
#include "core/memory/cheat_engine.h"
@@ -121,7 +122,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system},
cpu_manager{system}, reporter{system}, applet_manager{system} {}
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
ResultStatus Run() {
status = ResultStatus::Success;
@@ -178,16 +179,21 @@ struct System::Impl {
arp_manager.ResetAll();
telemetry_session = std::make_unique<Core::TelemetrySession>();
gpu_core = VideoCore::CreateGPU(emu_window, system);
if (!gpu_core) {
return ResultStatus::ErrorVideoCore;
}
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
Service::Init(service_manager, system);
GDBStub::DeferStart();
interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system);
gpu_core = VideoCore::CreateGPU(emu_window, system);
if (!gpu_core) {
return ResultStatus::ErrorVideoCore;
}
// Initialize time manager, which must happen after kernel is created
time_manager.Initialize();
is_powered_on = true;
exit_lock = false;
@@ -387,6 +393,7 @@ struct System::Impl {
/// Service State
Service::Glue::ARPManager arp_manager;
Service::LM::Manager lm_manager{reporter};
Service::Time::TimeManager time_manager;
/// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -717,6 +724,14 @@ const Service::LM::Manager& System::GetLogManager() const {
return impl->lm_manager;
}
Service::Time::TimeManager& System::GetTimeManager() {
return impl->time_manager;
}
const Service::Time::TimeManager& System::GetTimeManager() const {
return impl->time_manager;
}
void System::SetExitLock(bool locked) {
impl->exit_lock = locked;
}

View File

@@ -69,6 +69,10 @@ namespace SM {
class ServiceManager;
} // namespace SM
namespace Time {
class TimeManager;
} // namespace Time
} // namespace Service
namespace Tegra {
@@ -361,6 +365,10 @@ public:
const Service::LM::Manager& GetLogManager() const;
Service::Time::TimeManager& GetTimeManager();
const Service::Time::TimeManager& GetTimeManager() const;
void SetExitLock(bool locked);
bool GetExitLock() const;

View File

@@ -365,6 +365,8 @@ void CpuManager::RunThread(std::size_t core) {
data.enter_barrier.reset();
data.exit_barrier.reset();
data.initialized = false;
MicroProfileOnThreadExit();
}
} // namespace Core

View File

@@ -411,7 +411,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
// Combine sources and seed
for (auto& source : sd_key_sources) {
for (std::size_t i = 0; i < source.size(); ++i) {
source[i] ^= sd_seed[i & 0xF];
source[i] = static_cast<u8>(source[i] ^ sd_seed[i & 0xF]);
}
}

View File

@@ -266,8 +266,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
cur_file->offset = file_partition_size;
file_partition_size += cur_file->size;
cur_file->entry_offset = entry_offset;
entry_offset += sizeof(RomFSFileEntry) +
Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4);
entry_offset +=
static_cast<u32>(sizeof(RomFSFileEntry) +
Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4));
prev_file = cur_file;
}
// Assign deferred parent/sibling ownership.
@@ -284,8 +285,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
for (const auto& it : directories) {
cur_dir = it.second;
cur_dir->entry_offset = entry_offset;
entry_offset += sizeof(RomFSDirectoryEntry) +
Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4);
entry_offset +=
static_cast<u32>(sizeof(RomFSDirectoryEntry) +
Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4));
}
// Assign deferred parent/sibling ownership.
for (auto it = directories.rbegin(); it->second != root; ++it) {

View File

@@ -299,7 +299,7 @@ void IPSwitchCompiler::Parse() {
patch_text->GetName(), offset, Common::HexToString(replace));
}
patch.records.insert_or_assign(offset, std::move(replace));
patch.records.insert_or_assign(static_cast<u32>(offset), std::move(replace));
}
patches.push_back(std::move(patch));

View File

@@ -108,7 +108,7 @@ std::vector<u8> CNMT::Serialize() const {
memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader));
}
auto offset = header.table_offset;
u64_le offset = header.table_offset;
for (const auto& rec : content_records) {
memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord));

View File

@@ -29,7 +29,7 @@
namespace FileSys {
namespace {
constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
constexpr u32 SINGLE_BYTE_MODULUS = 0x100;
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{

View File

@@ -19,38 +19,6 @@
#include "core/loader/loader.h"
namespace FileSys {
namespace {
void SetTicketKeys(const std::vector<VirtualFile>& files) {
auto& keys = Core::Crypto::KeyManager::Instance();
for (const auto& ticket_file : files) {
if (ticket_file == nullptr) {
continue;
}
if (ticket_file->GetExtension() != "tik") {
continue;
}
if (ticket_file->GetSize() <
Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
continue;
}
Core::Crypto::Key128 key{};
ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
// We get the name without the extension in order to create the rights ID.
std::string name_only(ticket_file->GetName());
name_only.erase(name_only.size() - 4);
const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
u128 rights_id;
std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
}
}
} // Anonymous namespace
NSP::NSP(VirtualFile file_)
: file(std::move(file_)), status{Loader::ResultStatus::Success},
@@ -232,6 +200,35 @@ VirtualDir NSP::GetParentDirectory() const {
return file->GetContainingDirectory();
}
void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) {
for (const auto& ticket_file : files) {
if (ticket_file == nullptr) {
continue;
}
if (ticket_file->GetExtension() != "tik") {
continue;
}
if (ticket_file->GetSize() <
Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
continue;
}
Core::Crypto::Key128 key{};
ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
// We get the name without the extension in order to create the rights ID.
std::string name_only(ticket_file->GetName());
name_only.erase(name_only.size() - 4);
const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
u128 rights_id;
std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
}
}
void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
exefs = pfs;

View File

@@ -63,6 +63,7 @@ public:
VirtualDir GetParentDirectory() const override;
private:
void SetTicketKeys(const std::vector<VirtualFile>& files);
void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files);
void ReadNCAs(const std::vector<VirtualFile>& files);

View File

@@ -19,7 +19,7 @@ DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& se
DefaultControllerApplet::~DefaultControllerApplet() = default;
void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
ControllerParameters parameters) const {
const ControllerParameters& parameters) const {
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
auto& npad =

View File

@@ -38,7 +38,7 @@ public:
virtual ~ControllerApplet();
virtual void ReconfigureControllers(std::function<void()> callback,
ControllerParameters parameters) const = 0;
const ControllerParameters& parameters) const = 0;
};
class DefaultControllerApplet final : public ControllerApplet {
@@ -47,7 +47,7 @@ public:
~DefaultControllerApplet() override;
void ReconfigureControllers(std::function<void()> callback,
ControllerParameters parameters) const override;
const ControllerParameters& parameters) const override;
private:
Service::SM::ServiceManager& service_manager;

View File

@@ -84,10 +84,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
return;
std::lock_guard guard{touch_state->mutex};
touch_state->touch_x = static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
touch_state->touch_y = static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
touch_state->touch_x =
static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
touch_state->touch_y =
static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
touch_state->touch_pressed = true;
}

View File

@@ -14,8 +14,8 @@ namespace Layout {
template <class T>
static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area,
float screen_aspect_ratio) {
float scale = std::min(static_cast<float>(window_area.GetWidth()),
window_area.GetHeight() / screen_aspect_ratio);
const float scale = std::min(static_cast<float>(window_area.GetWidth()),
static_cast<float>(window_area.GetHeight()) / screen_aspect_ratio);
return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)),
static_cast<T>(std::round(scale * screen_aspect_ratio))};
}
@@ -27,7 +27,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
// so just calculate them both even if the other isn't showing.
FramebufferLayout res{width, height, false, {}};
const float window_aspect_ratio = static_cast<float>(height) / width;
const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width);
const float emulation_aspect_ratio = EmulationAspectRatio(
static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio);

View File

@@ -291,11 +291,11 @@ static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr)
*/
static u8 HexCharToValue(u8 hex) {
if (hex >= '0' && hex <= '9') {
return hex - '0';
return static_cast<u8>(hex - '0');
} else if (hex >= 'a' && hex <= 'f') {
return hex - 'a' + 0xA;
return static_cast<u8>(hex - 'a' + 0xA);
} else if (hex >= 'A' && hex <= 'F') {
return hex - 'A' + 0xA;
return static_cast<u8>(hex - 'A' + 0xA);
}
LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex);
@@ -310,9 +310,9 @@ static u8 HexCharToValue(u8 hex) {
static u8 NibbleToHex(u8 n) {
n &= 0xF;
if (n < 0xA) {
return '0' + n;
return static_cast<u8>('0' + n);
} else {
return 'a' + n - 0xA;
return static_cast<u8>('a' + n - 0xA);
}
}
@@ -355,8 +355,8 @@ static u64 HexToLong(const u8* src, std::size_t len) {
*/
static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) {
while (len-- > 0) {
u8 tmp = *src++;
*dest++ = NibbleToHex(tmp >> 4);
const u8 tmp = *src++;
*dest++ = NibbleToHex(static_cast<u8>(tmp >> 4));
*dest++ = NibbleToHex(tmp);
}
}
@@ -370,7 +370,7 @@ static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) {
*/
static void GdbHexToMem(u8* dest, const u8* src, std::size_t len) {
while (len-- > 0) {
*dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]);
*dest++ = static_cast<u8>((HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]));
src += 2;
}
}
@@ -602,22 +602,22 @@ static void SendReply(const char* reply) {
memcpy(command_buffer + 1, reply, command_length);
u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
const u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
command_buffer[0] = GDB_STUB_START;
command_buffer[command_length + 1] = GDB_STUB_END;
command_buffer[command_length + 2] = NibbleToHex(checksum >> 4);
command_buffer[command_length + 2] = NibbleToHex(static_cast<u8>(checksum >> 4));
command_buffer[command_length + 3] = NibbleToHex(checksum);
u8* ptr = command_buffer;
u32 left = command_length + 4;
while (left > 0) {
int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
const auto sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
if (sent_size < 0) {
LOG_ERROR(Debug_GDBStub, "gdb: send failed");
return Shutdown();
}
left -= sent_size;
left -= static_cast<u32>(sent_size);
ptr += sent_size;
}
}
@@ -777,10 +777,10 @@ static void ReadCommand() {
command_buffer[command_length++] = c;
}
u8 checksum_received = HexCharToValue(ReadByte()) << 4;
checksum_received |= HexCharToValue(ReadByte());
auto checksum_received = static_cast<u32>(HexCharToValue(ReadByte()) << 4);
checksum_received |= static_cast<u32>(HexCharToValue(ReadByte()));
u8 checksum_calculated = CalculateChecksum(command_buffer, command_length);
const u32 checksum_calculated = CalculateChecksum(command_buffer, command_length);
if (checksum_received != checksum_calculated) {
LOG_ERROR(Debug_GDBStub,

View File

@@ -38,10 +38,11 @@ public:
explicit RequestHelperBase(Kernel::HLERequestContext& context)
: context(&context), cmdbuf(context.CommandBuffer()) {}
void Skip(unsigned size_in_words, bool set_to_null) {
if (set_to_null)
void Skip(u32 size_in_words, bool set_to_null) {
if (set_to_null) {
memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
index += size_in_words;
}
index += static_cast<ptrdiff_t>(size_in_words);
}
/**
@@ -49,15 +50,15 @@ public:
*/
void AlignWithPadding() {
if (index & 3) {
Skip(4 - (index & 3), true);
Skip(static_cast<u32>(4 - (index & 3)), true);
}
}
unsigned GetCurrentOffset() const {
return static_cast<unsigned>(index);
u32 GetCurrentOffset() const {
return static_cast<u32>(index);
}
void SetCurrentOffset(unsigned offset) {
void SetCurrentOffset(u32 offset) {
index = static_cast<ptrdiff_t>(offset);
}
};
@@ -89,7 +90,7 @@ public:
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
// padding.
u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
u32 num_handles_to_move{};
u32 num_domain_objects{};
@@ -105,7 +106,7 @@ public:
raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
}
header.data_size.Assign(raw_data_size);
header.data_size.Assign(static_cast<u32>(raw_data_size));
if (num_handles_to_copy || num_handles_to_move) {
header.enable_handle_descriptor.Assign(1);
}

View File

@@ -118,7 +118,7 @@ std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
void HandleTable::Clear() {
for (u16 i = 0; i < table_size; ++i) {
generations[i] = i + 1;
generations[i] = static_cast<u16>(i + 1);
objects[i] = nullptr;
}
next_free_slot = 0;

View File

@@ -7,7 +7,6 @@
#include <bitset>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
#include <unordered_map>
#include <utility>
@@ -87,8 +86,6 @@ struct KernelCore::Impl {
}
cores.clear();
registered_core_threads.reset();
process_list.clear();
current_process = nullptr;
@@ -107,7 +104,11 @@ struct KernelCore::Impl {
cores.clear();
exclusive_monitor.reset();
host_thread_ids.clear();
num_host_threads = 0;
std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
std::thread::id{});
std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
}
void InitializePhysicalCores() {
@@ -177,54 +178,58 @@ struct KernelCore::Impl {
void MakeCurrentProcess(Process* process) {
current_process = process;
if (process == nullptr) {
return;
}
u32 core_id = GetCurrentHostThreadID();
const u32 core_id = GetCurrentHostThreadID();
if (core_id < Core::Hardware::NUM_CPU_CORES) {
system.Memory().SetCurrentPageTable(*process, core_id);
}
}
void RegisterCoreThread(std::size_t core_id) {
std::unique_lock lock{register_thread_mutex};
if (!is_multicore) {
single_core_thread_id = std::this_thread::get_id();
}
const std::thread::id this_id = std::this_thread::get_id();
const auto it = host_thread_ids.find(this_id);
if (!is_multicore) {
single_core_thread_id = this_id;
}
const auto end =
register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
ASSERT(it == host_thread_ids.end());
ASSERT(!registered_core_threads[core_id]);
host_thread_ids[this_id] = static_cast<u32>(core_id);
registered_core_threads.set(core_id);
ASSERT(it == end);
InsertHostThread(static_cast<u32>(core_id));
}
void RegisterHostThread() {
std::unique_lock lock{register_thread_mutex};
const std::thread::id this_id = std::this_thread::get_id();
const auto it = host_thread_ids.find(this_id);
if (it != host_thread_ids.end()) {
return;
const auto end =
register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
if (it == end) {
InsertHostThread(registered_thread_ids++);
}
host_thread_ids[this_id] = registered_thread_ids++;
}
u32 GetCurrentHostThreadID() const {
void InsertHostThread(u32 value) {
const size_t index = num_host_threads++;
ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads");
register_host_thread_values[index] = value;
register_host_thread_keys[index] = std::this_thread::get_id();
}
[[nodiscard]] u32 GetCurrentHostThreadID() const {
const std::thread::id this_id = std::this_thread::get_id();
if (!is_multicore) {
if (single_core_thread_id == this_id) {
return static_cast<u32>(system.GetCpuManager().CurrentCore());
}
if (!is_multicore && single_core_thread_id == this_id) {
return static_cast<u32>(system.GetCpuManager().CurrentCore());
}
std::unique_lock lock{register_thread_mutex};
const auto it = host_thread_ids.find(this_id);
if (it == host_thread_ids.end()) {
const auto end =
register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
if (it == end) {
return Core::INVALID_HOST_THREAD_ID;
}
return it->second;
return register_host_thread_values[static_cast<size_t>(
std::distance(register_host_thread_keys.begin(), it))];
}
Core::EmuThreadHandle GetCurrentEmuThreadID() const {
@@ -322,10 +327,14 @@ struct KernelCore::Impl {
std::vector<Kernel::PhysicalCore> cores;
// 0-3 IDs represent core threads, >3 represent others
std::unordered_map<std::thread::id, u32> host_thread_ids;
u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
mutable std::mutex register_thread_mutex;
std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
// Number of host threads is a relatively high number to avoid overflowing
static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
std::atomic<size_t> num_host_threads{0};
std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
register_host_thread_keys{};
std::array<std::atomic<u32>, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{};
// Kernel memory management
std::unique_ptr<Memory::MemoryManager> memory_manager;

View File

@@ -2,30 +2,18 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/spin_lock.h"
#include "core/arm/arm_interface.h"
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#endif
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler,
Core::CPUInterruptHandler& interrupt_handler)
: interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} {
guard = std::make_unique<Common::SpinLock>();
}
: interrupt_handler{interrupt_handler},
core_index{id}, scheduler{scheduler}, guard{std::make_unique<Common::SpinLock>()} {}
PhysicalCore::~PhysicalCore() = default;

View File

@@ -4,6 +4,7 @@
#include <algorithm>
#include <bitset>
#include <ctime>
#include <memory>
#include <random>
#include "common/alignment.h"
@@ -123,7 +124,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
: kernel.CreateNewUserProcessID();
process->capabilities.InitializeForMetadatalessProcess();
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0));
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
std::uniform_int_distribution<u64> distribution;
std::generate(process->random_entropy.begin(), process->random_entropy.end(),
[&] { return distribution(rng); });

View File

@@ -72,7 +72,7 @@ u32 GlobalScheduler::SelectThreads() {
if (top_thread != nullptr) {
// TODO(Blinkhawk): Implement Thread Pinning
} else {
idle_cores |= (1ul << core);
idle_cores |= (1U << core);
}
top_threads[core] = top_thread;
}
@@ -126,7 +126,7 @@ u32 GlobalScheduler::SelectThreads() {
top_threads[core_id] = suggested;
}
idle_cores &= ~(1ul << core_id);
idle_cores &= ~(1U << core_id);
}
u32 cores_needing_context_switch{};
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
@@ -134,7 +134,7 @@ u32 GlobalScheduler::SelectThreads() {
ASSERT(top_threads[core] == nullptr ||
static_cast<u32>(top_threads[core]->GetProcessorID()) == core);
if (update_thread(top_threads[core], sched)) {
cores_needing_context_switch |= (1ul << core);
cores_needing_context_switch |= (1U << core);
}
}
return cores_needing_context_switch;
@@ -364,7 +364,7 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule,
} else {
must_context_switch = true;
}
cores_pending_reschedule &= ~(1ul << core);
cores_pending_reschedule &= ~(1U << core);
}
if (must_context_switch) {
auto& core_scheduler = kernel.CurrentScheduler();
@@ -767,7 +767,7 @@ void Scheduler::SwitchToCurrent() {
current_thread->context_guard.unlock();
break;
}
if (current_thread->GetProcessorID() != core_id) {
if (static_cast<u32>(current_thread->GetProcessorID()) != core_id) {
current_thread->context_guard.unlock();
break;
}

View File

@@ -13,7 +13,6 @@
#include "common/logging/log.h"
#include "common/thread_queue_list.h"
#include "core/arm/arm_interface.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/cpu_manager.h"
#include "core/hardware_properties.h"
@@ -217,8 +216,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
} else {
thread->tls_address = 0;
}
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
thread->arm_interface.reset();
if ((type_flags & THREADTYPE_HLE) == 0) {
#ifdef ARCHITECTURE_x86_64
@@ -231,19 +229,10 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(),
processor_id);
}
#else
if (owner_process && !owner_process->Is64BitProcess()) {
thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32,
processor_id);
} else {
thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64,
processor_id);
}
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#error Platform not supported yet.
#endif
ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
static_cast<u32>(entry_point), static_cast<u32>(arg));
ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);

View File

@@ -496,7 +496,7 @@ public:
{3, nullptr, "LoadIdTokenCache"},
{130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
{150, nullptr, "CreateAuthorizationRequest"},
{160, nullptr, "StoreOpenContext"},
{160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
{170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
};
// clang-format on
@@ -520,6 +520,12 @@ private:
rb.PushRaw<u64>(user_id.GetNintendoID());
}
void StoreOpenContext(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
Common::UUID user_id;
};

View File

@@ -1201,6 +1201,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{151, nullptr, "TryPopFromNotificationStorageChannel"},
{160, nullptr, "GetHealthWarningDisappearedSystemEvent"},
{170, nullptr, "SetHdcpAuthenticationActivated"},
{180, nullptr, "GetLaunchRequiredVersion"},
{181, nullptr, "UpgradeLaunchRequiredVersion"},
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, nullptr, "PrepareForJit"},

View File

@@ -84,7 +84,7 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
void ProgressServiceBackend::SignalUpdate() const {
if (need_hle_lock) {
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
std::lock_guard lock(HLE::g_hle_lock);
event.writable->Signal();
} else {
event.writable->Signal();

View File

@@ -196,7 +196,9 @@ private:
const std::string& content_type_name) {
if (client == nullptr) {
client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT);
client->set_timeout_sec(timeout_seconds);
client->set_connection_timeout(timeout_seconds);
client->set_read_timeout(timeout_seconds);
client->set_write_timeout(timeout_seconds);
}
httplib::Headers headers{
@@ -255,7 +257,7 @@ private:
return out;
}
std::unique_ptr<httplib::Client> client;
std::unique_ptr<httplib::SSLClient> client;
std::string path;
u64 title_id;
u64 build_id;
@@ -443,13 +445,25 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
std::map<std::string, EventStatus>& games) {
httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)};
client.set_timeout_sec(static_cast<int>(TIMEOUT_SECONDS));
client.set_connection_timeout(static_cast<int>(TIMEOUT_SECONDS));
client.set_read_timeout(static_cast<int>(TIMEOUT_SECONDS));
client.set_write_timeout(static_cast<int>(TIMEOUT_SECONDS));
httplib::Headers headers{
{std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
{std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
};
if (!client.is_valid()) {
LOG_ERROR(Service_BCAT, "Client is invalid, going offline!");
return StatusResult::Offline;
}
if (!client.is_socket_open()) {
LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!");
return StatusResult::Offline;
}
const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers);
if (response == nullptr)
return StatusResult::Offline;

View File

@@ -79,7 +79,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
}
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
return FileSys::ERROR_PATH_NOT_FOUND;
}
if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
@@ -93,8 +93,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
std::string path(Common::FS::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty())
if (dir == nullptr || Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) {
dir = backing;
}
auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path));
if (new_dir == nullptr) {
// TODO(DarkLordZach): Find a better error code for this

View File

@@ -42,8 +42,8 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
cur_entry.modifier = 0;
if (Settings::values.keyboard_enabled) {
for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
cur_entry.key[i / KEYS_PER_BYTE] |=
(keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE));
auto& entry = cur_entry.key[i / KEYS_PER_BYTE];
entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)));
}
for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {

View File

@@ -269,7 +269,6 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
const auto& button_state = buttons[controller_idx];
const auto& analog_state = sticks[controller_idx];
const auto& motion_state = motions[controller_idx];
const auto [stick_l_x_f, stick_l_y_f] =
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
const auto [stick_r_x_f, stick_r_y_f] =
@@ -391,18 +390,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
libnx_entry.connection_status.raw = 0;
libnx_entry.connection_status.IsConnected.Assign(1);
auto& full_sixaxis_entry =
npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
auto& handheld_sixaxis_entry =
npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index];
auto& dual_left_sixaxis_entry =
npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index];
auto& dual_right_sixaxis_entry =
npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index];
auto& left_sixaxis_entry =
npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index];
auto& right_sixaxis_entry =
npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index];
switch (controller_type) {
case NPadControllerType::None:
@@ -541,18 +528,6 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
}
}
auto& main_controller =
npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
auto& handheld_entry =
npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index];
auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index];
auto& right_entry =
npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index];
auto& pokeball_entry =
npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
auto& full_sixaxis_entry =
npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
auto& handheld_sixaxis_entry =

View File

@@ -260,7 +260,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{404, nullptr, "HasLeftRightBattery"},
{405, nullptr, "GetNpadInterfaceType"},
{406, nullptr, "GetNpadLeftRightInterfaceType"},
{407, nullptr, "GetNpadOfHighestBatteryLevelForJoyLeft"},
{407, nullptr, "GetNpadOfHighestBatteryLevel"},
{408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
{500, nullptr, "GetPalmaConnectionHandle"},
{501, nullptr, "InitializePalma"},
@@ -475,7 +475,7 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto enable{rp.Pop<bool>()};
[[maybe_unused]] const auto enable{rp.Pop<bool>()};
const auto handle{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};

View File

@@ -23,7 +23,7 @@ namespace Service::LDR {
constexpr ResultCode ERROR_INSUFFICIENT_ADDRESS_SPACE{ErrorModule::RO, 2};
constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
[[maybe_unused]] constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52};
constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53};
constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54};
@@ -33,7 +33,7 @@ constexpr ResultCode ERROR_ALREADY_LOADED{ErrorModule::Loader, 57};
constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81};
constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82};
constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84};
constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85};
[[maybe_unused]] constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85};
constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
constexpr std::size_t MAXIMUM_LOADED_RO{0x40};
@@ -166,7 +166,7 @@ public:
{0, &RelocatableObject::LoadNro, "LoadNro"},
{1, &RelocatableObject::UnloadNro, "UnloadNro"},
{2, &RelocatableObject::LoadNrr, "LoadNrr"},
{3, nullptr, "UnloadNrr"},
{3, &RelocatableObject::UnloadNrr, "UnloadNrr"},
{4, &RelocatableObject::Initialize, "Initialize"},
{10, nullptr, "LoadNrrEx"},
};
@@ -272,6 +272,20 @@ public:
rb.Push(RESULT_SUCCESS);
}
void UnloadNrr(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto pid = rp.Pop<u64>();
const auto nrr_address = rp.Pop<VAddr>();
LOG_DEBUG(Service_LDR, "called with pid={}, nrr_address={:016X}", pid, nrr_address);
nrr.erase(nrr_address);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
bool ValidateRegionForMap(Kernel::Memory::PageTable& page_table, VAddr start,
std::size_t size) const {
constexpr std::size_t padding_size{4 * Kernel::Memory::PageSize};

View File

@@ -131,7 +131,7 @@ template <typename T>
T GetRandomValue(T min, T max) {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(0, static_cast<u64>(max));
std::uniform_int_distribution<u64> distribution(static_cast<u64>(min), static_cast<u64>(max));
return static_cast<T>(distribution(gen));
}
@@ -428,7 +428,7 @@ bool MiiManager::IsFullDatabase() const {
}
u32 MiiManager::GetCount(SourceFlag source_flag) const {
u32 count{};
std::size_t count{};
if ((source_flag & SourceFlag::Database) != SourceFlag::None) {
// TODO(bunnei): We don't implement the Mii database, but when we do, update this
count += 0;
@@ -436,7 +436,7 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const {
if ((source_flag & SourceFlag::Default) != SourceFlag::None) {
count += DefaultMiiCount;
}
return count;
return static_cast<u32>(count);
}
ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info,

View File

@@ -47,6 +47,7 @@ public:
{23, nullptr, "Convert"},
{24, nullptr, "ConvertCoreDataToCharInfo"},
{25, nullptr, "ConvertCharInfoToCoreData"},
{26, nullptr, "Append"},
};
// clang-format on

View File

@@ -62,7 +62,7 @@ public:
{18, nullptr, "SetRequirementByRevision"},
{19, nullptr, "GetRequirement"},
{20, nullptr, "GetRevision"},
{21, nullptr, "GetAppletInfo"},
{21, &IRequest::GetAppletInfo, "GetAppletInfo"},
{22, nullptr, "GetAdditionalInfo"},
{23, nullptr, "SetKeptInSleep"},
{24, nullptr, "RegisterSocketDescriptor"},
@@ -125,6 +125,16 @@ private:
rb.Push(RESULT_SUCCESS);
}
void GetAppletInfo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 8};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
rb.Push<u32>(0);
rb.Push<u32>(0);
}
Kernel::EventPair event1, event2;
};

View File

@@ -50,19 +50,9 @@ constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{
std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"),
};
constexpr std::array<const char*, 7> SHARED_FONTS_TTF{
"FontStandard.ttf",
"FontChineseSimplified.ttf",
"FontExtendedChineseSimplified.ttf",
"FontChineseTraditional.ttf",
"FontKorean.ttf",
"FontNintendoExtended.ttf",
"FontNintendoExtended2.ttf",
};
// The below data is specific to shared font data dumped from Switch on f/w 2.2
// Virtual address and offsets/sizes likely will vary by dump
constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
[[maybe_unused]] constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be
constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be
constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};

View File

@@ -46,6 +46,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
return GetVARegions(input, output);
case IoctlCommand::IocUnmapBufferCommand:
return UnmapBuffer(input, output);
case IoctlCommand::IocFreeSpaceCommand:
return FreeSpace(input, output);
default:
break;
}
@@ -91,6 +93,20 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
return result;
}
u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlFreeSpace params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
params.pages, params.page_size);
system.GPU().MemoryManager().Unmap(params.offset,
static_cast<std::size_t>(params.pages) * params.page_size);
std::memcpy(output.data(), &params, output.size());
return NvErrCodes::Success;
}
u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);

View File

@@ -82,6 +82,7 @@ private:
IocBindChannelCommand = 0x40044101,
IocGetVaRegionsCommand = 0xC0404108,
IocUnmapBufferCommand = 0xC0084105,
IocFreeSpaceCommand = 0xC0104103,
};
struct IoctlInitalizeEx {
@@ -107,6 +108,13 @@ private:
};
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
struct IoctlFreeSpace {
u64_le offset;
u32_le pages;
u32_le page_size;
};
static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
struct IoctlRemapEntry {
u16_le flags;
u16_le kind;
@@ -162,6 +170,7 @@ private:
u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);

View File

@@ -15,8 +15,9 @@
namespace Service::Nvidia::Devices {
nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface)
: nvdevice(system), events_interface{events_interface} {}
nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
SyncpointManager& syncpoint_manager)
: nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
nvhost_ctrl::~nvhost_ctrl() = default;
u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -36,8 +37,8 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::v
return IocCtrlEventRegister(input, output);
case IoctlCommand::IocCtrlEventUnregisterCommand:
return IocCtrlEventUnregister(input, output);
case IoctlCommand::IocCtrlEventSignalCommand:
return IocCtrlEventSignal(input, output);
case IoctlCommand::IocCtrlClearEventWaitCommand:
return IocCtrlClearEventWait(input, output);
default:
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
@@ -70,19 +71,33 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
return NvResult::BadParameter;
}
if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id);
std::memcpy(output.data(), &params, sizeof(params));
return NvResult::Success;
}
if (const auto new_value = syncpoint_manager.RefreshSyncpoint(params.syncpt_id);
syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
params.value = new_value;
std::memcpy(output.data(), &params, sizeof(params));
return NvResult::Success;
}
auto event = events_interface.events[event_id];
auto& gpu = system.GPU();
// This is mostly to take into account unimplemented features. As synced
// gpu is always synced.
if (!gpu.IsAsync()) {
event.writable->Signal();
event.event.writable->Signal();
return NvResult::Success;
}
auto lock = gpu.LockSync();
const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id);
const u32 current_syncpoint_value = event.fence.value;
const s32 diff = current_syncpoint_value - params.threshold;
if (diff >= 0) {
event.writable->Signal();
event.event.writable->Signal();
params.value = current_syncpoint_value;
std::memcpy(output.data(), &params, sizeof(params));
return NvResult::Success;
@@ -109,7 +124,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
}
params.value |= event_id;
event.writable->Clear();
event.event.writable->Clear();
gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
if (!is_async && ctrl.fresh_call) {
ctrl.must_delay = true;
@@ -154,24 +169,22 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto
return NvResult::Success;
}
u32 nvhost_ctrl::IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output) {
u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
IocCtrlEventSignalParams params{};
std::memcpy(&params, input.data(), sizeof(params));
// TODO(Blinkhawk): This is normally called when an NvEvents timeout on WaitSynchronization
// It is believed from RE to cancel the GPU Event. However, better research is required
u32 event_id = params.user_event_id & 0x00FF;
LOG_WARNING(Service_NVDRV, "(STUBBED) called, user_event_id: {:X}", event_id);
u32 event_id = params.event_id & 0x00FF;
LOG_WARNING(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id);
if (event_id >= MaxNvEvents) {
return NvResult::BadParameter;
}
if (events_interface.status[event_id] == EventState::Waiting) {
auto& gpu = system.GPU();
if (gpu.CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id],
events_interface.assigned_value[event_id])) {
events_interface.LiberateEvent(event_id);
events_interface.events[event_id].writable->Signal();
}
events_interface.LiberateEvent(event_id);
}
syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id);
return NvResult::Success;
}

View File

@@ -14,7 +14,8 @@ namespace Service::Nvidia::Devices {
class nvhost_ctrl final : public nvdevice {
public:
explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface);
explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface,
SyncpointManager& syncpoint_manager);
~nvhost_ctrl() override;
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -31,7 +32,7 @@ private:
IocSyncptWaitexCommand = 0xC0100019,
IocSyncptReadMaxCommand = 0xC008001A,
IocGetConfigCommand = 0xC183001B,
IocCtrlEventSignalCommand = 0xC004001C,
IocCtrlClearEventWaitCommand = 0xC004001C,
IocCtrlEventWaitCommand = 0xC010001D,
IocCtrlEventWaitAsyncCommand = 0xC010001E,
IocCtrlEventRegisterCommand = 0xC004001F,
@@ -94,7 +95,7 @@ private:
static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
struct IocCtrlEventSignalParams {
u32_le user_event_id;
u32_le event_id;
};
static_assert(sizeof(IocCtrlEventSignalParams) == 4,
"IocCtrlEventSignalParams is incorrect size");
@@ -142,9 +143,10 @@ private:
u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
u32 IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output);
u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
EventInterface& events_interface;
SyncpointManager& syncpoint_manager;
};
} // namespace Service::Nvidia::Devices

View File

@@ -7,14 +7,20 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
#include "core/hle/service/nvdrv/syncpoint_manager.h"
#include "core/memory.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
namespace Service::Nvidia::Devices {
nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
SyncpointManager& syncpoint_manager)
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager{syncpoint_manager} {
channel_fence.id = syncpoint_manager.AllocateSyncpoint();
channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id);
}
nvhost_gpu::~nvhost_gpu() = default;
u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -126,10 +132,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
params.num_entries, params.flags, params.unk0, params.unk1, params.unk2,
params.unk3);
auto& gpu = system.GPU();
params.fence_out.id = assigned_syncpoints;
params.fence_out.value = gpu.GetSyncpointValue(assigned_syncpoints);
assigned_syncpoints++;
channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id);
params.fence_out = channel_fence;
std::memcpy(output.data(), &params, output.size());
return 0;
}
@@ -145,37 +151,98 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
return 0;
}
static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
return {
Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1,
Tegra::SubmissionMode::Increasing),
{fence.value},
Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1,
Tegra::SubmissionMode::Increasing),
Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Acquire, fence.id),
};
}
static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence, u32 add_increment) {
std::vector<Tegra::CommandHeader> result{
Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1,
Tegra::SubmissionMode::Increasing),
{}};
for (u32 count = 0; count < add_increment; ++count) {
result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1,
Tegra::SubmissionMode::Increasing));
result.emplace_back(
Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Increment, fence.id));
}
return result;
}
static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence fence,
u32 add_increment) {
std::vector<Tegra::CommandHeader> result{
Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1,
Tegra::SubmissionMode::Increasing),
{}};
const std::vector<Tegra::CommandHeader> increment{
BuildIncrementCommandList(fence, add_increment)};
result.insert(result.end(), increment.begin(), increment.end());
return result;
}
u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
Tegra::CommandList&& entries) {
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
params.num_entries, params.flags.raw);
auto& gpu = system.GPU();
params.fence_out.id = channel_fence.id;
if (params.flags.add_wait.Value() &&
!syncpoint_manager.IsSyncpointExpired(params.fence_out.id, params.fence_out.value)) {
gpu.PushGPUEntries(Tegra::CommandList{BuildWaitCommandList(params.fence_out)});
}
if (params.flags.add_increment.Value() || params.flags.increment.Value()) {
const u32 increment_value = params.flags.increment.Value() ? params.fence_out.value : 0;
params.fence_out.value = syncpoint_manager.IncreaseSyncpoint(
params.fence_out.id, params.AddIncrementValue() + increment_value);
} else {
params.fence_out.value = syncpoint_manager.GetSyncpointMax(params.fence_out.id);
}
entries.RefreshIntegrityChecks(gpu);
gpu.PushGPUEntries(std::move(entries));
if (params.flags.add_increment.Value()) {
if (params.flags.suppress_wfi) {
gpu.PushGPUEntries(Tegra::CommandList{
BuildIncrementCommandList(params.fence_out, params.AddIncrementValue())});
} else {
gpu.PushGPUEntries(Tegra::CommandList{
BuildIncrementWithWfiCommandList(params.fence_out, params.AddIncrementValue())});
}
}
std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
return 0;
}
u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
}
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
params.num_entries, params.flags.raw);
ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) +
params.num_entries * sizeof(Tegra::CommandListHeader),
"Incorrect input size");
Tegra::CommandList entries(params.num_entries);
std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(Tegra::CommandListHeader));
UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);
auto& gpu = system.GPU();
u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id);
if (params.flags.increment.Value()) {
params.fence_out.value += current_syncpoint_value;
} else {
params.fence_out.value = current_syncpoint_value;
}
gpu.PushGPUEntries(std::move(entries));
std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
return 0;
return SubmitGPFIFOImpl(params, output, std::move(entries));
}
u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
@@ -185,31 +252,17 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
}
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
params.num_entries, params.flags.raw);
Tegra::CommandList entries(params.num_entries);
if (version == IoctlVersion::Version2) {
std::memcpy(entries.data(), input2.data(),
std::memcpy(entries.command_lists.data(), input2.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
} else {
system.Memory().ReadBlock(params.address, entries.data(),
system.Memory().ReadBlock(params.address, entries.command_lists.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
}
UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);
auto& gpu = system.GPU();
u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id);
if (params.flags.increment.Value()) {
params.fence_out.value += current_syncpoint_value;
} else {
params.fence_out.value = current_syncpoint_value;
}
gpu.PushGPUEntries(std::move(entries));
std::memcpy(output.data(), &params, output.size());
return 0;
return SubmitGPFIFOImpl(params, output, std::move(entries));
}
u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {

View File

@@ -11,6 +11,11 @@
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "video_core/dma_pusher.h"
namespace Service::Nvidia {
class SyncpointManager;
}
namespace Service::Nvidia::Devices {
@@ -21,7 +26,8 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
class nvhost_gpu final : public nvdevice {
public:
explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
SyncpointManager& syncpoint_manager);
~nvhost_gpu() override;
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -162,10 +168,15 @@ private:
u32_le raw;
BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list
BitField<1, 1, u32_le> add_increment; // append an increment to the list
BitField<2, 1, u32_le> new_hw_format; // Mostly ignored
BitField<2, 1, u32_le> new_hw_format; // mostly ignored
BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt
BitField<8, 1, u32_le> increment; // increment the returned fence
} flags;
Fence fence_out; // returned new fence object for others to wait on
u32 AddIncrementValue() const {
return flags.add_increment.Value() << 1;
}
};
static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence),
"IoctlSubmitGpfifo is incorrect size");
@@ -190,6 +201,8 @@ private:
u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
Tegra::CommandList&& entries);
u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output);
u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
const std::vector<u8>& input2, IoctlVersion version);
@@ -198,7 +211,8 @@ private:
u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
std::shared_ptr<nvmap> nvmap_dev;
u32 assigned_syncpoints{};
SyncpointManager& syncpoint_manager;
Fence channel_fence;
};
} // namespace Service::Nvidia::Devices

View File

@@ -2,15 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
#include "video_core/memory_manager.h"
#include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices {
nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {}
nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
: nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
nvhost_nvdec::~nvhost_nvdec() = default;
u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -21,7 +23,7 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
switch (static_cast<IoctlCommand>(command.raw)) {
case IoctlCommand::IocSetNVMAPfdCommand:
return SetNVMAPfd(input, output);
return SetNVMAPfd(input);
case IoctlCommand::IocSubmit:
return Submit(input, output);
case IoctlCommand::IocGetSyncpoint:
@@ -29,79 +31,29 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
case IoctlCommand::IocGetWaitbase:
return GetWaitbase(input, output);
case IoctlCommand::IocMapBuffer:
return MapBuffer(input, output);
case IoctlCommand::IocMapBuffer2:
case IoctlCommand::IocMapBuffer3:
case IoctlCommand::IocMapBufferEx:
return MapBufferEx(input, output);
case IoctlCommand::IocUnmapBufferEx:
return UnmapBufferEx(input, output);
return MapBuffer(input, output);
case IoctlCommand::IocUnmapBufferEx: {
// This command is sent when the video stream has ended, flush all video contexts
// This is usually sent in the folowing order: vic, nvdec, vic.
// Inform the GPU to clear any remaining nvdec buffers when this is detected.
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
Tegra::ChCommandHeaderList cmdlist(1);
cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
system.GPU().PushCommandBuffer(cmdlist);
[[fallthrough]]; // fallthrough to unmap buffers
};
case IoctlCommand::IocUnmapBuffer:
case IoctlCommand::IocUnmapBuffer2:
case IoctlCommand::IocUnmapBuffer3:
return UnmapBuffer(input, output);
case IoctlCommand::IocSetSubmitTimeout:
return SetSubmitTimeout(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
}
u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
nvmap_fd = params.nvmap_fd;
return 0;
}
u32 nvhost_nvdec::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSubmit params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
return 0;
}
u32 nvhost_nvdec::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlGetSyncpoint params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
params.value = 0; // Seems to be hard coded at 0
std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
return 0;
}
u32 nvhost_nvdec::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlGetWaitbase params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
params.value = 0; // Seems to be hard coded at 0
std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
return 0;
}
u32 nvhost_nvdec::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
params.address_1);
params.address_1 = 0;
params.address_2 = 0;
std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
return 0;
}
u32 nvhost_nvdec::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlMapBufferEx params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBufferEx));
LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
params.address_1);
params.address_1 = 0;
params.address_2 = 0;
std::memcpy(output.data(), &params, sizeof(IoctlMapBufferEx));
return 0;
}
u32 nvhost_nvdec::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlUnmapBufferEx params{};
std::memcpy(&params, input.data(), sizeof(IoctlUnmapBufferEx));
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
std::memcpy(output.data(), &params, sizeof(IoctlUnmapBufferEx));
UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
return 0;
}

View File

@@ -4,16 +4,14 @@
#pragma once
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include <memory>
#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
namespace Service::Nvidia::Devices {
class nvhost_nvdec final : public nvdevice {
class nvhost_nvdec final : public nvhost_nvdec_common {
public:
explicit nvhost_nvdec(Core::System& system);
explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
~nvhost_nvdec() override;
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -27,62 +25,15 @@ private:
IocGetSyncpoint = 0xC0080002,
IocGetWaitbase = 0xC0080003,
IocMapBuffer = 0xC01C0009,
IocMapBuffer2 = 0xC16C0009,
IocMapBuffer3 = 0xC15C0009,
IocMapBufferEx = 0xC0A40009,
IocUnmapBufferEx = 0xC0A4000A,
IocUnmapBuffer = 0xC0A4000A,
IocUnmapBuffer2 = 0xC16C000A,
IocUnmapBufferEx = 0xC01C000A,
IocUnmapBuffer3 = 0xC15C000A,
IocSetSubmitTimeout = 0x40040007,
};
struct IoctlSetNvmapFD {
u32_le nvmap_fd;
};
static_assert(sizeof(IoctlSetNvmapFD) == 0x4, "IoctlSetNvmapFD is incorrect size");
struct IoctlSubmit {
INSERT_PADDING_BYTES(0x40); // TODO(DarkLordZach): RE this structure
};
static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit has incorrect size");
struct IoctlGetSyncpoint {
u32 unknown; // seems to be ignored? Nintendo added this
u32 value;
};
static_assert(sizeof(IoctlGetSyncpoint) == 0x08, "IoctlGetSyncpoint has incorrect size");
struct IoctlGetWaitbase {
u32 unknown; // seems to be ignored? Nintendo added this
u32 value;
};
static_assert(sizeof(IoctlGetWaitbase) == 0x08, "IoctlGetWaitbase has incorrect size");
struct IoctlMapBuffer {
u32 unknown;
u32 address_1;
u32 address_2;
INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
};
static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
struct IoctlMapBufferEx {
u32 unknown;
u32 address_1;
u32 address_2;
INSERT_PADDING_BYTES(0x98); // TODO(DarkLordZach): RE this structure
};
static_assert(sizeof(IoctlMapBufferEx) == 0xA4, "IoctlMapBufferEx has incorrect size");
struct IoctlUnmapBufferEx {
INSERT_PADDING_BYTES(0xA4); // TODO(DarkLordZach): RE this structure
};
static_assert(sizeof(IoctlUnmapBufferEx) == 0xA4, "IoctlUnmapBufferEx has incorrect size");
u32_le nvmap_fd{};
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices

View File

@@ -0,0 +1,234 @@
// Copyright 2020 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <cstring>
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
#include "core/memory.h"
#include "video_core/memory_manager.h"
#include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices {
namespace {
// Splice vectors will copy count amount of type T from the input vector into the dst vector.
template <typename T>
std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
std::size_t offset) {
std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
offset += count * sizeof(T);
return offset;
}
// Write vectors will write data to the output buffer
template <typename T>
std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
offset += src.size() * sizeof(T);
return offset;
}
} // Anonymous namespace
namespace NvErrCodes {
constexpr u32 Success{};
[[maybe_unused]] constexpr u32 OutOfMemory{static_cast<u32>(-12)};
constexpr u32 InvalidInput{static_cast<u32>(-22)};
} // namespace NvErrCodes
nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
nvhost_nvdec_common::~nvhost_nvdec_common() = default;
u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
nvmap_fd = params.nvmap_fd;
return 0;
}
u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSubmit params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
// Instantiate param buffers
std::size_t offset = sizeof(IoctlSubmit);
std::vector<CommandBuffer> command_buffers(params.cmd_buffer_count);
std::vector<Reloc> relocs(params.relocation_count);
std::vector<u32> reloc_shifts(params.relocation_count);
std::vector<SyncptIncr> syncpt_increments(params.syncpoint_count);
std::vector<SyncptIncr> wait_checks(params.syncpoint_count);
std::vector<Fence> fences(params.fence_count);
// Splice input into their respective buffers
offset = SpliceVectors(input, command_buffers, params.cmd_buffer_count, offset);
offset = SpliceVectors(input, relocs, params.relocation_count, offset);
offset = SpliceVectors(input, reloc_shifts, params.relocation_count, offset);
offset = SpliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
offset = SpliceVectors(input, wait_checks, params.syncpoint_count, offset);
offset = SpliceVectors(input, fences, params.fence_count, offset);
// TODO(ameerj): For async gpu, utilize fences for syncpoint 'max' increment
auto& gpu = system.GPU();
for (const auto& cmd_buffer : command_buffers) {
auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;);
const auto map = FindBufferMap(object->dma_map_addr);
if (!map) {
LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
object->addr, object->dma_map_addr);
return 0;
}
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
cmdlist.size() * sizeof(u32));
gpu.PushCommandBuffer(cmdlist);
}
std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
// Some games expect command_buffers to be written back
offset = sizeof(IoctlSubmit);
offset = WriteVectors(output, command_buffers, offset);
offset = WriteVectors(output, relocs, offset);
offset = WriteVectors(output, reloc_shifts, offset);
offset = WriteVectors(output, syncpt_increments, offset);
offset = WriteVectors(output, wait_checks, offset);
return NvErrCodes::Success;
}
u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlGetSyncpoint params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
// We found that implementing this causes deadlocks with async gpu, along with degraded
// performance. TODO: RE the nvdec async implementation
params.value = 0;
std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
return NvErrCodes::Success;
}
u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlGetWaitbase params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
params.value = 0; // Seems to be hard coded at 0
std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
return 0;
}
u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
auto& gpu = system.GPU();
for (auto& cmf_buff : cmd_buffer_handles) {
auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
if (!object) {
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
std::memcpy(output.data(), &params, output.size());
return NvErrCodes::InvalidInput;
}
if (object->dma_map_addr == 0) {
// NVDEC and VIC memory is in the 32-bit address space
// MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space
const GPUVAddr low_addr = gpu.MemoryManager().MapAllocate32(object->addr, object->size);
object->dma_map_addr = static_cast<u32>(low_addr);
// Ensure that the dma_map_addr is indeed in the lower 32-bit address space.
ASSERT(object->dma_map_addr == low_addr);
}
if (!object->dma_map_addr) {
LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
} else {
cmf_buff.map_address = object->dma_map_addr;
AddBufferMap(object->dma_map_addr, object->size, object->addr,
object->status == nvmap::Object::Status::Allocated);
}
}
std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
cmd_buffer_handles.size() * sizeof(MapBufferEntry));
return NvErrCodes::Success;
}
u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
auto& gpu = system.GPU();
for (auto& cmf_buff : cmd_buffer_handles) {
const auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
if (!object) {
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
std::memcpy(output.data(), &params, output.size());
return NvErrCodes::InvalidInput;
}
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
} else {
// This occurs quite frequently, however does not seem to impact functionality
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
object->dma_map_addr);
}
object->dma_map_addr = 0;
}
std::memset(output.data(), 0, output.size());
return NvErrCodes::Success;
}
u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
std::memcpy(&submit_timeout, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
return NvErrCodes::Success;
}
std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
GPUVAddr gpu_addr) const {
const auto it = std::find_if(
buffer_mappings.begin(), buffer_mappings.upper_bound(gpu_addr), [&](const auto& entry) {
return (gpu_addr >= entry.second.StartAddr() && gpu_addr < entry.second.EndAddr());
});
ASSERT(it != buffer_mappings.end());
return it->second;
}
void nvhost_nvdec_common::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
bool is_allocated) {
buffer_mappings.insert_or_assign(gpu_addr, BufferMap{gpu_addr, size, cpu_addr, is_allocated});
}
std::optional<std::size_t> nvhost_nvdec_common::RemoveBufferMap(GPUVAddr gpu_addr) {
const auto iter{buffer_mappings.find(gpu_addr)};
if (iter == buffer_mappings.end()) {
return std::nullopt;
}
std::size_t size = 0;
if (iter->second.IsAllocated()) {
size = iter->second.Size();
}
buffer_mappings.erase(iter);
return size;
}
} // namespace Service::Nvidia::Devices

View File

@@ -0,0 +1,168 @@
// Copyright 2020 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
namespace Service::Nvidia::Devices {
class nvmap;
class nvhost_nvdec_common : public nvdevice {
public:
explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
~nvhost_nvdec_common() override;
virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
IoctlVersion version) = 0;
protected:
class BufferMap final {
public:
constexpr BufferMap() = default;
constexpr BufferMap(GPUVAddr start_addr, std::size_t size)
: start_addr{start_addr}, end_addr{start_addr + size} {}
constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr,
bool is_allocated)
: start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr},
is_allocated{is_allocated} {}
constexpr VAddr StartAddr() const {
return start_addr;
}
constexpr VAddr EndAddr() const {
return end_addr;
}
constexpr std::size_t Size() const {
return end_addr - start_addr;
}
constexpr VAddr CpuAddr() const {
return cpu_addr;
}
constexpr bool IsAllocated() const {
return is_allocated;
}
private:
GPUVAddr start_addr{};
GPUVAddr end_addr{};
VAddr cpu_addr{};
bool is_allocated{};
};
struct IoctlSetNvmapFD {
u32_le nvmap_fd;
};
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
struct IoctlSubmitCommandBuffer {
u32_le id;
u32_le offset;
u32_le count;
};
static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
"IoctlSubmitCommandBuffer is incorrect size");
struct IoctlSubmit {
u32_le cmd_buffer_count;
u32_le relocation_count;
u32_le syncpoint_count;
u32_le fence_count;
};
static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");
struct CommandBuffer {
s32 memory_id;
u32 offset;
s32 word_count;
};
static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");
struct Reloc {
s32 cmdbuffer_memory;
s32 cmdbuffer_offset;
s32 target;
s32 target_offset;
};
static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
struct SyncptIncr {
u32 id;
u32 increments;
};
static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
struct Fence {
u32 id;
u32 value;
};
static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
struct IoctlGetSyncpoint {
// Input
u32_le param;
// Output
u32_le value;
};
static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");
struct IoctlGetWaitbase {
u32_le unknown; // seems to be ignored? Nintendo added this
u32_le value;
};
static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
struct IoctlMapBuffer {
u32_le num_entries;
u32_le data_address; // Ignored by the driver.
u32_le attach_host_ch_das;
};
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
struct IocGetIdParams {
// Input
u32_le param;
// Output
u32_le value;
};
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
// Used for mapping and unmapping command buffers
struct MapBufferEntry {
u32_le map_handle;
u32_le map_address;
};
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
/// Ioctl command implementations
u32 SetNVMAPfd(const std::vector<u8>& input);
u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
u32_le nvmap_fd{};
u32_le submit_timeout{};
std::shared_ptr<nvmap> nvmap_dev;
// This is expected to be ordered, therefore we must use a map, not unordered_map
std::map<GPUVAddr, BufferMap> buffer_mappings;
};
}; // namespace Service::Nvidia::Devices

View File

@@ -2,15 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
#include "video_core/memory_manager.h"
#include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices {
nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
: nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {}
nvhost_vic::~nvhost_vic() = default;
u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -21,7 +23,7 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
switch (static_cast<IoctlCommand>(command.raw)) {
case IoctlCommand::IocSetNVMAPfdCommand:
return SetNVMAPfd(input, output);
return SetNVMAPfd(input);
case IoctlCommand::IocSubmit:
return Submit(input, output);
case IoctlCommand::IocGetSyncpoint:
@@ -29,83 +31,19 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
case IoctlCommand::IocGetWaitbase:
return GetWaitbase(input, output);
case IoctlCommand::IocMapBuffer:
return MapBuffer(input, output);
case IoctlCommand::IocMapBuffer2:
case IoctlCommand::IocMapBuffer3:
case IoctlCommand::IocMapBuffer4:
case IoctlCommand::IocMapBufferEx:
return MapBuffer(input, output);
case IoctlCommand::IocUnmapBuffer:
case IoctlCommand::IocUnmapBuffer2:
case IoctlCommand::IocUnmapBuffer3:
case IoctlCommand::IocUnmapBufferEx:
return UnmapBufferEx(input, output);
return UnmapBuffer(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
}
u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
nvmap_fd = params.nvmap_fd;
return 0;
}
u32 nvhost_vic::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSubmit params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
// Workaround for Luigi's Mansion 3, as nvhost_vic is not implemented for asynch GPU
params.command_buffer = {};
std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
return 0;
}
u32 nvhost_vic::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlGetSyncpoint params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
params.value = 0; // Seems to be hard coded at 0
std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
return 0;
}
u32 nvhost_vic::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlGetWaitbase params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
params.value = 0; // Seems to be hard coded at 0
std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
return 0;
}
u32 nvhost_vic::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
params.address_1);
params.address_1 = 0;
params.address_2 = 0;
std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
return 0;
}
u32 nvhost_vic::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlMapBufferEx params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBufferEx));
LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
params.address_1);
params.address_1 = 0;
params.address_2 = 0;
std::memcpy(output.data(), &params, sizeof(IoctlMapBufferEx));
return 0;
}
u32 nvhost_vic::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlUnmapBufferEx params{};
std::memcpy(&params, input.data(), sizeof(IoctlUnmapBufferEx));
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
std::memcpy(output.data(), &params, sizeof(IoctlUnmapBufferEx));
UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
return 0;
}

View File

@@ -4,19 +4,15 @@
#pragma once
#include <array>
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
namespace Service::Nvidia::Devices {
class nvmap;
class nvhost_vic final : public nvdevice {
class nvhost_vic final : public nvhost_nvdec_common {
public:
explicit nvhost_vic(Core::System& system);
~nvhost_vic() override;
explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
~nvhost_vic();
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
IoctlVersion version) override;
@@ -28,74 +24,14 @@ private:
IocGetSyncpoint = 0xC0080002,
IocGetWaitbase = 0xC0080003,
IocMapBuffer = 0xC01C0009,
IocMapBuffer2 = 0xC0340009,
IocMapBuffer3 = 0xC0140009,
IocMapBuffer4 = 0xC00C0009,
IocMapBufferEx = 0xC03C0009,
IocUnmapBufferEx = 0xC03C000A,
IocUnmapBuffer = 0xC03C000A,
IocUnmapBuffer2 = 0xC034000A,
IocUnmapBuffer3 = 0xC00C000A,
IocUnmapBufferEx = 0xC01C000A,
};
struct IoctlSetNvmapFD {
u32_le nvmap_fd;
};
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
struct IoctlSubmitCommandBuffer {
u32 id;
u32 offset;
u32 count;
};
static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
"IoctlSubmitCommandBuffer is incorrect size");
struct IoctlSubmit {
u32 command_buffer_count;
u32 relocations_count;
u32 syncpt_count;
u32 wait_count;
std::array<IoctlSubmitCommandBuffer, 4> command_buffer;
};
static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit is incorrect size");
struct IoctlGetSyncpoint {
u32 unknown; // seems to be ignored? Nintendo added this
u32 value;
};
static_assert(sizeof(IoctlGetSyncpoint) == 0x8, "IoctlGetSyncpoint is incorrect size");
struct IoctlGetWaitbase {
u32 unknown; // seems to be ignored? Nintendo added this
u32 value;
};
static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
struct IoctlMapBuffer {
u32 unknown;
u32 address_1;
u32 address_2;
INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
};
static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
struct IoctlMapBufferEx {
u32 unknown;
u32 address_1;
u32 address_2;
INSERT_PADDING_BYTES(0x30); // TODO(DarkLordZach): RE this structure
};
static_assert(sizeof(IoctlMapBufferEx) == 0x3C, "IoctlMapBufferEx is incorrect size");
struct IoctlUnmapBufferEx {
INSERT_PADDING_BYTES(0x3C); // TODO(DarkLordZach): RE this structure
};
static_assert(sizeof(IoctlUnmapBufferEx) == 0x3C, "IoctlUnmapBufferEx is incorrect size");
u32_le nvmap_fd{};
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices

View File

@@ -37,6 +37,7 @@ public:
VAddr addr;
Status status;
u32 refcount;
u32 dma_map_addr;
};
std::shared_ptr<Object> GetObject(u32 handle) const {

View File

@@ -21,6 +21,7 @@
#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvdrv/nvmemp.h"
#include "core/hle/service/nvdrv/syncpoint_manager.h"
#include "core/hle/service/nvflinger/nvflinger.h"
namespace Service::Nvidia {
@@ -36,24 +37,26 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
nvflinger.SetNVDrvInstance(module_);
}
Module::Module(Core::System& system) {
Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
auto& kernel = system.Kernel();
for (u32 i = 0; i < MaxNvEvents; i++) {
std::string event_label = fmt::format("NVDRV::NvEvent_{}", i);
events_interface.events[i] = Kernel::WritableEvent::CreateEventPair(kernel, event_label);
events_interface.events[i] = {Kernel::WritableEvent::CreateEventPair(kernel, event_label)};
events_interface.status[i] = EventState::Free;
events_interface.registered[i] = false;
}
auto nvmap_dev = std::make_shared<Devices::nvmap>(system);
devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev);
devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev);
devices["/dev/nvhost-gpu"] =
std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev, syncpoint_manager);
devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system);
devices["/dev/nvmap"] = nvmap_dev;
devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev);
devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface);
devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system);
devices["/dev/nvhost-ctrl"] =
std::make_shared<Devices::nvhost_ctrl>(system, events_interface, syncpoint_manager);
devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, nvmap_dev);
devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system);
devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system);
devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, nvmap_dev);
}
Module::~Module() = default;
@@ -95,17 +98,17 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
if (events_interface.assigned_syncpt[i] == syncpoint_id &&
events_interface.assigned_value[i] == value) {
events_interface.LiberateEvent(i);
events_interface.events[i].writable->Signal();
events_interface.events[i].event.writable->Signal();
}
}
}
std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const {
return events_interface.events[event_id].readable;
return events_interface.events[event_id].event.readable;
}
std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const {
return events_interface.events[event_id].writable;
return events_interface.events[event_id].event.writable;
}
} // namespace Service::Nvidia

View File

@@ -10,6 +10,7 @@
#include "common/common_types.h"
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvdrv/syncpoint_manager.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -22,15 +23,23 @@ class NVFlinger;
namespace Service::Nvidia {
class SyncpointManager;
namespace Devices {
class nvdevice;
}
/// Represents an Nvidia event
struct NvEvent {
Kernel::EventPair event;
Fence fence{};
};
struct EventInterface {
// Mask representing currently busy events
u64 events_mask{};
// Each kernel event associated to an NV event
std::array<Kernel::EventPair, MaxNvEvents> events;
std::array<NvEvent, MaxNvEvents> events;
// The status of the current NVEvent
std::array<EventState, MaxNvEvents> status{};
// Tells if an NVEvent is registered or not
@@ -119,6 +128,9 @@ public:
std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const;
private:
/// Manages syncpoints on the host
SyncpointManager syncpoint_manager;
/// Id to use for the next open file descriptor.
u32 next_fd = 1;

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