Compare commits

...

209 Commits

Author SHA1 Message Date
Lioncash
8fc806e88a yuzu: Remove setting for using Unicorn
The JIT is mature enough that this setting can be removed, falling back
to Unicorn only on unsupported architectures. Any missing features from
Unicorn (of which there are extremely few), are mostly
developer-oriented, which most users don't care about.

Features should be coordinated with the JIT, not the interpreter,
anyhow.
2019-07-11 05:59:13 -04:00
Lioncash
70624e1c1d core/arm: Remove obsolete Unicorn memory mapping
This was initially necessary when AArch64 JIT emulation was in its
infancy and all memory-related instructions weren't implemented.

Given the JIT now has all of these facilities implemented, we can remove
these functions from the CPU interface.
2019-07-11 05:35:46 -04:00
Flame Sage
0b3901bdd0 Merge pull request #2714 from DarkLordZach/repo-sync-pipeline
Add Repository Sync Pipeline
2019-07-10 22:22:04 -04:00
Zach Hilman
502358ab05 Add Repository Sync Pipeline 2019-07-10 22:18:32 -04:00
bunnei
fd066ffbce Merge pull request #2697 from lioncash/doc
gl_rasterizer: Amend documentation comment for ConfigureFramebuffers()
2019-07-10 16:38:09 -04:00
bunnei
7fb7054bc8 Merge pull request #2686 from ReinUsesLisp/vk-scheduler
vk_scheduler: Drop execution context in favor of views
2019-07-10 16:35:48 -04:00
bunnei
93eaea109d Merge pull request #2700 from ogniK5377/GetFriendList
IFriendService::GetFriendList
2019-07-10 16:29:48 -04:00
bunnei
463af08bed Merge pull request #2611 from DarkLordZach/pm-info-cmd
pm: Implement various pm commands for finding process and title IDs
2019-07-10 16:28:29 -04:00
bunnei
d707a12b9a Merge pull request #2650 from DarkLordZach/mii-iface-ver
mii: Implement IDatabaseService SetInterfaceVersion
2019-07-10 16:26:23 -04:00
bunnei
206ec29f17 Merge pull request #2691 from lioncash/override
video_core: Add missing override specifiers
2019-07-10 16:25:43 -04:00
Flame Sage
55245b6183 Merge pull request #2706 from DarkLordZach/azure-1
Add Pipeline Definitions for Azure CI
2019-07-09 22:22:21 -04:00
Zach Hilman
f2e5c19520 Add Pipeline Definitions 2019-07-09 22:17:56 -04:00
Flame Sage
05d55b0fd7 Set up CI with Azure Pipelines
[skip ci]
2019-07-09 22:01:46 -04:00
David Marcec
0330f5d6f8 IFriendService::GetFriendList
We don't have any friends implemented in Yuzu yet so it doesn't make sense to return any friends. For now we'll be returning 0 friends however the information provided will allow a proper implementation of this cmd when needed.
2019-07-09 18:20:58 +10:00
Lioncash
c04785c928 gl_rasterizer: Amend documentation comment for ConfigureFramebuffers()
must_reconfigure isn't a parameter for this function any more, so it can
be replaced with current_state.

While we're at it, we can make the parameters of the declaration match
the same name as the ones in the definition.
2019-07-09 02:08:15 -04:00
Zach Hilman
618d8446ab Merge pull request #2661 from ogniK5377/audren-loop
audren: Only manage wave buffers with a size
2019-07-08 09:35:42 -04:00
Zach Hilman
6c3cceafdc Merge pull request #2657 from ogniK5377/npad-assignments
hid:StartLrAssignmentMode, hid:StopLrAssignmentMode, hid:SwapNpadAssignment
2019-07-08 09:35:19 -04:00
David Marcec
5234e08a0d addressed issues 2019-07-08 14:51:40 +10:00
David Marcec
e3d000a7e6 addressed issue 2019-07-08 14:49:16 +10:00
bunnei
7b28f954c9 Merge pull request #2651 from DarkLordZach/apm-boost-mode-1
apm: Initial implementation of performance config and boost mode
2019-07-07 21:40:30 -04:00
bunnei
8f5aae3074 Merge pull request #2642 from DarkLordZach/fsp-log-2
fsp-srv: Implement Access Logging Functionality
2019-07-07 21:39:40 -04:00
Hexagon12
8070cb3f6b Merge pull request #2694 from FearlessTobi/patch-1
Delete decode_integer_set.cpp
2019-07-07 22:43:45 +03:00
Tobias
be020f7621 Delete decode_integer_set.cpp 2019-07-07 21:40:33 +02:00
Lioncash
cbdd6cd1c0 vk_sampler_cache: Remove unused includes
These are no longer used within this header, so they can be removed.
2019-07-07 13:40:36 -04:00
Lioncash
4b27680639 video_core: Add missing override specifiers 2019-07-07 13:38:39 -04:00
ReinUsesLisp
86a874a2fc vk_scheduler: Drop execution context in favor of views
Instead of passing by copy an execution context through out the whole
Vulkan call hierarchy, use a command buffer view and fence view
approach.

This internally dereferences the command buffer or fence forcing the
user to be unable to use an outdated version of it on normal usage.
It is still possible to keep store an outdated if it is casted to
VKFence& or vk::CommandBuffer.

While changing this file, add an extra parameter for Flush and Finish to
allow releasing the fence from this calls.
2019-07-07 03:30:22 -03:00
Zach Hilman
a4ef86a021 mii: Implement IDatabaseService SetInterfaceVersion
Appears to set a member variable used to affect the API that games access, and the method used to store data.
2019-07-06 21:39:12 -04:00
Zach Hilman
9e689a81f8 Merge pull request #2674 from lioncash/reporter
core/reporter: Minor changes
2019-07-06 21:26:40 -04:00
Zach Hilman
fb9124b6cd Merge pull request #2677 from lioncash/assert
kernel/vm_manager: Handle stack/TLS IO region placement a little better
2019-07-06 21:25:27 -04:00
Zach Hilman
f732cd5a4b Merge pull request #2684 from SciresM/suspend_tick
am: Implement GetAccumulatedSuspendedTickValue
2019-07-06 21:19:20 -04:00
Michael Scire
36259c01c2 clang-format fixes 2019-07-06 13:52:05 -07:00
Michael Scire
7fb7d3c218 am: Implement GetAccumulatedSuspendedTickValue 2019-07-06 12:13:34 -07:00
Lioncash
65c748fbd3 memory: Remove unused includes
These aren't used within the central memory management code, so they can
be removed.
2019-07-06 02:24:34 -04:00
Lioncash
63a5f48e7e memory: Remove unused PageTable forward declaration
This isn't used by anything in the header file, so it can be removed.
2019-07-06 02:24:34 -04:00
Lioncash
2a9e388290 kernel/vm_manager: Rename 'new map' to 'stack'
Provides a more accurate name for the memory region and also
disambiguates between the map and new map regions of memory, making it
easier to understand.
2019-07-06 02:24:30 -04:00
Lioncash
313cc36fec kernel/vm_manager: Handle stack/TLS IO region placement better
Handles the placement of the stack a little nicer compared to the
previous code, which was off in a few ways. e.g.

The stack (new map) region, shouldn't be the width of the entire address
space if the size of the region calculation ends up being zero. It
should be placed at the same location as the TLS IO region and also have
the same size.

In the event the TLS IO region contains a size of zero, we should also
be doing the same thing. This fixes our memory layout a little bit and
also resolves some cases where assertions can trigger due to the memory
layout being incorrect.
2019-07-05 21:57:31 -04:00
Lioncash
48807e9a24 core/reporter: Allow moves into SaveToFile()
Taking the json instance as a constant reference, makes all moves into
the parameter non-functional, resulting in copies. Taking it by value
allows moves to function.
2019-07-05 17:45:34 -04:00
Lioncash
2321656dbe core/reporter: Add missing includes and forward declarations
Adds missing inclusions to prevent potential compilation issues.
2019-07-05 17:45:24 -04:00
Lioncash
e721c344ae core/reporter: Remove unnecessary namespace qualifiers
The Reporter class is part of the Core namespace, so the System class
doesn't need to be qualified.
2019-07-05 17:09:26 -04:00
Lioncash
6ec48af222 core/reporter: Remove pessimizing move in GetHLERequestContextData()
This can inhibit copy-elision, so we can remove this redundant move.
2019-07-05 17:08:13 -04:00
Lioncash
f12eb40834 core/reporter: Make bracing consistent
Makes all control statements braced, regardless of their size, making
code more uniform.
2019-07-05 17:05:27 -04:00
Lioncash
7ad11e3867 core/reporter: Return in error case in SaveToFile()
If the path couldn't be created, then we shouldn't be attempting to save
the file.
2019-07-05 17:02:32 -04:00
Zach Hilman
772c86a260 Merge pull request #2601 from FernandoS27/texture_cache
Implement a new Texture Cache
2019-07-05 13:39:13 -04:00
Fernando Sahmkow
3b9d89839d texture_cache: Address Feedback 2019-07-05 09:46:53 -04:00
Fernando Sahmkow
30b176f92b texture_cache: Correct Texture Buffer Uploading 2019-07-04 19:38:19 -04:00
Zach Hilman
3f3a93f13b Merge pull request #2669 from FearlessTobi/move-cpujit-setting
yuzu: Move CPU Jit setting to Debug tab
2019-07-04 15:33:59 -04:00
Zach Hilman
54a02d14fd Merge pull request #2555 from lioncash/tls
kernel/process: Decouple TLS handling from threads
2019-07-04 15:32:32 -04:00
fearlessTobi
447bdac298 yuzu: Remove CPU Jit setting from the UI
A normal user shouldn't change this, as it will slow down the emulation and can lead to bugs or crashes. The renaming is done in order to prevent users from leaving this on without a way to turn it off from the UI.
2019-07-04 14:48:08 +02:00
bunnei
cca663792f Merge pull request #2670 from DarkLordZach/fix-merge-discrep-1
gl_shader_cache: Make CachedShader constructor private
2019-07-04 03:03:44 -04:00
bunnei
3c7eed16dc Merge pull request #2658 from ogniK5377/QueryAudioDeviceOutputEvent
IAudioDevice::QueryAudioDeviceOutputEvent
2019-07-04 01:42:22 -04:00
bunnei
70b595a63b Merge pull request #2638 from DarkLordZach/quest-flag
set: Implement GetQuestFlag with config option
2019-07-04 01:40:41 -04:00
Zach Hilman
ad50cd7df9 gl_shader_cache: Make CachedShader constructor private
Fixes missing review comments introduced.
2019-07-03 20:39:46 -04:00
Lioncash
e23110bd9f kernel/process: Default initialize all member variables
Ensures a Process instance is always created with a deterministic
initial state.
2019-07-03 20:31:40 -04:00
Lioncash
abdce723eb kernel/process: Decouple TLS handling from threads
Extracts out all of the thread local storage management from thread
instances themselves and makes the owning process handle the management
of the memory. This brings the memory management slightly more in line
with how the kernel handles these allocations.

Furthermore, this also makes the TLS page management a little more
readable compared to the lingering implementation that was carried over
from Citra.
2019-07-03 20:31:40 -04:00
Lioncash
55481df50f kernel/vm_manager: Add overload of FindFreeRegion() that operates on a boundary
This will be necessary for making our TLS slot management slightly more
straightforward. This can also be utilized for other purposes in the
future.

We can implement the existing simpler overload in terms of this one
anyways, we just pass the beginning and end of the ASLR region as the
boundaries.
2019-07-03 20:29:49 -04:00
Zach Hilman
beb3d77a79 Merge pull request #2613 from ogniK5377/InitalizeApplicationInfo
Implemented InitializeApplicationInfo & InitializeApplicationInfoRestricted
2019-07-03 20:23:56 -04:00
Zach Hilman
e86af37ecb Merge pull request #2608 from ogniK5377/Time_GetSharedMemoryNativeHandle
Implement Time::GetSharedMemoryNativeHandle
2019-07-03 20:22:23 -04:00
Zach Hilman
da5a537029 Merge pull request #2563 from ReinUsesLisp/shader-initializers
gl_shader_cache: Use static constructors for CachedShader initialization
2019-07-03 20:20:05 -04:00
bunnei
58032e0085 Merge pull request #2604 from ogniK5377/INotificationService
Implemented INotificationService
2019-07-02 23:32:57 -04:00
bunnei
2521007c09 Merge pull request #2659 from FernandoS27/safe-caches
rasterizer_cache: Protect inherited caches from submission level
2019-07-02 22:27:04 -04:00
Zach Hilman
6be79bab37 Merge pull request #2660 from bakugo/deltafragments
file_sys: Ignore DeltaFragment NCAs during installation
2019-07-01 22:27:24 -05:00
Bakugo
b50557d1f0 file_sys: Rename other ContentRecordType members 2019-07-02 00:57:23 +01:00
David Marcec
b82b5e46e7 audren: Only manage wave buffers with a size
We shouldn't be incrementing if wave buffers are empty. They are considered invalid/unused wave buffers.

This fixes the issue of certain sounds looping when they shouldn't
2019-07-01 21:20:23 +10:00
Fernando Sahmkow
4705d1b523 rasterizer_cache: Protect inherited caches from submission level 2019-07-01 04:32:01 -04:00
David Marcec
965608e6d1 IAudioDevice::QueryAudioDeviceOutputEvent
The event should only be signaled when an output audio device gets changed. Example, Speaker to USB headset. We don't identify different devices internally yet so there's no need to signal the event yet.
2019-07-01 18:05:44 +10:00
Bakugo
c72ef5f405 file_sys/registered_cache: Improve missing metadata error
This can happen when installing NSPs too, not just XCIs.
2019-07-01 07:31:32 +01:00
Bakugo
9968c0883a file_sys/submission_package: Don't warn about missing DeltaFragment NCAs
DeltaFragments are not useful to us and are often not included in patch NSPs.
2019-07-01 06:46:05 +01:00
Bakugo
79163fca80 file_sys/registered_cache: Ignore DeltaFragment NCAs during installation
DeltaFragments are only used to download and apply partial patches on a real console, and are not useful to us at all. Most patch NSPs do not include them, and when they do, it's a waste of space to install them.
2019-07-01 06:37:22 +01:00
Bakugo
306a24aad7 file_sys: Rename ContentRecordType::Patch to DeltaFragment
Avoids potential confusion, since patches and DeltaFragments are not the same thing. Actual full patches are listed under the Program type.
2019-07-01 06:32:13 +01:00
David Marcec
472210bf72 hid:StartLrAssignmentMode, hid:StopLrAssignmentMode, hid:SwapNpadAssignment
StartLrAssignmentMode and StopLrAssignmentMode don't require any implementation as it's just used for showing the screen of changing the controller orientation if the user wishes to do so.  Ever since #1634 this has not been needed as users can specify the controller orientation from the config and swap at any time. We store a private member just in case this gets used for anything extra in the future
2019-07-01 15:12:57 +10:00
bunnei
d992909636 Merge pull request #2583 from FernandoS27/core-timing-safe
Core_Timing: Make core_timing threadsafe by default.
2019-06-30 12:54:00 -04:00
ReinUsesLisp
6e1db6b703 texture_cache: Pack sibling queries inside a method 2019-06-29 20:47:46 -03:00
ReinUsesLisp
8eae66907e texture_cache: Use std::vector reservation for sampled_textures 2019-06-29 20:10:31 -03:00
ReinUsesLisp
f6f1a8f26a texture_cache: Style changes 2019-06-29 19:52:37 -03:00
Zach Hilman
1ca2b504bf Merge pull request #2653 from FearlessTobi/revert-2474-patch-1
Revert "CMake: Get Git submodule dependencies via CMake"
2019-06-29 16:55:47 -05:00
ReinUsesLisp
dd9ace502b texture_cache: Use std::array for siblings_table 2019-06-29 18:54:13 -03:00
ReinUsesLisp
3f3c3ca5f9 texture_cache: Address feedback 2019-06-29 17:29:39 -03:00
Zach Hilman
7e5d7773cc am: Implement SetCpuBoostMode in terms of APM 2019-06-28 22:46:51 -04:00
Zach Hilman
e2ad3e1fb0 core: Keep instance of APM Controller 2019-06-28 22:46:31 -04:00
Zach Hilman
e52306ca60 apm: Implement SetCpuBoostMode 2019-06-28 22:46:00 -04:00
Zach Hilman
1c6e6305ea apm: Add getters for performance config and mode 2019-06-28 22:45:31 -04:00
Zach Hilman
9175b00e7d apm: Add apm:am service
8.0.0+ identical version of apm
2019-06-28 22:44:30 -04:00
Zach Hilman
65eb9cbb28 apm: Add Controller class to manage speed data and application 2019-06-28 22:43:51 -04:00
Zach Hilman
d40f38967e fsp-srv: Implement GetAccessLogVersionInfo
Returns some misc. data about logging to help the game determine if it should log.
2019-06-28 21:05:42 -04:00
Zach Hilman
554e2f2f98 reporter: Add report class for filesystem access logs 2019-06-28 21:02:50 -04:00
Zach Hilman
db2fdd0352 fsp-srv: Implement OutputAccessLogToSdCard
Allows games to log data to the SD.
2019-06-28 21:02:34 -04:00
Zach Hilman
f477c5dfdd set: Implement GetQuestFlag
Simply returns a true/false value indicating if the system is a kiosk system. This has been mapped to a config option for the purposes of yuzu.
2019-06-28 18:38:47 -04:00
Zach Hilman
efa7d8d04b settings: Add config option for kiosk (quest) mode 2019-06-28 18:37:33 -04:00
David Marcec
dfe4b3f723 Attemp clang format fix?
Seems to be an issue with clang format
2019-06-28 22:08:50 +10:00
David Marcec
7d417d501d Added errors.h to cmakelist 2019-06-28 15:31:29 +10:00
David Marcec
c2146c4eef Addressed issues 2019-06-28 15:29:38 +10:00
David Marcec
fd6549be73 Addressed issues 2019-06-28 15:19:51 +10:00
David Marcec
0b03e8a98f Implemented InitializeApplicationInfo & InitializeApplicationInfoRestricted
InitializeApplicationInfoRestricted will need further implementation as it's checking for other user requirements about the game. As we're emulating, we're assuming the user owns the game so we skip these checks currently, implementation will need to be added further on
2019-06-27 16:44:42 +10:00
Zach Hilman
bce4bfffb6 pm: Implement pm:shell and pm:dmnt GetApplicationPid
Returns the process ID of the current application or 0 if no app is running.
2019-06-26 19:07:34 -04:00
Zach Hilman
354c254cde pm: Implement pm:dmnt GetTitlePid
Takes a title ID and searches for a matching process, returning error if it doesn't exist, otherwise the process ID.
2019-06-26 19:06:51 -04:00
Zach Hilman
49af3bcdcb pm: Implement pm:info GetTitleId
Searches the process list for a process with the specified ID, returning the title ID if it exists.
2019-06-26 19:05:04 -04:00
David Marcec
f67039c067 Addressed issues 2019-06-26 16:52:34 +10:00
Fernando Sahmkow
223ca80753 texture_cache: Correct variable naming. 2019-06-25 19:35:08 -04:00
Fernando Sahmkow
5aeabd9a17 gl_texture_cache: Correct asserts 2019-06-25 19:26:59 -04:00
Fernando Sahmkow
88bc39374f texture_cache: Corrections, documentation and asserts 2019-06-25 18:36:19 -04:00
Fernando Sahmkow
c0abc7124d surface_params: Corrections, asserts and documentation. 2019-06-25 18:03:25 -04:00
Fernando Sahmkow
fb234560b0 copy_params: use constexpr for constructor 2019-06-25 17:42:50 -04:00
Fernando Sahmkow
18d24fbdd0 gl_texture_cache: Corrections and fixes 2019-06-25 17:40:08 -04:00
Fernando Sahmkow
36665ce0b2 gl_resource_manager: Correct MakeStreamCopy 2019-06-25 17:32:04 -04:00
Fernando Sahmkow
58c8a44e7a texture_cache: Query MemoryManager from the system 2019-06-25 17:26:00 -04:00
David Marcec
19dc36ce06 Implement Time::GetSharedMemoryNativeHandle
This PR attempts to implement the shared memory provided by GetSharedMemoryNativeHandle. There is still more work to be done however that requires a rehaul of the current time module to handle clock contexts. This PR is mainly to get the basic functionality of the SharedMemory working and allow the use of addition to it whilst things get improved on.

Things to note:
Memory Barriers are used in the SharedMemory and a better solution would need to be done to implement this. Currently in this PR I’m faking the memory barriers as everything is sync and single threaded. They work by incrementing the counter and just populate the two data slots. On data reading, it will read the last added data.

Specific values in the shared memory would need to be updated periodically. This isn't included in this PR since we don't actively do this yet. In a later PR when time is refactored this should be done.

Finally, as we don't handle clock contexts. When time is refactored, we will need to update the shared memory for specific contexts. This PR does this already however since the contexts are all identical and not separated. We're just updating the same values for each context which in this case is empty.

Tiime:SetStandardUserSystemClockAutomaticCorrectionEnabled, Time:IsStandardUserSystemClockAutomaticCorrectionEnabled are also partially implemented in this PR. The reason the implementation is partial is because once again, a lack of clock contexts. This will be improved on in a future PR.

This PR closes issue #2556
2019-06-26 00:45:53 +10:00
David Marcec
192f1f7ebe SizedNotificationInfo should be 0x10 bytes, user_uuid is incorrect, this should be the users account id 2019-06-25 15:19:37 +10:00
David Marcec
5d005b87a3 fixed spelling errors and fixed issue with Pop not returning the SizedNotificationInfo 2019-06-25 11:23:23 +10:00
ReinUsesLisp
7565389700 texture_cache: Include "core/core.h" 2019-06-24 02:15:57 -03:00
ReinUsesLisp
e723441e37 gl_texture_cache: Explicitly add indirect include 2019-06-24 02:13:55 -03:00
ReinUsesLisp
34841a41c3 texture_cache/surface_view: Address feedback 2019-06-24 02:09:56 -03:00
ReinUsesLisp
0837290992 texture_cache/surface_base: Address feedback 2019-06-24 02:08:52 -03:00
ReinUsesLisp
75de730e28 video_core/surface: Address feedback 2019-06-24 02:07:11 -03:00
ReinUsesLisp
10a83653ee decode/texture: Address feedback 2019-06-24 02:05:05 -03:00
ReinUsesLisp
4504302abc renderer_opengl/utils: Remove unused includes and unused forward declaration 2019-06-24 02:03:37 -03:00
ReinUsesLisp
4b2ff1e00e gl_texture_cache: Address some feedback 2019-06-24 02:01:44 -03:00
ReinUsesLisp
0b6df52109 gl_shader_disk_cache: Address feedback 2019-06-24 01:59:32 -03:00
ReinUsesLisp
b8b05a484a gl_shader_decompiler: Address feedback 2019-06-24 01:56:38 -03:00
ReinUsesLisp
4d63f97945 shader_bytecode: Include missing <array> 2019-06-24 01:51:02 -03:00
ReinUsesLisp
de982deb25 common/alignment: Address feedback 2019-06-24 01:47:09 -03:00
David Marcec
e49ae3bf92 Implemented INotificationService 2019-06-24 12:26:45 +10:00
Fernando Sahmkow
d1812316e1 texture_cache: Style and Corrections 2019-06-20 21:24:47 -04:00
Fernando Sahmkow
51ba60b27e shader_cache: Correct versioning and size calculation. 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
97c8c9f49a texture_cache: Eliminate linear textures fallthrough 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
6acdae0e4c texture_cache: Correct format R16U as sibling 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
d7587842eb texture_cache: Implement texception detection and texture barriers. 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
198a0395bb texture_cache: Corrections to buffers and shadow formats use. 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
fed773a86c texture_cache: Implement Irregular Views in surfaces 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
082740d34d surface: Correct format S8Z24 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
03d489dcf5 texture_cache: Initialize all siblings to invalid pixel format. 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
9422cf7c10 gl_texture_cache: Use Stream Buffers instead of Persistant for Buffer Copies. 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
fac3706253 gl_texture_cache: Correct Image Blit 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
7232a1ed16 decoders: correct block calculation 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
3dd7643214 texture_cache: Use siblings textures on Rebuild and fix possible error on blitting 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
4db28f72f6 texture_cache: Remove old rasterizer cache 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
2d83553ea7 texture_cache: Implement siblings texture formats. 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
cb728797b0 fermi2d: Correct Origin Mode 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
a56f687793 texture_cache: correct texture buffer on surface params 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
b01f9c8a70 texture_cache: eliminate accelerated depth->color/color->depth copies due to driver instability. 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
561ce29c98 texture_cache: correct mutex locks 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
b7de31ac97 shader_ir: Fix image copy rebase issues 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
6f69f06873 texture_cache: Don't Image Copy if component types differ 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
9f755218a1 texture_cache: move some large methods to cpp files 2019-06-20 21:38:34 -03:00
Fernando Sahmkow
3809041c24 texture_cache: Optimize GetSurface and use references on functions that don't change a surface. 2019-06-20 21:38:33 -03:00
Fernando Sahmkow
60bf761afb texture_cache: Implement Buffer Copy and detect Turing GPUs Image Copies 2019-06-20 21:38:33 -03:00
Fernando Sahmkow
228f516bb4 texture_cache uncompress-compress is untopological.
This makes conflicts between non compress and compress textures to be 
auto recycled. It also limits the amount of mipmaps a texture can have 
if it goes above it's limit.
2019-06-20 21:38:33 -03:00
Fernando Sahmkow
9251354152 texture_cache: Correct copying between compressed and uncompressed formats 2019-06-20 21:38:33 -03:00
Fernando Sahmkow
0966665fc2 texture_cache: Only load on recycle with accurate GPU.
Testing so far has proven this to be quite safe as texture memory read 
added a 2-5ms load to the current cache.
2019-06-20 21:38:33 -03:00
Fernando Sahmkow
ea1525dab1 Fix rebase errors 2019-06-20 21:38:33 -03:00
Fernando Sahmkow
bdf9faab33 texture_cache: Handle uncontinuous surfaces. 2019-06-20 21:38:33 -03:00
Fernando Sahmkow
e60ed2bb3e texture_cache: return null surface on invalid address 2019-06-20 21:38:33 -03:00
Fernando Sahmkow
fcac55d5bf texture_cache: Add checks for texture buffers. 2019-06-20 21:38:33 -03:00
Fernando Sahmkow
175aa343ff texture_cache: Fermi2D reform and implement View Mirage
This also does some fixes on compressed textures reinterpret and on the
Fermi2D engine in general.
2019-06-20 21:38:33 -03:00
ReinUsesLisp
1bf4154e7d gl_shader_decompiler: Implement image binding settings 2019-06-20 21:38:33 -03:00
ReinUsesLisp
9097301d92 shader: Implement bindless images 2019-06-20 21:38:33 -03:00
ReinUsesLisp
06c4ce8645 shader: Decode SUST and implement backing image functionality 2019-06-20 21:38:33 -03:00
ReinUsesLisp
007ffbef1c gl_rasterizer: Track texture buffer usage 2019-06-20 21:38:33 -03:00
ReinUsesLisp
58c0d37422 video_core: Make ARB_buffer_storage a required extension 2019-06-20 21:36:12 -03:00
ReinUsesLisp
07f7ce1da2 gl_rasterizer_cache: Use texture buffers to emulate texture buffers 2019-06-20 21:36:12 -03:00
ReinUsesLisp
b8c75a845b maxwell_3d: Partially implement texture buffers as 1D textures 2019-06-20 21:36:12 -03:00
ReinUsesLisp
6c81c8f5b7 gl_shader_decompiler: Allow 1D textures to be texture buffers 2019-06-20 21:36:12 -03:00
ReinUsesLisp
4e81fc8296 shader: Implement texture buffers 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
d267948a73 texture_cache: loose TryReconstructSurface when accurate GPU is not on.
Also corrects some asserts.
2019-06-20 21:36:12 -03:00
Fernando Sahmkow
6162cb922e texture_cache: Document the most important methods. 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
4530511ee4 texture_cache: Try to Reconstruct Surface on bigger than overlap.
This fixes clouds in SMO Cap Kingdom and lens on Cloud Kingdom.
Also moved accurate_gpu setting check to Pick Strategy
2019-06-20 21:36:12 -03:00
Fernando Sahmkow
a79831d9d0 texture_cache: Implement Guard mechanism 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
7731a0e2d1 texture_cache: General Fixes
Fixed ASTC mipmaps loading
Fixed alignment on openGL upload/download
Fixed Block Height Calculation
Removed unalign_height
2019-06-20 21:36:12 -03:00
ReinUsesLisp
c2ed348bdd surface_params: Ensure pitch is always written to avoid surface leaks 2019-06-20 21:36:12 -03:00
ReinUsesLisp
9098905dd1 gl_framebuffer_cache: Use a hashed struct to cache framebuffers 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
d65a4af895 texture_cache return invalid buffer on deactivated color_mask 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
6bd034eae9 engine_upload: Addapt to new Texture Cache 2019-06-20 21:36:12 -03:00
ReinUsesLisp
2131f71573 surface_params: Optimize CreateForTexture
Instead of using Common::AlignUp, use Common::AlignBits to align the
texture compression factor.
2019-06-20 21:36:12 -03:00
Fernando Sahmkow
41b4674458 gl_texture_cache: Make main views be proxy textures instead of a full view. 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
07cc7e0c12 texture_cache: Add ASync Protections 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
1bbc9debfb Remove Framebuffer reconfiguration and restrict rendertarget protection 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
5192521dc3 texture_cache: Implement GPU Dirty Flags 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
94f2be5473 texture_cache: Optimize GetMipBlockHeight and GetMipBlockDepth 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
a4a58be2d4 texture_cache: Implement L1_Inner_cache 2019-06-20 21:36:12 -03:00
ReinUsesLisp
345e73f2fe video_core: Use un-shifted block sizes to avoid integer divisions
Instead of storing all block width, height and depths in their shifted
form:

block_width = 1U << block_shift;

Store them like they are provided by the emulated hardware (their
block_shift form). This way we can avoid doing the costly
Common::AlignUp operation to align texture sizes and drop CPU integer
divisions with bitwise logic (defined in Common::AlignBits).
2019-06-20 21:36:12 -03:00
ReinUsesLisp
28d7c2f5a5 texture_cache: Change internal cache from lists to vectors 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
b347543e83 Reduce amount of size calculations. 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
4e2071b6d9 texture_cache: Correct premature texceptions
Due to our current infrastructure, it is possible for a mipmap to be set 
on as a render target before a texception of that mipmap's superset be 
set afterwards. This is problematic as we rely on texture views to set 
up texceptions and protecting render targets targets for 3D texture 
rendering.

One simple solution is to configure framebuffers after texture setup but 
this brings other problems. This solution, forces a reconfiguration of 
the framebuffers after such event happens.
2019-06-20 21:36:12 -03:00
Fernando Sahmkow
ba677ccb5a texture_cache: Implement guest flushing 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
de0b1cb2b2 Fixes to mipmap's process and reconstruct process 2019-06-20 21:36:12 -03:00
ReinUsesLisp
e0002599ac surface_base: Add parenthesis to EmplaceOverview's predicate 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
324e470879 Texture Cache: Implement Blitting and Fermi Copies 2019-06-20 21:36:12 -03:00
ReinUsesLisp
549fd18ac4 surface_view: Add constructor for ViewParams 2019-06-20 21:36:12 -03:00
ReinUsesLisp
16e8625a30 surface_base: Split BreakDown into layered and non-layered variants 2019-06-20 21:36:12 -03:00
ReinUsesLisp
2b30000a1e surface_base: Silence truncation warnings and minor renames and reordering 2019-06-20 21:36:12 -03:00
ReinUsesLisp
03d10ea3b4 copy_params: Use constructor instead of C-like initialization 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
1af4414861 Correct Mipmaps View method in Texture Cache 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
d86f9cd709 Change texture_cache chaching from GPUAddr to CacheAddr
This also reverses the changes to make invalidation and flushing through
the GPU address.
2019-06-20 21:36:12 -03:00
Fernando Sahmkow
b711cdce78 Corrections to Structural Matching
The texture will now be reconstructed if the width only matches on GoB 
alignment.
2019-06-20 21:36:12 -03:00
Fernando Sahmkow
bc930754cc Implement Texture Cache V2 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
3d471e732d Correct Surface Base and Views for new Texture Cache 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
3b26206dbd Add OGLTextureView 2019-06-20 21:36:12 -03:00
Fernando Sahmkow
6b0695b3cd Deglobalize Memory Manager on texture cahe and Implement Invalidation and Flushing using GPUVAddr 2019-06-20 21:36:11 -03:00
ReinUsesLisp
6c410104f4 texture_cache: Remove execution context copies from the texture cache
This is done to simplify the OpenGL implementation, it is needed for
Vulkan.
2019-06-20 21:36:11 -03:00
ReinUsesLisp
fa59a7b4d8 gl_texture_cache: Implement fermi copies 2019-06-20 21:36:11 -03:00
ReinUsesLisp
1b4503c571 texture_cache: Split texture cache into different files 2019-06-20 21:36:11 -03:00
ReinUsesLisp
5f3aacdc37 texture_cache: Move staging buffer into a generic implementation 2019-06-20 21:36:11 -03:00
ReinUsesLisp
2787a0c287 texture_cache: Flush 3D textures in the order they are drawn 2019-06-20 21:36:11 -03:00
ReinUsesLisp
4b396f375c gl_texture_cache: Minor changes 2019-06-20 21:36:11 -03:00
ReinUsesLisp
0cefb7bcb4 gl_texture_cache: Add copy from multiple overlaps into a single surface 2019-06-20 21:36:11 -03:00
ReinUsesLisp
84139586c9 gl_texture_cache: Attach surface textures instead of views 2019-06-20 21:36:11 -03:00
ReinUsesLisp
fb94871791 gl_texture_cache: Add fast copy path 2019-06-20 21:36:11 -03:00
ReinUsesLisp
bab21e8cb3 gl_texture_cache: Initial implementation 2019-06-20 21:36:11 -03:00
Fernando Sahmkow
90792cdb6e Core_Timing: Make core_timing threadsafe by default.
The old implementation had faulty Threadsafe methods where events could
be missing. This implementation unifies unsafe/safe methods and makes
core timing thread safe overall.
2019-06-16 14:14:35 -04:00
ReinUsesLisp
4ec8a3df08 gl_shader_cache: Use static constructors for CachedShader initialization 2019-06-07 20:20:22 -03:00
163 changed files with 5883 additions and 3857 deletions

19
.ci/yuzu-mainline.yml Normal file
View File

@@ -0,0 +1,19 @@
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
steps:
- script: echo Hello, world!
displayName: 'Run a one-line script'
- script: |
echo Add other tasks to build, test, and deploy your project.
echo See https://aka.ms/yaml
displayName: 'Run a multi-line script'

19
.ci/yuzu-patreon.yml Normal file
View File

@@ -0,0 +1,19 @@
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
steps:
- script: echo Hello, world!
displayName: 'Run a one-line script'
- script: |
echo Add other tasks to build, test, and deploy your project.
echo See https://aka.ms/yaml
displayName: 'Run a multi-line script'

19
.ci/yuzu-repo-sync.yml Normal file
View File

@@ -0,0 +1,19 @@
trigger:
- master
jobs:
- job: copy
displayName: 'Sync Repository'
pool:
vmImage: 'ubuntu-latest'
steps:
- script: echo 'https://$(GitUsername):$(GitAccessToken)@dev.azure.com' > $HOME/.git-credentials
displayName: 'Load Credentials'
- script: git config --global credential.helper store
displayName: 'Register Credential Helper'
- script: git remote add other $(GitRepoPushChangesURL)
displayName: 'Register Repository'
- script: git push --force other HEAD:$(GitPushBranch)
displayName: 'Update Code'
- script: rm -rf $HOME/.git-credentials
displayName: 'Clear Cached Credentials'

19
.ci/yuzu.yml Normal file
View File

@@ -0,0 +1,19 @@
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
steps:
- script: echo Hello, world!
displayName: 'Run a one-line script'
- script: |
echo Add other tasks to build, test, and deploy your project.
echo See https://aka.ms/yaml
displayName: 'Run a multi-line script'

View File

@@ -70,6 +70,7 @@ set(HASH_FILES
"${VIDEO_CORE}/shader/decode/half_set.cpp"
"${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
"${VIDEO_CORE}/shader/decode/hfma2.cpp"
"${VIDEO_CORE}/shader/decode/image.cpp"
"${VIDEO_CORE}/shader/decode/integer_set.cpp"
"${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
"${VIDEO_CORE}/shader/decode/memory.cpp"

View File

@@ -217,13 +217,15 @@ std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_co
if (offset == samples.size()) {
offset = 0;
if (!wave_buffer.is_looping) {
if (!wave_buffer.is_looping && wave_buffer.buffer_sz) {
SetWaveIndex(wave_index + 1);
}
out_status.wave_buffer_consumed++;
if (wave_buffer.buffer_sz) {
out_status.wave_buffer_consumed++;
}
if (wave_buffer.end_of_stream) {
if (wave_buffer.end_of_stream || wave_buffer.buffer_sz == 0) {
info.play_state = PlayState::Paused;
}
}

View File

@@ -105,7 +105,7 @@ void Stream::PlayNextBuffer() {
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
core_timing.ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
core_timing.ScheduleEvent(GetBufferReleaseCycles(*active_buffer), release_event, {});
}
void Stream::ReleaseActiveBuffer() {

View File

@@ -44,6 +44,7 @@ add_custom_command(OUTPUT scm_rev.cpp
"${VIDEO_CORE}/shader/decode/half_set.cpp"
"${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
"${VIDEO_CORE}/shader/decode/hfma2.cpp"
"${VIDEO_CORE}/shader/decode/image.cpp"
"${VIDEO_CORE}/shader/decode/integer_set.cpp"
"${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
"${VIDEO_CORE}/shader/decode/memory.cpp"
@@ -74,6 +75,7 @@ add_library(common STATIC
assert.h
detached_tasks.cpp
detached_tasks.h
binary_find.h
bit_field.h
bit_util.h
cityhash.cpp

View File

@@ -19,6 +19,12 @@ constexpr T AlignDown(T value, std::size_t size) {
return static_cast<T>(value - value % size);
}
template <typename T>
constexpr T AlignBits(T value, std::size_t align) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
}
template <typename T>
constexpr bool Is4KBAligned(T value) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");

21
src/common/binary_find.h Normal file
View File

@@ -0,0 +1,21 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <algorithm>
namespace Common {
template <class ForwardIt, class T, class Compare = std::less<>>
ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value, Compare comp = {}) {
// Note: BOTH type T and the type after ForwardIt is dereferenced
// must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
// This is stricter than lower_bound requirement (see above)
first = std::lower_bound(first, last, value, comp);
return first != last && !comp(value, *first) ? first : last;
}
} // namespace Common

View File

@@ -97,4 +97,48 @@ inline u32 CountTrailingZeroes64(u64 value) {
}
#endif
#ifdef _MSC_VER
inline u32 MostSignificantBit32(const u32 value) {
unsigned long result;
_BitScanReverse(&result, value);
return static_cast<u32>(result);
}
inline u32 MostSignificantBit64(const u64 value) {
unsigned long result;
_BitScanReverse64(&result, value);
return static_cast<u32>(result);
}
#else
inline u32 MostSignificantBit32(const u32 value) {
return 31U - static_cast<u32>(__builtin_clz(value));
}
inline u32 MostSignificantBit64(const u64 value) {
return 63U - static_cast<u32>(__builtin_clzll(value));
}
#endif
inline u32 Log2Floor32(const u32 value) {
return MostSignificantBit32(value);
}
inline u32 Log2Ceil32(const u32 value) {
const u32 log2_f = Log2Floor32(value);
return log2_f + ((value ^ (1U << log2_f)) != 0U);
}
inline u32 Log2Floor64(const u64 value) {
return MostSignificantBit64(value);
}
inline u32 Log2Ceil64(const u64 value) {
const u64 log2_f = static_cast<u64>(Log2Floor64(value));
return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL));
}
} // namespace Common

View File

@@ -4,6 +4,7 @@
#pragma once
#include <algorithm>
#include <string>
#if !defined(ARCHITECTURE_x86_64)

View File

@@ -175,6 +175,7 @@ add_library(core STATIC
hle/service/acc/acc_u0.h
hle/service/acc/acc_u1.cpp
hle/service/acc/acc_u1.h
hle/service/acc/errors.h
hle/service/acc/profile_manager.cpp
hle/service/acc/profile_manager.h
hle/service/am/am.cpp
@@ -207,6 +208,8 @@ add_library(core STATIC
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
hle/service/apm/apm.h
hle/service/apm/controller.cpp
hle/service/apm/controller.h
hle/service/apm/interface.cpp
hle/service/apm/interface.h
hle/service/audio/audctl.cpp
@@ -270,6 +273,7 @@ add_library(core STATIC
hle/service/filesystem/fsp_srv.h
hle/service/fgm/fgm.cpp
hle/service/fgm/fgm.h
hle/service/friend/errors.h
hle/service/friend/friend.cpp
hle/service/friend/friend.h
hle/service/friend/interface.cpp
@@ -291,6 +295,7 @@ add_library(core STATIC
hle/service/hid/irs.h
hle/service/hid/xcd.cpp
hle/service/hid/xcd.h
hle/service/hid/errors.h
hle/service/hid/controllers/controller_base.cpp
hle/service/hid/controllers/controller_base.h
hle/service/hid/controllers/debug_pad.cpp
@@ -429,6 +434,8 @@ add_library(core STATIC
hle/service/time/interface.h
hle/service/time/time.cpp
hle/service/time/time.h
hle/service/time/time_sharedmemory.cpp
hle/service/time/time_sharedmemory.h
hle/service/usb/usb.cpp
hle/service/usb/usb.h
hle/service/vi/display/vi_display.cpp

View File

@@ -44,13 +44,6 @@ public:
/// Step CPU by one instruction
virtual void Step() = 0;
/// Maps a backing memory region for the CPU
virtual void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
Kernel::VMAPermission perms) = 0;
/// Unmaps a region of memory that was previously mapped using MapBackingMemory
virtual void UnmapMemory(VAddr address, std::size_t size) = 0;
/// Clear all instruction cache
virtual void ClearInstructionCache() = 0;

View File

@@ -177,15 +177,6 @@ ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
ARM_Dynarmic::~ARM_Dynarmic() = default;
void ARM_Dynarmic::MapBackingMemory(u64 address, std::size_t size, u8* memory,
Kernel::VMAPermission perms) {
inner_unicorn.MapBackingMemory(address, size, memory, perms);
}
void ARM_Dynarmic::UnmapMemory(u64 address, std::size_t size) {
inner_unicorn.UnmapMemory(address, size);
}
void ARM_Dynarmic::SetPC(u64 pc) {
jit->SetPC(pc);
}

View File

@@ -23,9 +23,6 @@ public:
ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ARM_Dynarmic() override;
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
Kernel::VMAPermission perms) override;
void UnmapMemory(u64 address, std::size_t size) override;
void SetPC(u64 pc) override;
u64 GetPC() const override;
u64 GetReg(int index) const override;

View File

@@ -76,15 +76,6 @@ ARM_Unicorn::~ARM_Unicorn() {
CHECKED(uc_close(uc));
}
void ARM_Unicorn::MapBackingMemory(VAddr address, std::size_t size, u8* memory,
Kernel::VMAPermission perms) {
CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory));
}
void ARM_Unicorn::UnmapMemory(VAddr address, std::size_t size) {
CHECKED(uc_mem_unmap(uc, address, size));
}
void ARM_Unicorn::SetPC(u64 pc) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
}

View File

@@ -18,9 +18,6 @@ public:
explicit ARM_Unicorn(System& system);
~ARM_Unicorn() override;
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
Kernel::VMAPermission perms) override;
void UnmapMemory(VAddr address, std::size_t size) override;
void SetPC(u64 pc) override;
u64 GetPC() const override;
u64 GetReg(int index) const override;

View File

@@ -25,6 +25,7 @@
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -143,7 +144,7 @@ struct System::Impl {
telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>();
Service::Init(service_manager, system, *virtual_filesystem);
Service::Init(service_manager, system);
GDBStub::Init();
renderer = VideoCore::CreateRenderer(emu_window, system);
@@ -306,6 +307,9 @@ struct System::Impl {
/// Frontend applets
Service::AM::Applets::AppletManager applet_manager;
/// APM (Performance) services
Service::APM::Controller apm_controller{core_timing};
/// Glue services
Service::Glue::ARPManager arp_manager;
@@ -568,6 +572,14 @@ const Service::Glue::ARPManager& System::GetARPManager() const {
return impl->arp_manager;
}
Service::APM::Controller& System::GetAPMController() {
return impl->apm_controller;
}
const Service::APM::Controller& System::GetAPMController() const {
return impl->apm_controller;
}
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
return impl->Init(*this, emu_window);
}

View File

@@ -43,6 +43,10 @@ struct AppletFrontendSet;
class AppletManager;
} // namespace AM::Applets
namespace APM {
class Controller;
}
namespace Glue {
class ARPManager;
}
@@ -296,6 +300,10 @@ public:
const Service::Glue::ARPManager& GetARPManager() const;
Service::APM::Controller& GetAPMController();
const Service::APM::Controller& GetAPMController() const;
private:
System();

View File

@@ -53,16 +53,12 @@ bool CpuBarrier::Rendezvous() {
Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
std::size_t core_index)
: cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} {
if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
#else
arm_interface = std::make_unique<ARM_Unicorn>(system);
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
arm_interface = std::make_unique<ARM_Unicorn>(system);
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
} else {
arm_interface = std::make_unique<ARM_Unicorn>(system);
}
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface);
}
@@ -70,15 +66,12 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
Cpu::~Cpu() = default;
std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
return std::make_unique<DynarmicExclusiveMonitor>(num_cores);
return std::make_unique<DynarmicExclusiveMonitor>(num_cores);
#else
return nullptr; // TODO(merry): Passthrough exclusive monitor
// TODO(merry): Passthrough exclusive monitor
return nullptr;
#endif
} else {
return nullptr; // TODO(merry): Passthrough exclusive monitor
}
}
void Cpu::RunLoop(bool tight_loop) {

View File

@@ -56,12 +56,12 @@ void CoreTiming::Initialize() {
}
void CoreTiming::Shutdown() {
MoveEvents();
ClearPendingEvents();
UnregisterAllEvents();
}
EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) {
std::lock_guard guard{inner_mutex};
// check for existing type with same name.
// we want event type names to remain unique so that we can use them for serialization.
ASSERT_MSG(event_types.find(name) == event_types.end(),
@@ -82,6 +82,7 @@ void CoreTiming::UnregisterAllEvents() {
void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
ASSERT(event_type != nullptr);
std::lock_guard guard{inner_mutex};
const s64 timeout = GetTicks() + cycles_into_future;
// If this event needs to be scheduled before the next advance(), force one early
@@ -93,12 +94,8 @@ void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_ty
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
void CoreTiming::ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
u64 userdata) {
ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type});
}
void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
std::lock_guard guard{inner_mutex};
const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
return e.type == event_type && e.userdata == userdata;
});
@@ -110,10 +107,6 @@ void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
}
}
void CoreTiming::UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) {
unschedule_queue.Push(std::make_pair(event_type, userdata));
}
u64 CoreTiming::GetTicks() const {
u64 ticks = static_cast<u64>(global_timer);
if (!is_global_timer_sane) {
@@ -135,6 +128,7 @@ void CoreTiming::ClearPendingEvents() {
}
void CoreTiming::RemoveEvent(const EventType* event_type) {
std::lock_guard guard{inner_mutex};
const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
[&](const Event& e) { return e.type == event_type; });
@@ -145,11 +139,6 @@ void CoreTiming::RemoveEvent(const EventType* event_type) {
}
}
void CoreTiming::RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
MoveEvents();
RemoveEvent(event_type);
}
void CoreTiming::ForceExceptionCheck(s64 cycles) {
cycles = std::max<s64>(0, cycles);
if (downcount <= cycles) {
@@ -162,19 +151,8 @@ void CoreTiming::ForceExceptionCheck(s64 cycles) {
downcount = static_cast<int>(cycles);
}
void CoreTiming::MoveEvents() {
for (Event ev; ts_queue.Pop(ev);) {
ev.fifo_order = event_fifo_id++;
event_queue.emplace_back(std::move(ev));
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
}
void CoreTiming::Advance() {
MoveEvents();
for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) {
UnscheduleEvent(ev.first, ev.second);
}
std::unique_lock<std::mutex> guard(inner_mutex);
const int cycles_executed = slice_length - downcount;
global_timer += cycles_executed;
@@ -186,7 +164,9 @@ void CoreTiming::Advance() {
Event evt = std::move(event_queue.front());
std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
event_queue.pop_back();
inner_mutex.unlock();
evt.type->callback(evt.userdata, global_timer - evt.time);
inner_mutex.lock();
}
is_global_timer_sane = false;

View File

@@ -6,6 +6,7 @@
#include <chrono>
#include <functional>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
@@ -67,7 +68,7 @@ public:
///
EventType* RegisterEvent(const std::string& name, TimedCallback callback);
/// Unregisters all registered events thus far.
/// Unregisters all registered events thus far. Note: not thread unsafe
void UnregisterAllEvents();
/// After the first Advance, the slice lengths and the downcount will be reduced whenever an
@@ -76,20 +77,10 @@ public:
/// Scheduling from a callback will not update the downcount until the Advance() completes.
void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
/// This is to be called when outside of hle threads, such as the graphics thread, wants to
/// schedule things to be executed on the main thread.
///
/// @note This doesn't change slice_length and thus events scheduled by this might be
/// called with a delay of up to MAX_SLICE_LENGTH
void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
u64 userdata = 0);
void UnscheduleEvent(const EventType* event_type, u64 userdata);
void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata);
/// We only permit one event of each type in the queue at a time.
void RemoveEvent(const EventType* event_type);
void RemoveNormalAndThreadsafeEvent(const EventType* event_type);
void ForceExceptionCheck(s64 cycles);
@@ -120,7 +111,6 @@ private:
/// Clear all pending events. This should ONLY be done on exit.
void ClearPendingEvents();
void MoveEvents();
s64 global_timer = 0;
s64 idled_cycles = 0;
@@ -143,14 +133,9 @@ private:
// remain stable regardless of rehashes/resizing.
std::unordered_map<std::string, EventType> event_types;
// The queue for storing the events from other threads threadsafe until they will be added
// to the event_queue by the emu thread
Common::MPSCQueue<Event> ts_queue;
// The queue for unscheduling the events from other threads threadsafe
Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue;
EventType* ev_lost = nullptr;
std::mutex inner_mutex;
};
} // namespace Core::Timing

View File

@@ -35,9 +35,9 @@ enum class ContentRecordType : u8 {
Program = 1,
Data = 2,
Control = 3,
Manual = 4,
Legal = 5,
Patch = 6,
HtmlDocument = 4,
LegalInformation = 5,
DeltaFragment = 6,
};
struct ContentRecord {

View File

@@ -99,7 +99,7 @@ ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
return ContentRecordType::Data;
case NCAContentType::Manual:
// TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal.
return ContentRecordType::Manual;
return ContentRecordType::HtmlDocument;
default:
UNREACHABLE_MSG("Invalid NCAContentType={:02X}", static_cast<u8>(type));
}
@@ -397,8 +397,8 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
});
if (meta_iter == ncas.end()) {
LOG_ERROR(Loader, "The XCI you are attempting to install does not have a metadata NCA and "
"is therefore malformed. Double check your encryption keys.");
LOG_ERROR(Loader, "The file you are attempting to install does not have a metadata NCA and "
"is therefore malformed. Check your encryption keys.");
return InstallResult::ErrorMetaFailed;
}
@@ -415,6 +415,9 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
const auto cnmt_file = section0->GetFiles()[0];
const CNMT cnmt(cnmt_file);
for (const auto& record : cnmt.GetContentRecords()) {
// Ignore DeltaFragments, they are not useful to us
if (record.type == ContentRecordType::DeltaFragment)
continue;
const auto nca = GetNCAFromNSPForID(nsp, record.nca_id);
if (nca == nullptr)
return InstallResult::ErrorCopyFailed;

View File

@@ -248,10 +248,13 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
if (next_file == nullptr) {
LOG_WARNING(Service_FS,
"NCA with ID {}.nca is listed in content metadata, but cannot "
"be found in PFS. NSP appears to be corrupted.",
id_string);
if (rec.type != ContentRecordType::DeltaFragment) {
LOG_WARNING(Service_FS,
"NCA with ID {}.nca is listed in content metadata, but cannot "
"be found in PFS. NSP appears to be corrupted.",
id_string);
}
continue;
}

View File

@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <bitset>
#include <memory>
#include <random>
#include "common/alignment.h"
@@ -48,8 +49,58 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) {
}
} // Anonymous namespace
SharedPtr<Process> Process::Create(Core::System& system, std::string name,
Process::ProcessType type) {
// Represents a page used for thread-local storage.
//
// Each TLS page contains slots that may be used by processes and threads.
// Every process and thread is created with a slot in some arbitrary page
// (whichever page happens to have an available slot).
class TLSPage {
public:
static constexpr std::size_t num_slot_entries = Memory::PAGE_SIZE / Memory::TLS_ENTRY_SIZE;
explicit TLSPage(VAddr address) : base_address{address} {}
bool HasAvailableSlots() const {
return !is_slot_used.all();
}
VAddr GetBaseAddress() const {
return base_address;
}
std::optional<VAddr> ReserveSlot() {
for (std::size_t i = 0; i < is_slot_used.size(); i++) {
if (is_slot_used[i]) {
continue;
}
is_slot_used[i] = true;
return base_address + (i * Memory::TLS_ENTRY_SIZE);
}
return std::nullopt;
}
void ReleaseSlot(VAddr address) {
// Ensure that all given addresses are consistent with how TLS pages
// are intended to be used when releasing slots.
ASSERT(IsWithinPage(address));
ASSERT((address % Memory::TLS_ENTRY_SIZE) == 0);
const std::size_t index = (address - base_address) / Memory::TLS_ENTRY_SIZE;
is_slot_used[index] = false;
}
private:
bool IsWithinPage(VAddr address) const {
return base_address <= address && address < base_address + Memory::PAGE_SIZE;
}
VAddr base_address;
std::bitset<num_slot_entries> is_slot_used;
};
SharedPtr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) {
auto& kernel = system.Kernel();
SharedPtr<Process> process(new Process(system));
@@ -181,61 +232,55 @@ void Process::PrepareForTermination() {
}
/**
* Finds a free location for the TLS section of a thread.
* @param tls_slots The TLS page array of the thread's owner process.
* Returns a tuple of (page, slot, alloc_needed) where:
* page: The index of the first allocated TLS page that has free slots.
* slot: The index of the first free slot in the indicated page.
* alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
* Attempts to find a TLS page that contains a free slot for
* use by a thread.
*
* @returns If a page with an available slot is found, then an iterator
* pointing to the page is returned. Otherwise the end iterator
* is returned instead.
*/
static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
const std::vector<std::bitset<8>>& tls_slots) {
// Iterate over all the allocated pages, and try to find one where not all slots are used.
for (std::size_t page = 0; page < tls_slots.size(); ++page) {
const auto& page_tls_slots = tls_slots[page];
if (!page_tls_slots.all()) {
// We found a page with at least one free slot, find which slot it is
for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
if (!page_tls_slots.test(slot)) {
return std::make_tuple(page, slot, false);
}
}
}
}
return std::make_tuple(0, 0, true);
static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) {
return std::find_if(tls_pages.begin(), tls_pages.end(),
[](const auto& page) { return page.HasAvailableSlots(); });
}
VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress();
VAddr Process::CreateTLSRegion() {
auto tls_page_iter = FindTLSPageWithAvailableSlots(tls_pages);
if (needs_allocation) {
tls_slots.emplace_back(0); // The page is completely available at the start
available_page = tls_slots.size() - 1;
available_slot = 0; // Use the first slot in the new page
if (tls_page_iter == tls_pages.cend()) {
const auto region_address =
vm_manager.FindFreeRegion(vm_manager.GetTLSIORegionBaseAddress(),
vm_manager.GetTLSIORegionEndAddress(), Memory::PAGE_SIZE);
ASSERT(region_address.Succeeded());
// Allocate some memory from the end of the linear heap for this region.
auto& tls_memory = thread.GetTLSMemory();
tls_memory->insert(tls_memory->end(), Memory::PAGE_SIZE, 0);
const auto map_result = vm_manager.MapMemoryBlock(
*region_address, std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE), 0,
Memory::PAGE_SIZE, MemoryState::ThreadLocal);
ASSERT(map_result.Succeeded());
vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
tls_pages.emplace_back(*region_address);
vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0,
Memory::PAGE_SIZE, MemoryState::ThreadLocal);
const auto reserve_result = tls_pages.back().ReserveSlot();
ASSERT(reserve_result.has_value());
return *reserve_result;
}
tls_slots[available_page].set(available_slot);
return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE;
return *tls_page_iter->ReserveSlot();
}
void Process::FreeTLSSlot(VAddr tls_address) {
const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress();
const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
void Process::FreeTLSRegion(VAddr tls_address) {
const VAddr aligned_address = Common::AlignDown(tls_address, Memory::PAGE_SIZE);
auto iter =
std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) {
return page.GetBaseAddress() == aligned_address;
});
tls_slots[tls_page].reset(tls_slot);
// Something has gone very wrong if we're freeing a region
// with no actual page available.
ASSERT(iter != tls_pages.cend());
iter->ReleaseSlot(tls_address);
}
void Process::LoadModule(CodeSet module_, VAddr base_addr) {

View File

@@ -5,7 +5,6 @@
#pragma once
#include <array>
#include <bitset>
#include <cstddef>
#include <list>
#include <string>
@@ -32,6 +31,7 @@ namespace Kernel {
class KernelCore;
class ResourceLimit;
class Thread;
class TLSPage;
struct CodeSet;
@@ -260,10 +260,10 @@ public:
// Thread-local storage management
// Marks the next available region as used and returns the address of the slot.
VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread);
[[nodiscard]] VAddr CreateTLSRegion();
// Frees a used TLS slot identified by the given address
void FreeTLSSlot(VAddr tls_address);
void FreeTLSRegion(VAddr tls_address);
private:
explicit Process(Core::System& system);
@@ -290,7 +290,7 @@ private:
u64 code_memory_size = 0;
/// Current status of the process
ProcessStatus status;
ProcessStatus status{};
/// The ID of this process
u64 process_id = 0;
@@ -310,7 +310,7 @@ private:
/// holds the TLS for a specific thread. This vector contains which parts are in use for each
/// page as a bitmask.
/// This vector will grow as more pages are allocated for new threads.
std::vector<std::bitset<8>> tls_slots;
std::vector<TLSPage> tls_pages;
/// Contains the parsed process capability descriptors.
ProcessCapabilities capabilities;
@@ -339,7 +339,7 @@ private:
Mutex mutex;
/// Random values for svcGetInfo RandomEntropy
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
/// List of threads that are running with this process as their owner.
std::list<const Thread*> thread_list;

View File

@@ -98,9 +98,9 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add
return ERR_INVALID_ADDRESS_STATE;
}
if (!vm_manager.IsWithinNewMapRegion(dst_addr, size)) {
if (!vm_manager.IsWithinStackRegion(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}",
"Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
dst_addr, size);
return ERR_INVALID_MEMORY_RANGE;
}
@@ -726,8 +726,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
// 2.0.0+
ASLRRegionBaseAddr = 12,
ASLRRegionSize = 13,
NewMapRegionBaseAddr = 14,
NewMapRegionSize = 15,
StackRegionBaseAddr = 14,
StackRegionSize = 15,
// 3.0.0+
IsVirtualAddressMemoryEnabled = 16,
PersonalMmHeapUsage = 17,
@@ -752,8 +752,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
case GetInfoType::HeapRegionSize:
case GetInfoType::ASLRRegionBaseAddr:
case GetInfoType::ASLRRegionSize:
case GetInfoType::NewMapRegionBaseAddr:
case GetInfoType::NewMapRegionSize:
case GetInfoType::StackRegionBaseAddr:
case GetInfoType::StackRegionSize:
case GetInfoType::TotalPhysicalMemoryAvailable:
case GetInfoType::TotalPhysicalMemoryUsed:
case GetInfoType::IsVirtualAddressMemoryEnabled:
@@ -806,12 +806,12 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
*result = process->VMManager().GetASLRRegionSize();
return RESULT_SUCCESS;
case GetInfoType::NewMapRegionBaseAddr:
*result = process->VMManager().GetNewMapRegionBaseAddress();
case GetInfoType::StackRegionBaseAddr:
*result = process->VMManager().GetStackRegionBaseAddress();
return RESULT_SUCCESS;
case GetInfoType::NewMapRegionSize:
*result = process->VMManager().GetNewMapRegionSize();
case GetInfoType::StackRegionSize:
*result = process->VMManager().GetStackRegionSize();
return RESULT_SUCCESS;
case GetInfoType::TotalPhysicalMemoryAvailable:

View File

@@ -65,7 +65,7 @@ void Thread::Stop() {
owner_process->UnregisterThread(this);
// Mark the TLS slot in the thread's page as free.
owner_process->FreeTLSSlot(tls_address);
owner_process->FreeTLSRegion(tls_address);
}
void Thread::WakeAfterDelay(s64 nanoseconds) {
@@ -76,13 +76,13 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
// This function might be called from any thread so we have to be cautious and use the
// thread-safe version of ScheduleEvent.
const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
Core::System::GetInstance().CoreTiming().ScheduleEventThreadsafe(
Core::System::GetInstance().CoreTiming().ScheduleEvent(
cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle);
}
void Thread::CancelWakeupTimer() {
Core::System::GetInstance().CoreTiming().UnscheduleEventThreadsafe(
kernel.ThreadWakeupCallbackEventType(), callback_handle);
Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
callback_handle);
}
static std::optional<s32> GetNextProcessorId(u64 mask) {
@@ -205,9 +205,9 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
thread->name = std::move(name);
thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
thread->owner_process = &owner_process;
thread->tls_address = thread->owner_process->CreateTLSRegion();
thread->scheduler = &system.Scheduler(processor_id);
thread->scheduler->AddThread(thread);
thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
thread->owner_process->RegisterThread(thread.get());

View File

@@ -5,7 +5,6 @@
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -78,9 +77,6 @@ enum class ThreadActivity : u32 {
class Thread final : public WaitObject {
public:
using TLSMemory = std::vector<u8>;
using TLSMemoryPtr = std::shared_ptr<TLSMemory>;
using MutexWaitingThreads = std::vector<SharedPtr<Thread>>;
using ThreadContext = Core::ARM_Interface::ThreadContext;
@@ -169,14 +165,6 @@ public:
return thread_id;
}
TLSMemoryPtr& GetTLSMemory() {
return tls_memory;
}
const TLSMemoryPtr& GetTLSMemory() const {
return tls_memory;
}
/// Resumes a thread from waiting
void ResumeFromWait();
@@ -463,11 +451,9 @@ private:
u32 ideal_core{0xFFFFFFFF};
u64 affinity_mask{0x1};
TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>();
ThreadActivity activity = ThreadActivity::Normal;
std::string name;
ThreadActivity activity = ThreadActivity::Normal;
};
/**

View File

@@ -8,7 +8,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/memory_hook.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/errors.h"
@@ -109,15 +108,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
VirtualMemoryArea& final_vma = vma_handle->second;
ASSERT(final_vma.size == size);
system.ArmInterface(0).MapBackingMemory(target, size, block->data() + offset,
VMAPermission::ReadWriteExecute);
system.ArmInterface(1).MapBackingMemory(target, size, block->data() + offset,
VMAPermission::ReadWriteExecute);
system.ArmInterface(2).MapBackingMemory(target, size, block->data() + offset,
VMAPermission::ReadWriteExecute);
system.ArmInterface(3).MapBackingMemory(target, size, block->data() + offset,
VMAPermission::ReadWriteExecute);
final_vma.type = VMAType::AllocatedMemoryBlock;
final_vma.permissions = VMAPermission::ReadWrite;
final_vma.state = state;
@@ -137,11 +127,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
VirtualMemoryArea& final_vma = vma_handle->second;
ASSERT(final_vma.size == size);
system.ArmInterface(0).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
system.ArmInterface(1).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
system.ArmInterface(2).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
system.ArmInterface(3).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
final_vma.type = VMAType::BackingMemory;
final_vma.permissions = VMAPermission::ReadWrite;
final_vma.state = state;
@@ -152,22 +137,33 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
}
ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const {
// Find the first Free VMA.
const VAddr base = GetASLRRegionBaseAddress();
const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) {
if (vma.second.type != VMAType::Free)
return false;
return FindFreeRegion(GetASLRRegionBaseAddress(), GetASLRRegionEndAddress(), size);
}
const VAddr vma_end = vma.second.base + vma.second.size;
return vma_end > base && vma_end >= base + size;
});
ResultVal<VAddr> VMManager::FindFreeRegion(VAddr begin, VAddr end, u64 size) const {
ASSERT(begin < end);
ASSERT(size <= end - begin);
if (vma_handle == vma_map.end()) {
const VMAHandle vma_handle =
std::find_if(vma_map.begin(), vma_map.end(), [begin, end, size](const auto& vma) {
if (vma.second.type != VMAType::Free) {
return false;
}
const VAddr vma_base = vma.second.base;
const VAddr vma_end = vma_base + vma.second.size;
const VAddr assumed_base = (begin < vma_base) ? vma_base : begin;
const VAddr used_range = assumed_base + size;
return vma_base <= assumed_base && assumed_base < used_range && used_range < end &&
used_range <= vma_end;
});
if (vma_handle == vma_map.cend()) {
// TODO(Subv): Find the correct error code here.
return ResultCode(-1);
}
const VAddr target = std::max(base, vma_handle->second.base);
const VAddr target = std::max(begin, vma_handle->second.base);
return MakeResult<VAddr>(target);
}
@@ -219,11 +215,6 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) {
ASSERT(FindVMA(target)->second.size >= size);
system.ArmInterface(0).UnmapMemory(target, size);
system.ArmInterface(1).UnmapMemory(target, size);
system.ArmInterface(2).UnmapMemory(target, size);
system.ArmInterface(3).UnmapMemory(target, size);
return RESULT_SUCCESS;
}
@@ -614,9 +605,11 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) {
u64 map_region_size = 0;
u64 heap_region_size = 0;
u64 new_map_region_size = 0;
u64 stack_region_size = 0;
u64 tls_io_region_size = 0;
u64 stack_and_tls_io_end = 0;
switch (type) {
case FileSys::ProgramAddressSpaceType::Is32Bit:
case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
@@ -632,6 +625,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
map_region_size = 0;
heap_region_size = 0x80000000;
}
stack_and_tls_io_end = 0x40000000;
break;
case FileSys::ProgramAddressSpaceType::Is36Bit:
address_space_width = 36;
@@ -641,6 +635,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
aslr_region_end = aslr_region_base + 0xFF8000000;
map_region_size = 0x180000000;
heap_region_size = 0x180000000;
stack_and_tls_io_end = 0x80000000;
break;
case FileSys::ProgramAddressSpaceType::Is39Bit:
address_space_width = 39;
@@ -650,7 +645,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
aslr_region_end = aslr_region_base + 0x7FF8000000;
map_region_size = 0x1000000000;
heap_region_size = 0x180000000;
new_map_region_size = 0x80000000;
stack_region_size = 0x80000000;
tls_io_region_size = 0x1000000000;
break;
default:
@@ -658,6 +653,8 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
return;
}
const u64 stack_and_tls_io_begin = aslr_region_base;
address_space_base = 0;
address_space_end = 1ULL << address_space_width;
@@ -668,15 +665,20 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
heap_region_end = heap_region_base + heap_region_size;
heap_end = heap_region_base;
new_map_region_base = heap_region_end;
new_map_region_end = new_map_region_base + new_map_region_size;
stack_region_base = heap_region_end;
stack_region_end = stack_region_base + stack_region_size;
tls_io_region_base = new_map_region_end;
tls_io_region_base = stack_region_end;
tls_io_region_end = tls_io_region_base + tls_io_region_size;
if (new_map_region_size == 0) {
new_map_region_base = address_space_base;
new_map_region_end = address_space_end;
if (stack_region_size == 0) {
stack_region_base = stack_and_tls_io_begin;
stack_region_end = stack_and_tls_io_end;
}
if (tls_io_region_size == 0) {
tls_io_region_base = stack_and_tls_io_begin;
tls_io_region_end = stack_and_tls_io_end;
}
}
@@ -868,21 +870,21 @@ bool VMManager::IsWithinMapRegion(VAddr address, u64 size) const {
return IsInsideAddressRange(address, size, GetMapRegionBaseAddress(), GetMapRegionEndAddress());
}
VAddr VMManager::GetNewMapRegionBaseAddress() const {
return new_map_region_base;
VAddr VMManager::GetStackRegionBaseAddress() const {
return stack_region_base;
}
VAddr VMManager::GetNewMapRegionEndAddress() const {
return new_map_region_end;
VAddr VMManager::GetStackRegionEndAddress() const {
return stack_region_end;
}
u64 VMManager::GetNewMapRegionSize() const {
return new_map_region_end - new_map_region_base;
u64 VMManager::GetStackRegionSize() const {
return stack_region_end - stack_region_base;
}
bool VMManager::IsWithinNewMapRegion(VAddr address, u64 size) const {
return IsInsideAddressRange(address, size, GetNewMapRegionBaseAddress(),
GetNewMapRegionEndAddress());
bool VMManager::IsWithinStackRegion(VAddr address, u64 size) const {
return IsInsideAddressRange(address, size, GetStackRegionBaseAddress(),
GetStackRegionEndAddress());
}
VAddr VMManager::GetTLSIORegionBaseAddress() const {

View File

@@ -362,13 +362,38 @@ public:
ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state);
/**
* Finds the first free address that can hold a region of the desired size.
* Finds the first free memory region of the given size within
* the user-addressable ASLR memory region.
*
* @param size Size of the desired region.
* @return The found free address.
* @param size The size of the desired region in bytes.
*
* @returns If successful, the base address of the free region with
* the given size.
*/
ResultVal<VAddr> FindFreeRegion(u64 size) const;
/**
* Finds the first free address range that can hold a region of the desired size
*
* @param begin The starting address of the range.
* This is treated as an inclusive beginning address.
*
* @param end The ending address of the range.
* This is treated as an exclusive ending address.
*
* @param size The size of the free region to attempt to locate,
* in bytes.
*
* @returns If successful, the base address of the free region with
* the given size.
*
* @returns If unsuccessful, a result containing an error code.
*
* @pre The starting address must be less than the ending address.
* @pre The size must not exceed the address range itself.
*/
ResultVal<VAddr> FindFreeRegion(VAddr begin, VAddr end, u64 size) const;
/**
* Maps a memory-mapped IO region at a given address.
*
@@ -571,17 +596,17 @@ public:
/// Determines whether or not the specified range is within the map region.
bool IsWithinMapRegion(VAddr address, u64 size) const;
/// Gets the base address of the new map region.
VAddr GetNewMapRegionBaseAddress() const;
/// Gets the base address of the stack region.
VAddr GetStackRegionBaseAddress() const;
/// Gets the end address of the new map region.
VAddr GetNewMapRegionEndAddress() const;
/// Gets the end address of the stack region.
VAddr GetStackRegionEndAddress() const;
/// Gets the total size of the new map region in bytes.
u64 GetNewMapRegionSize() const;
/// Gets the total size of the stack region in bytes.
u64 GetStackRegionSize() const;
/// Determines whether or not the given address range is within the new map region
bool IsWithinNewMapRegion(VAddr address, u64 size) const;
/// Determines whether or not the given address range is within the stack region
bool IsWithinStackRegion(VAddr address, u64 size) const;
/// Gets the base address of the TLS IO region.
VAddr GetTLSIORegionBaseAddress() const;
@@ -701,8 +726,8 @@ private:
VAddr map_region_base = 0;
VAddr map_region_end = 0;
VAddr new_map_region_base = 0;
VAddr new_map_region_end = 0;
VAddr stack_region_base = 0;
VAddr stack_region_end = 0;
VAddr tls_io_region_base = 0;
VAddr tls_io_region_end = 0;

View File

@@ -15,13 +15,18 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/acc/acc.h"
#include "core/hle/service/acc/acc_aa.h"
#include "core/hle/service/acc/acc_su.h"
#include "core/hle/service/acc/acc_u0.h"
#include "core/hle/service/acc/acc_u1.h"
#include "core/hle/service/acc/errors.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/glue/arp.h"
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
namespace Service::Account {
@@ -217,10 +222,72 @@ void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestCon
rb.Push(profile_manager->CanSystemRegisterUser());
}
void Module::Interface::InitializeApplicationInfoOld(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto pid = rp.Pop<u64>();
LOG_DEBUG(Service_ACC, "called, process_id={}", pid);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
rb.Push(InitializeApplicationInfoBase(pid));
}
void Module::Interface::InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto pid = rp.Pop<u64>();
LOG_WARNING(Service_ACC, "(Partial implementation) called, process_id={}", pid);
// TODO(ogniK): We require checking if the user actually owns the title and what not. As of
// currently, we assume the user owns the title. InitializeApplicationInfoBase SHOULD be called
// first then we do extra checks if the game is a digital copy.
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(InitializeApplicationInfoBase(pid));
}
ResultCode Module::Interface::InitializeApplicationInfoBase(u64 process_id) {
if (application_info) {
LOG_ERROR(Service_ACC, "Application already initialized");
return ERR_ACCOUNTINFO_ALREADY_INITIALIZED;
}
const auto& list = system.Kernel().GetProcessList();
const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) {
return process->GetProcessID() == process_id;
});
if (iter == list.end()) {
LOG_ERROR(Service_ACC, "Failed to find process ID");
application_info.application_type = ApplicationType::Unknown;
return ERR_ACCOUNTINFO_BAD_APPLICATION;
}
const auto launch_property = system.GetARPManager().GetLaunchProperty((*iter)->GetTitleID());
if (launch_property.Failed()) {
LOG_ERROR(Service_ACC, "Failed to get launch property");
return ERR_ACCOUNTINFO_BAD_APPLICATION;
}
switch (launch_property->base_game_storage_id) {
case FileSys::StorageId::GameCard:
application_info.application_type = ApplicationType::GameCard;
break;
case FileSys::StorageId::Host:
case FileSys::StorageId::NandUser:
case FileSys::StorageId::SdCard:
application_info.application_type = ApplicationType::Digital;
break;
default:
LOG_ERROR(Service_ACC, "Invalid game storage ID");
return ERR_ACCOUNTINFO_BAD_APPLICATION;
}
LOG_WARNING(Service_ACC, "ApplicationInfo init required");
// TODO(ogniK): Actual initalization here
return RESULT_SUCCESS;
}
void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {

View File

@@ -4,6 +4,7 @@
#pragma once
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/service.h"
namespace Service::Account {
@@ -25,12 +26,33 @@ public:
void ListOpenUsers(Kernel::HLERequestContext& ctx);
void GetLastOpenedUser(Kernel::HLERequestContext& ctx);
void GetProfile(Kernel::HLERequestContext& ctx);
void InitializeApplicationInfoOld(Kernel::HLERequestContext& ctx);
void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
void InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx);
void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx);
private:
ResultCode InitializeApplicationInfoBase(u64 process_id);
enum class ApplicationType : u32_le {
GameCard = 0,
Digital = 1,
Unknown = 3,
};
struct ApplicationInfo {
Service::Glue::ApplicationLaunchProperty launch_property;
ApplicationType application_type;
constexpr explicit operator bool() const {
return launch_property.title_id != 0x0;
}
};
ApplicationInfo application_info{};
protected:
std::shared_ptr<Module> module;
std::shared_ptr<ProfileManager> profile_manager;

View File

@@ -22,7 +22,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
{60, nullptr, "ListOpenContextStoredUsers"},
{99, nullptr, "DebugActivateOpenContextRetention"},
{100, &ACC_U0::InitializeApplicationInfoOld, "InitializeApplicationInfoOld"},
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
{101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
{102, nullptr, "AuthenticateApplicationAsync"},
{103, nullptr, "CheckNetworkServiceAvailabilityAsync"},
@@ -31,7 +31,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{120, nullptr, "CreateGuestLoginRequest"},
{130, nullptr, "LoadOpenContext"},
{131, nullptr, "ListOpenContextStoredUsers"},
{140, nullptr, "InitializeApplicationInfo"},
{140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"},
{141, nullptr, "ListQualifiedUsers"},
{150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"},
};

View File

@@ -0,0 +1,14 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::Account {
constexpr ResultCode ERR_ACCOUNTINFO_BAD_APPLICATION{ErrorModule::Account, 22};
constexpr ResultCode ERR_ACCOUNTINFO_ALREADY_INITIALIZED{ErrorModule::Account, 41};
} // namespace Service::Account

View File

@@ -29,7 +29,8 @@
#include "core/hle/service/am/omm.h"
#include "core/hle/service/am/spsm.h"
#include "core/hle/service/am/tcap.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/apm/interface.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -270,7 +271,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
{70, nullptr, "ReportMultimediaError"},
{71, nullptr, "GetCurrentIlluminanceEx"},
{80, nullptr, "SetWirelessPriorityMode"},
{90, nullptr, "GetAccumulatedSuspendedTickValue"},
{90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
{100, nullptr, "SetAlbumImageTakenNotificationEnabled"},
{1000, nullptr, "GetDebugStorageChannel"},
@@ -283,10 +284,14 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
"ISelfController:LaunchableEvent");
// TODO(ogniK): Figure out where, when and why this event gets signalled
// This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
// called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
// ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
// suspended if the event has previously been created by a call to
// GetAccumulatedSuspendedTickChangedEvent.
accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Manual, "ISelfController:AccumulatedSuspendedTickChangedEvent");
accumulated_suspended_tick_changed_event.writable->Signal(); // Is signalled on creation
accumulated_suspended_tick_changed_event.writable->Signal();
}
ISelfController::~ISelfController() = default;
@@ -449,11 +454,19 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
rb.Push<u32>(idle_time_detection_extension);
}
void ISelfController::GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
// This command returns the total number of system ticks since ISelfController creation
// where the game was suspended. Since Yuzu doesn't implement game suspension, this command
// can just always return 0 ticks.
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
}
void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx) {
// The implementation of this function is fine as is, the reason we're labelling it as stubbed
// is because we're currently unsure when and where accumulated_suspended_tick_changed_event is
// actually signalled for the time being.
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_DEBUG(Service_AM, "called.");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
@@ -508,8 +521,9 @@ void AppletMessageQueue::OperationModeChanged() {
on_operation_mode_changed.writable->Signal();
}
ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
: ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) {
ICommonStateGetter::ICommonStateGetter(Core::System& system,
std::shared_ptr<AppletMessageQueue> msg_queue)
: ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -542,7 +556,7 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
{64, nullptr, "SetTvPowerStateMatchingMode"},
{65, nullptr, "GetApplicationIdByContentActionName"},
{66, nullptr, "SetCpuBoostMode"},
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{80, nullptr, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
@@ -623,6 +637,16 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
}
}
void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
const auto& sm = system.ServiceManager();
const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
ASSERT(apm_sys != nullptr);
apm_sys->SetCpuBoostMode(ctx);
}
IStorage::IStorage(std::vector<u8> buffer)
: ServiceFramework("IStorage"), buffer(std::move(buffer)) {
// clang-format off
@@ -651,13 +675,11 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
}
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
const bool use_docked_mode{Settings::values.use_docked_mode};
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
: APM::PerformanceMode::Handheld));
rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
}
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {

View File

@@ -133,6 +133,7 @@ private:
void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -145,7 +146,8 @@ private:
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue);
explicit ICommonStateGetter(Core::System& system,
std::shared_ptr<AppletMessageQueue> msg_queue);
~ICommonStateGetter() override;
private:
@@ -167,7 +169,9 @@ private:
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
void GetBootMode(Kernel::HLERequestContext& ctx);
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
Core::System& system;
std::shared_ptr<AppletMessageQueue> msg_queue;
};

View File

@@ -42,7 +42,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
@@ -146,7 +146,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetSelfController(Kernel::HLERequestContext& ctx) {

View File

@@ -80,7 +80,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {

View File

@@ -459,10 +459,10 @@ void WebBrowser::InitializeOffline() {
case OfflineWebSource::OfflineHtmlPage:
// While there is an AppID TLV field, in official SW this is always ignored.
title_id = 0;
type = FileSys::ContentRecordType::Manual;
type = FileSys::ContentRecordType::HtmlDocument;
break;
case OfflineWebSource::ApplicationLegalInformation:
type = FileSys::ContentRecordType::Legal;
type = FileSys::ContentRecordType::LegalInformation;
break;
case OfflineWebSource::SystemDataPage:
type = FileSys::ContentRecordType::Data;

View File

@@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/apm/interface.h"
@@ -12,11 +11,15 @@ namespace Service::APM {
Module::Module() = default;
Module::~Module() = default;
void InstallInterfaces(SM::ServiceManager& service_manager) {
void InstallInterfaces(Core::System& system) {
auto module_ = std::make_shared<Module>();
std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager);
std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager);
std::make_shared<APM_Sys>()->InstallAsService(service_manager);
std::make_shared<APM>(module_, system.GetAPMController(), "apm")
->InstallAsService(system.ServiceManager());
std::make_shared<APM>(module_, system.GetAPMController(), "apm:p")
->InstallAsService(system.ServiceManager());
std::make_shared<APM>(module_, system.GetAPMController(), "apm:am")
->InstallAsService(system.ServiceManager());
std::make_shared<APM_Sys>(system.GetAPMController())->InstallAsService(system.ServiceManager());
}
} // namespace Service::APM

View File

@@ -8,11 +8,6 @@
namespace Service::APM {
enum class PerformanceMode : u8 {
Handheld = 0,
Docked = 1,
};
class Module final {
public:
Module();
@@ -20,6 +15,6 @@ public:
};
/// Registers all AM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(Core::System& system);
} // namespace Service::APM

View File

@@ -0,0 +1,68 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/hle/service/apm/controller.h"
#include "core/settings.h"
namespace Service::APM {
constexpr PerformanceConfiguration DEFAULT_PERFORMANCE_CONFIGURATION =
PerformanceConfiguration::Config7;
Controller::Controller(Core::Timing::CoreTiming& core_timing)
: core_timing(core_timing), configs{
{PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION},
{PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION},
} {}
Controller::~Controller() = default;
void Controller::SetPerformanceConfiguration(PerformanceMode mode,
PerformanceConfiguration config) {
static const std::map<PerformanceConfiguration, u32> PCONFIG_TO_SPEED_MAP{
{PerformanceConfiguration::Config1, 1020}, {PerformanceConfiguration::Config2, 1020},
{PerformanceConfiguration::Config3, 1224}, {PerformanceConfiguration::Config4, 1020},
{PerformanceConfiguration::Config5, 1020}, {PerformanceConfiguration::Config6, 1224},
{PerformanceConfiguration::Config7, 1020}, {PerformanceConfiguration::Config8, 1020},
{PerformanceConfiguration::Config9, 1020}, {PerformanceConfiguration::Config10, 1020},
{PerformanceConfiguration::Config11, 1020}, {PerformanceConfiguration::Config12, 1020},
{PerformanceConfiguration::Config13, 1785}, {PerformanceConfiguration::Config14, 1785},
{PerformanceConfiguration::Config15, 1020}, {PerformanceConfiguration::Config16, 1020},
};
SetClockSpeed(PCONFIG_TO_SPEED_MAP.find(config)->second);
configs.insert_or_assign(mode, config);
}
void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
constexpr std::array<PerformanceConfiguration, 3> BOOST_MODE_TO_CONFIG_MAP{{
PerformanceConfiguration::Config7,
PerformanceConfiguration::Config13,
PerformanceConfiguration::Config15,
}};
SetPerformanceConfiguration(PerformanceMode::Docked,
BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode)));
}
PerformanceMode Controller::GetCurrentPerformanceMode() {
return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld;
}
PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
if (configs.find(mode) == configs.end()) {
configs.insert_or_assign(mode, DEFAULT_PERFORMANCE_CONFIGURATION);
}
return configs[mode];
}
void Controller::SetClockSpeed(u32 mhz) {
LOG_INFO(Service_APM, "called, mhz={:08X}", mhz);
// TODO(DarkLordZach): Actually signal core_timing to change clock speed.
}
} // namespace Service::APM

View File

@@ -0,0 +1,70 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <map>
#include "common/common_types.h"
namespace Core::Timing {
class CoreTiming;
}
namespace Service::APM {
enum class PerformanceConfiguration : u32 {
Config1 = 0x00010000,
Config2 = 0x00010001,
Config3 = 0x00010002,
Config4 = 0x00020000,
Config5 = 0x00020001,
Config6 = 0x00020002,
Config7 = 0x00020003,
Config8 = 0x00020004,
Config9 = 0x00020005,
Config10 = 0x00020006,
Config11 = 0x92220007,
Config12 = 0x92220008,
Config13 = 0x92220009,
Config14 = 0x9222000A,
Config15 = 0x9222000B,
Config16 = 0x9222000C,
};
enum class CpuBoostMode : u32 {
Disabled = 0,
Full = 1, // CPU + GPU -> Config 13, 14, 15, or 16
Partial = 2, // GPU Only -> Config 15 or 16
};
enum class PerformanceMode : u8 {
Handheld = 0,
Docked = 1,
};
// Class to manage the state and change of the emulated system performance.
// Specifically, this deals with PerformanceMode, which corresponds to the system being docked or
// undocked, and PerformanceConfig which specifies the exact CPU, GPU, and Memory clocks to operate
// at. Additionally, this manages 'Boost Mode', which allows games to temporarily overclock the
// system during times of high load -- this simply maps to different PerformanceConfigs to use.
class Controller {
public:
Controller(Core::Timing::CoreTiming& core_timing);
~Controller();
void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config);
void SetFromCpuBoostMode(CpuBoostMode mode);
PerformanceMode GetCurrentPerformanceMode();
PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode);
private:
void SetClockSpeed(u32 mhz);
std::map<PerformanceMode, PerformanceConfiguration> configs;
Core::Timing::CoreTiming& core_timing;
};
} // namespace Service::APM

View File

@@ -5,43 +5,32 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/apm/interface.h"
namespace Service::APM {
class ISession final : public ServiceFramework<ISession> {
public:
ISession() : ServiceFramework("ISession") {
ISession(Controller& controller) : ServiceFramework("ISession"), controller(controller) {
static const FunctionInfo functions[] = {
{0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},
{1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"},
{2, nullptr, "SetCpuOverclockEnabled"},
};
RegisterHandlers(functions);
}
private:
enum class PerformanceConfiguration : u32 {
Config1 = 0x00010000,
Config2 = 0x00010001,
Config3 = 0x00010002,
Config4 = 0x00020000,
Config5 = 0x00020001,
Config6 = 0x00020002,
Config7 = 0x00020003,
Config8 = 0x00020004,
Config9 = 0x00020005,
Config10 = 0x00020006,
Config11 = 0x92220007,
Config12 = 0x92220008,
};
void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
u32 config = rp.Pop<u32>();
LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
config);
const auto mode = rp.PopEnum<PerformanceMode>();
const auto config = rp.PopEnum<PerformanceConfiguration>();
LOG_DEBUG(Service_APM, "called mode={} config={}", static_cast<u32>(mode),
static_cast<u32>(config));
controller.SetPerformanceConfiguration(mode, config);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -50,20 +39,23 @@ private:
void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
const auto mode = rp.PopEnum<PerformanceMode>();
LOG_DEBUG(Service_APM, "called mode={}", static_cast<u32>(mode));
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode));
}
Controller& controller;
};
APM::APM(std::shared_ptr<Module> apm, const char* name)
: ServiceFramework(name), apm(std::move(apm)) {
APM::APM(std::shared_ptr<Module> apm, Controller& controller, const char* name)
: ServiceFramework(name), apm(std::move(apm)), controller(controller) {
static const FunctionInfo functions[] = {
{0, &APM::OpenSession, "OpenSession"},
{1, nullptr, "GetPerformanceMode"},
{1, &APM::GetPerformanceMode, "GetPerformanceMode"},
{6, nullptr, "IsCpuOverclockEnabled"},
};
RegisterHandlers(functions);
}
@@ -75,10 +67,17 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISession>();
rb.PushIpcInterface<ISession>(controller);
}
APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_APM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.PushEnum(controller.GetCurrentPerformanceMode());
}
APM_Sys::APM_Sys(Controller& controller) : ServiceFramework{"apm:sys"}, controller(controller) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestPerformanceMode"},
@@ -87,8 +86,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
{3, nullptr, "GetLastThrottlingState"},
{4, nullptr, "ClearLastThrottlingState"},
{5, nullptr, "LoadAndApplySettings"},
{6, nullptr, "SetCpuBoostMode"},
{7, nullptr, "GetCurrentPerformanceConfiguration"},
{6, &APM_Sys::SetCpuBoostMode, "SetCpuBoostMode"},
{7, &APM_Sys::GetCurrentPerformanceConfiguration, "GetCurrentPerformanceConfiguration"},
};
// clang-format on
@@ -102,7 +101,28 @@ void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISession>();
rb.PushIpcInterface<ISession>(controller);
}
void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto mode = rp.PopEnum<CpuBoostMode>();
LOG_DEBUG(Service_APM, "called, mode={:08X}", static_cast<u32>(mode));
controller.SetFromCpuBoostMode(mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void APM_Sys::GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_APM, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.PushEnum(
controller.GetCurrentPerformanceConfiguration(controller.GetCurrentPerformanceMode()));
}
} // namespace Service::APM

View File

@@ -8,24 +8,34 @@
namespace Service::APM {
class Controller;
class Module;
class APM final : public ServiceFramework<APM> {
public:
explicit APM(std::shared_ptr<Module> apm, const char* name);
explicit APM(std::shared_ptr<Module> apm, Controller& controller, const char* name);
~APM() override;
private:
void OpenSession(Kernel::HLERequestContext& ctx);
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
std::shared_ptr<Module> apm;
Controller& controller;
};
class APM_Sys final : public ServiceFramework<APM_Sys> {
public:
explicit APM_Sys();
explicit APM_Sys(Controller& controller);
~APM_Sys() override;
void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
private:
void GetPerformanceEvent(Kernel::HLERequestContext& ctx);
void GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx);
Controller& controller;
};
} // namespace Service::APM

View File

@@ -167,13 +167,12 @@ public:
{3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
{4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
{5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
{6, &IAudioDevice::ListAudioDeviceName,
"ListAudioDeviceNameAuto"}, // TODO(ogniK): Confirm if autos are identical to non auto
{6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
{7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
{8, nullptr, "GetAudioDeviceOutputVolumeAuto"},
{10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
{11, nullptr, "QueryAudioDeviceInputEvent"},
{12, nullptr, "QueryAudioDeviceOutputEvent"},
{12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
{13, nullptr, "GetAudioSystemMasterVolumeSetting"},
};
RegisterHandlers(functions);
@@ -181,6 +180,11 @@ public:
auto& kernel = Core::System::GetInstance().Kernel();
buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
"IAudioOutBufferReleasedEvent");
// Should only be signalled when an audio output device has been changed, example: speaker
// to headset
audio_output_device_switch_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
}
private:
@@ -237,7 +241,16 @@ private:
rb.Push<u32>(1);
}
void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(audio_output_device_switch_event.readable);
}
Kernel::EventPair buffer_event;
Kernel::EventPair audio_output_device_switch_event;
}; // namespace Audio

View File

@@ -472,12 +472,12 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
}
}
void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) {
void InstallInterfaces(Core::System& system) {
romfs_factory = nullptr;
CreateFactories(vfs, false);
std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
std::make_shared<FSP_PR>()->InstallAsService(service_manager);
std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
CreateFactories(*system.GetFilesystem(), false);
std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
std::make_shared<FSP_SRV>(system.GetReporter())->InstallAsService(system.ServiceManager());
}
} // namespace Service::FileSystem

View File

@@ -65,7 +65,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
// above is called.
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs);
void InstallInterfaces(Core::System& system);
// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
// pointers and booleans. This makes using a VfsDirectory with switch services much easier and

View File

@@ -26,6 +26,7 @@
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
#include "core/reporter.h"
namespace Service::FileSystem {
@@ -613,7 +614,7 @@ private:
u64 next_entry_index = 0;
};
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFileSystem"},
@@ -710,14 +711,14 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{1001, nullptr, "SetSaveDataSize"},
{1002, nullptr, "SetSaveDataRootPath"},
{1003, nullptr, "DisableAutoSaveDataCreation"},
{1004, nullptr, "SetGlobalAccessLogMode"},
{1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
{1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
{1006, nullptr, "OutputAccessLogToSdCard"},
{1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
{1007, nullptr, "RegisterUpdatePartition"},
{1008, nullptr, "OpenRegisteredUpdatePartition"},
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1010, nullptr, "SetDataStorageRedirectTarget"},
{1011, nullptr, "OutputAccessLogToSdCard2"},
{1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
{1200, nullptr, "OpenMultiCommitManager"},
@@ -814,21 +815,22 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
}
void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
log_mode = rp.PopEnum<LogMode>();
LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
LOG_DEBUG(Service_FS, "called");
enum class LogMode : u32 {
Off,
Log,
RedirectToSdCard,
LogToSdCard = Log | RedirectToSdCard,
};
// Given we always want to receive logging information,
// we always specify logging as enabled.
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.PushEnum(LogMode::Log);
rb.PushEnum(log_mode);
}
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
@@ -902,4 +904,26 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ct
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
}
void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
const auto raw = ctx.ReadBuffer();
auto log = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(raw.data()), raw.size());
LOG_DEBUG(Service_FS, "called, log='{}'", log);
reporter.SaveFilesystemAccessReport(log_mode, std::move(log));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.PushEnum(AccessLogVersion::Latest);
rb.Push(access_log_program_index);
}
} // namespace Service::FileSystem

View File

@@ -7,15 +7,32 @@
#include <memory>
#include "core/hle/service/service.h"
namespace Core {
class Reporter;
}
namespace FileSys {
class FileSystemBackend;
}
namespace Service::FileSystem {
enum class AccessLogVersion : u32 {
V7_0_0 = 2,
Latest = V7_0_0,
};
enum class LogMode : u32 {
Off,
Log,
RedirectToSdCard,
LogToSdCard = Log | RedirectToSdCard,
};
class FSP_SRV final : public ServiceFramework<FSP_SRV> {
public:
explicit FSP_SRV();
explicit FSP_SRV(const Core::Reporter& reporter);
~FSP_SRV() override;
private:
@@ -26,13 +43,20 @@ private:
void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx);
void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
FileSys::VirtualFile romfs;
u64 current_process_id = 0;
u32 access_log_program_index = 0;
LogMode log_mode = LogMode::LogToSdCard;
const Core::Reporter& reporter;
};
} // namespace Service::FileSystem

View File

@@ -0,0 +1,12 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::Friend {
constexpr ResultCode ERR_NO_NOTIFICATIONS{ErrorModule::Account, 15};
}

View File

@@ -2,8 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <queue>
#include "common/logging/log.h"
#include "common/uuid.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/friend/errors.h"
#include "core/hle/service/friend/friend.h"
#include "core/hle/service/friend/interface.h"
@@ -17,7 +22,7 @@ public:
{0, nullptr, "GetCompletionEvent"},
{1, nullptr, "Cancel"},
{10100, nullptr, "GetFriendListIds"},
{10101, nullptr, "GetFriendList"},
{10101, &IFriendService::GetFriendList, "GetFriendList"},
{10102, nullptr, "UpdateFriendInfo"},
{10110, nullptr, "GetFriendProfileImage"},
{10200, nullptr, "SendFriendRequestForApplication"},
@@ -94,6 +99,23 @@ public:
}
private:
enum class PresenceFilter : u32 {
None = 0,
Online = 1,
OnlinePlay = 2,
OnlineOrOnlinePlay = 3,
};
struct SizedFriendFilter {
PresenceFilter presence;
u8 is_favorite;
u8 same_app;
u8 same_app_played;
u8 arbitary_app_played;
u64 group_id;
};
static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");
void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
// Stub used by Splatoon 2
LOG_WARNING(Service_ACC, "(STUBBED) called");
@@ -107,6 +129,121 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void GetFriendList(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto friend_offset = rp.Pop<u32>();
const auto uuid = rp.PopRaw<Common::UUID>();
[[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
const auto pid = rp.Pop<u64>();
LOG_WARNING(Service_ACC, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
uuid.Format(), pid);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // Friend count
// TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
}
};
class INotificationService final : public ServiceFramework<INotificationService> {
public:
INotificationService(Common::UUID uuid) : ServiceFramework("INotificationService"), uuid(uuid) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &INotificationService::GetEvent, "GetEvent"},
{1, &INotificationService::Clear, "Clear"},
{2, &INotificationService::Pop, "Pop"}
};
// clang-format on
RegisterHandlers(functions);
}
private:
void GetEvent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
if (!is_event_created) {
auto& kernel = Core::System::GetInstance().Kernel();
notification_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent");
is_event_created = true;
}
rb.PushCopyObjects(notification_event.readable);
}
void Clear(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
while (!notifications.empty()) {
notifications.pop();
}
std::memset(&states, 0, sizeof(States));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Pop(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
if (notifications.empty()) {
LOG_ERROR(Service_ACC, "No notifications in queue!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_NOTIFICATIONS);
return;
}
const auto notification = notifications.front();
notifications.pop();
switch (notification.notification_type) {
case NotificationTypes::HasUpdatedFriendsList:
states.has_updated_friends = false;
break;
case NotificationTypes::HasReceivedFriendRequest:
states.has_received_friend_request = false;
break;
default:
// HOS seems not have an error case for an unknown notification
LOG_WARNING(Service_ACC, "Unknown notification {:08X}",
static_cast<u32>(notification.notification_type));
break;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<SizedNotificationInfo>(notification);
}
enum class NotificationTypes : u32 {
HasUpdatedFriendsList = 0x65,
HasReceivedFriendRequest = 0x1
};
struct SizedNotificationInfo {
NotificationTypes notification_type;
INSERT_PADDING_WORDS(
1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now
u64_le account_id;
};
static_assert(sizeof(SizedNotificationInfo) == 0x10,
"SizedNotificationInfo is an incorrect size");
struct States {
bool has_updated_friends;
bool has_received_friend_request;
};
Common::UUID uuid;
bool is_event_created = false;
Kernel::EventPair notification_event;
std::queue<SizedNotificationInfo> notifications;
States states{};
};
void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
@@ -116,6 +253,17 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
}
void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto uuid = rp.PopRaw<Common::UUID>();
LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<INotificationService>(uuid);
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {}

View File

@@ -16,6 +16,7 @@ public:
~Interface() override;
void CreateFriendService(Kernel::HLERequestContext& ctx);
void CreateNotificationService(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;

View File

@@ -10,7 +10,7 @@ Friend::Friend(std::shared_ptr<Module> module, const char* name)
: Interface(std::move(module), name) {
static const FunctionInfo functions[] = {
{0, &Friend::CreateFriendService, "CreateFriendService"},
{1, nullptr, "CreateNotificationService"},
{1, &Friend::CreateNotificationService, "CreateNotificationService"},
{2, nullptr, "CreateDaemonSuspendSessionService"},
};
RegisterHandlers(functions);

View File

@@ -548,6 +548,37 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) {
connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
}
void Controller_NPad::StartLRAssignmentMode() {
// Nothing internally is used for lr assignment mode. Since we have the ability to set the
// controller types from boot, it doesn't really matter about showing a selection screen
is_in_lr_assignment_mode = true;
}
void Controller_NPad::StopLRAssignmentMode() {
is_in_lr_assignment_mode = false;
}
bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN ||
npad_id_2 == NPAD_UNKNOWN) {
return true;
}
const auto npad_index_1 = NPadIdToIndex(npad_id_1);
const auto npad_index_2 = NPadIdToIndex(npad_id_2);
if (!IsControllerSupported(connected_controllers[npad_index_1].type) ||
!IsControllerSupported(connected_controllers[npad_index_2].type)) {
return false;
}
std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
InitNewlyAddedControler(npad_index_1);
InitNewlyAddedControler(npad_index_2);
return true;
}
bool Controller_NPad::IsControllerSupported(NPadControllerType controller) {
if (controller == NPadControllerType::Handheld) {
// Handheld is not even a supported type, lets stop here

View File

@@ -124,6 +124,10 @@ public:
void ConnectAllDisconnectedControllers();
void ClearAllControllers();
void StartLRAssignmentMode();
void StopLRAssignmentMode();
bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2);
// Logical OR for all buttons presses on all controllers
// Specifically for cheat engine and other features.
u32 GetAndResetPressState();
@@ -321,5 +325,6 @@ private:
void RequestPadStateUpdate(u32 npad_id);
std::array<ControllerPad, 10> npad_pad_states{};
bool IsControllerSupported(NPadControllerType controller);
bool is_in_lr_assignment_mode{false};
};
} // namespace Service::HID

View File

@@ -0,0 +1,13 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::HID {
constexpr ResultCode ERR_NPAD_NOT_CONNECTED{ErrorModule::HID, 710};
} // namespace Service::HID

View File

@@ -16,6 +16,7 @@
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/xcd.h"
@@ -202,11 +203,11 @@ Hid::Hid() : ServiceFramework("hid") {
{123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
{124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
{125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
{126, nullptr, "StartLrAssignmentMode"},
{127, nullptr, "StopLrAssignmentMode"},
{126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"},
{127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"},
{128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
{129, nullptr, "GetNpadHandheldActivationMode"},
{130, nullptr, "SwapNpadAssignment"},
{130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
{131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
{132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
@@ -733,6 +734,49 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
controller.StartLRAssignmentMode();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
controller.StopLRAssignmentMode();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_1{rp.Pop<u32>()};
const auto npad_2{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}",
applet_resource_user_id, npad_1, npad_2);
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
IPC::ResponseBuilder rb{ctx, 2};
if (controller.SwapNpadAssignment(npad_1, npad_2)) {
rb.Push(RESULT_SUCCESS);
} else {
LOG_ERROR(Service_HID, "Npads are not connected!");
rb.Push(ERR_NPAD_NOT_CONNECTED);
}
}
class HidDbg final : public ServiceFramework<HidDbg> {
public:
explicit HidDbg() : ServiceFramework{"hid:dbg"} {

View File

@@ -119,6 +119,9 @@ private:
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
void StartLrAssignmentMode(Kernel::HLERequestContext& ctx);
void StopLrAssignmentMode(Kernel::HLERequestContext& ctx);
void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
std::shared_ptr<IAppletResource> applet_resource;
};

View File

@@ -48,7 +48,7 @@ public:
{19, nullptr, "Export"},
{20, nullptr, "IsBrokenDatabaseWithClearFlag"},
{21, &IDatabaseService::GetIndex, "GetIndex"},
{22, nullptr, "SetInterfaceVersion"},
{22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
{23, nullptr, "Convert"},
};
// clang-format on
@@ -350,8 +350,22 @@ private:
rb.Push(index);
}
void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
current_interface_version = rp.PopRaw<u32>();
LOG_DEBUG(Service_Mii, "called, interface_version={:08X}", current_interface_version);
UNIMPLEMENTED_IF(current_interface_version != 1);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
MiiManager db;
u32 current_interface_version = 0;
// Last read offsets of Get functions
std::array<u32, 4> offsets{};
};

View File

@@ -3,11 +3,44 @@
// Refer to the license.txt file included.
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/service.h"
namespace Service::PM {
namespace {
constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1};
constexpr u64 NO_PROCESS_FOUND_PID{0};
std::optional<Kernel::SharedPtr<Kernel::Process>> SearchProcessList(
const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list,
std::function<bool(const Kernel::SharedPtr<Kernel::Process>&)> predicate) {
const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);
if (iter == process_list.end()) {
return std::nullopt;
}
return *iter;
}
void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list) {
const auto process = SearchProcessList(process_list, [](const auto& process) {
return process->GetProcessID() == Kernel::Process::ProcessIDMin;
});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(process.has_value() ? (*process)->GetProcessID() : NO_PROCESS_FOUND_PID);
}
} // Anonymous namespace
class BootMode final : public ServiceFramework<BootMode> {
public:
explicit BootMode() : ServiceFramework{"pm:bm"} {
@@ -41,14 +74,15 @@ private:
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
public:
explicit DebugMonitor() : ServiceFramework{"pm:dmnt"} {
explicit DebugMonitor(const Kernel::KernelCore& kernel)
: ServiceFramework{"pm:dmnt"}, kernel(kernel) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetDebugProcesses"},
{1, nullptr, "StartDebugProcess"},
{2, nullptr, "GetTitlePid"},
{2, &DebugMonitor::GetTitlePid, "GetTitlePid"},
{3, nullptr, "EnableDebugForTitleId"},
{4, nullptr, "GetApplicationPid"},
{4, &DebugMonitor::GetApplicationPid, "GetApplicationPid"},
{5, nullptr, "EnableDebugForApplication"},
{6, nullptr, "DisableDebug"},
};
@@ -56,21 +90,77 @@ public:
RegisterHandlers(functions);
}
private:
void GetTitlePid(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id);
const auto process =
SearchProcessList(kernel.GetProcessList(), [title_id](const auto& process) {
return process->GetTitleID() == title_id;
});
if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_PROCESS_NOT_FOUND);
return;
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push((*process)->GetProcessID());
}
void GetApplicationPid(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called");
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
}
const Kernel::KernelCore& kernel;
};
class Info final : public ServiceFramework<Info> {
public:
explicit Info() : ServiceFramework{"pm:info"} {
explicit Info(const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list)
: ServiceFramework{"pm:info"}, process_list(process_list) {
static const FunctionInfo functions[] = {
{0, nullptr, "GetTitleId"},
{0, &Info::GetTitleId, "GetTitleId"},
};
RegisterHandlers(functions);
}
private:
void GetTitleId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
const auto process = SearchProcessList(process_list, [process_id](const auto& process) {
return process->GetProcessID() == process_id;
});
if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_PROCESS_NOT_FOUND);
return;
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push((*process)->GetTitleID());
}
const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list;
};
class Shell final : public ServiceFramework<Shell> {
public:
explicit Shell() : ServiceFramework{"pm:shell"} {
explicit Shell(const Kernel::KernelCore& kernel)
: ServiceFramework{"pm:shell"}, kernel(kernel) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "LaunchProcess"},
@@ -79,21 +169,31 @@ public:
{3, nullptr, "GetProcessEventWaiter"},
{4, nullptr, "GetProcessEventType"},
{5, nullptr, "NotifyBootFinished"},
{6, nullptr, "GetApplicationPid"},
{6, &Shell::GetApplicationPid, "GetApplicationPid"},
{7, nullptr, "BoostSystemMemoryResourceLimit"},
{8, nullptr, "EnableAdditionalSystemThreads"},
{9, nullptr, "GetUnimplementedEventHandle"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void GetApplicationPid(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called");
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
}
const Kernel::KernelCore& kernel;
};
void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<BootMode>()->InstallAsService(sm);
std::make_shared<DebugMonitor>()->InstallAsService(sm);
std::make_shared<Info>()->InstallAsService(sm);
std::make_shared<Shell>()->InstallAsService(sm);
void InstallInterfaces(Core::System& system) {
std::make_shared<BootMode>()->InstallAsService(system.ServiceManager());
std::make_shared<DebugMonitor>(system.Kernel())->InstallAsService(system.ServiceManager());
std::make_shared<Info>(system.Kernel().GetProcessList())
->InstallAsService(system.ServiceManager());
std::make_shared<Shell>(system.Kernel())->InstallAsService(system.ServiceManager());
}
} // namespace Service::PM

View File

@@ -4,8 +4,8 @@
#pragma once
namespace Service::SM {
class ServiceManager;
namespace Core {
class System;
}
namespace Service::PM {
@@ -16,6 +16,6 @@ enum class SystemBootMode {
};
/// Registers all PM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(Core::System& system);
} // namespace Service::PM

View File

@@ -195,8 +195,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
// Module interface
/// Initialize ServiceManager
void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
FileSys::VfsFilesystem& vfs) {
void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
// here and pass it into the respective InstallInterfaces functions.
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
@@ -206,7 +205,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
Account::InstallInterfaces(system);
AM::InstallInterfaces(*sm, nv_flinger, system);
AOC::InstallInterfaces(*sm);
APM::InstallInterfaces(*sm);
APM::InstallInterfaces(system);
Audio::InstallInterfaces(*sm);
BCAT::InstallInterfaces(*sm);
BPC::InstallInterfaces(*sm);
@@ -218,7 +217,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
EUPLD::InstallInterfaces(*sm);
Fatal::InstallInterfaces(*sm);
FGM::InstallInterfaces(*sm);
FileSystem::InstallInterfaces(*sm, vfs);
FileSystem::InstallInterfaces(system);
Friend::InstallInterfaces(*sm);
Glue::InstallInterfaces(system);
GRC::InstallInterfaces(*sm);
@@ -242,14 +241,14 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
PCTL::InstallInterfaces(*sm);
PCV::InstallInterfaces(*sm);
PlayReport::InstallInterfaces(*sm);
PM::InstallInterfaces(*sm);
PM::InstallInterfaces(system);
PSC::InstallInterfaces(*sm);
PSM::InstallInterfaces(*sm);
Set::InstallInterfaces(*sm);
Sockets::InstallInterfaces(*sm);
SPL::InstallInterfaces(*sm);
SSL::InstallInterfaces(*sm);
Time::InstallInterfaces(*sm);
Time::InstallInterfaces(system);
USB::InstallInterfaces(*sm);
VI::InstallInterfaces(*sm, nv_flinger);
WLAN::InstallInterfaces(*sm);

View File

@@ -182,8 +182,7 @@ private:
};
/// Initialize ServiceManager
void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
FileSys::VfsFilesystem& vfs);
void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
/// Shutdown ServiceManager
void Shutdown();

View File

@@ -95,6 +95,14 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
}
void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(Settings::values.quest_flag));
}
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
@@ -114,7 +122,7 @@ SET::SET() : ServiceFramework("set") {
{5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
{6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"},
{7, nullptr, "GetKeyCodeMap"},
{8, nullptr, "GetQuestFlag"},
{8, &SET::GetQuestFlag, "GetQuestFlag"},
{9, nullptr, "GetKeyCodeMap2"},
};
// clang-format on

View File

@@ -42,6 +42,7 @@ private:
void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
void GetQuestFlag(Kernel::HLERequestContext& ctx);
};
} // namespace Service::Set

View File

@@ -6,8 +6,9 @@
namespace Service::Time {
Time::Time(std::shared_ptr<Module> time, const char* name)
: Module::Interface(std::move(time), name) {
Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
const char* name)
: Module::Interface(std::move(time), std::move(shared_memory), name) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
@@ -16,12 +17,12 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
{3, &Time::GetTimeZoneService, "GetTimeZoneService"},
{4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
{5, nullptr, "GetEphemeralNetworkSystemClock"},
{20, nullptr, "GetSharedMemoryNativeHandle"},
{20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
{30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"},
{31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
{100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
{101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
{100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
{101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
{201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},

View File

@@ -8,9 +8,12 @@
namespace Service::Time {
class SharedMemory;
class Time final : public Module::Interface {
public:
explicit Time(std::shared_ptr<Module> time, const char* name);
explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
const char* name);
~Time() override;
};

View File

@@ -13,6 +13,7 @@
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/time/interface.h"
#include "core/hle/service/time/time.h"
#include "core/hle/service/time/time_sharedmemory.h"
#include "core/settings.h"
namespace Service::Time {
@@ -61,9 +62,18 @@ static u64 CalendarToPosix(const CalendarTime& calendar_time,
return static_cast<u64>(epoch_time);
}
enum class ClockContextType {
StandardSteady,
StandardUserSystem,
StandardNetworkSystem,
StandardLocalSystem,
};
class ISystemClock final : public ServiceFramework<ISystemClock> {
public:
ISystemClock() : ServiceFramework("ISystemClock") {
ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory,
ClockContextType clock_type)
: ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) {
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
{1, nullptr, "SetCurrentTime"},
@@ -72,6 +82,8 @@ public:
};
RegisterHandlers(functions);
UpdateSharedMemoryContext(system_clock_context);
}
private:
@@ -87,34 +99,63 @@ private:
void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Time, "(STUBBED) called");
SystemClockContext system_clock_ontext{};
// TODO(ogniK): This should be updated periodically however since we have it stubbed we'll
// only update when we get a new context
UpdateSharedMemoryContext(system_clock_context);
IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(system_clock_ontext);
rb.PushRaw(system_clock_context);
}
void UpdateSharedMemoryContext(const SystemClockContext& clock_context) {
switch (clock_type) {
case ClockContextType::StandardLocalSystem:
shared_memory->SetStandardLocalSystemClockContext(clock_context);
break;
case ClockContextType::StandardNetworkSystem:
shared_memory->SetStandardNetworkSystemClockContext(clock_context);
break;
}
}
SystemClockContext system_clock_context{};
std::shared_ptr<Service::Time::SharedMemory> shared_memory;
ClockContextType clock_type;
};
class ISteadyClock final : public ServiceFramework<ISteadyClock> {
public:
ISteadyClock() : ServiceFramework("ISteadyClock") {
ISteadyClock(std::shared_ptr<SharedMemory> shared_memory)
: ServiceFramework("ISteadyClock"), shared_memory(shared_memory) {
static const FunctionInfo functions[] = {
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
};
RegisterHandlers(functions);
shared_memory->SetStandardSteadyClockTimepoint(GetCurrentTimePoint());
}
private:
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
const auto& core_timing = Core::System::GetInstance().CoreTiming();
const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000),
{}};
const auto time_point = GetCurrentTimePoint();
// TODO(ogniK): This should be updated periodically
shared_memory->SetStandardSteadyClockTimepoint(time_point);
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(steady_clock_time_point);
rb.PushRaw(time_point);
}
SteadyClockTimePoint GetCurrentTimePoint() const {
const auto& core_timing = Core::System::GetInstance().CoreTiming();
const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
return {static_cast<u64_le>(ms.count() / 1000), {}};
}
std::shared_ptr<SharedMemory> shared_memory;
};
class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
@@ -233,7 +274,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>();
rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardUserSystem);
}
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
@@ -241,7 +282,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>();
rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardNetworkSystem);
}
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
@@ -249,7 +290,7 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISteadyClock>();
rb.PushIpcInterface<ISteadyClock>(shared_memory);
}
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
@@ -265,7 +306,7 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>();
rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardLocalSystem);
}
void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
@@ -333,16 +374,52 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
rb.PushRaw<u64>(difference);
}
Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
: ServiceFramework(name), time(std::move(time)) {}
void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(shared_memory->GetSharedMemoryHolder());
}
void Module::Interface::IsStandardUserSystemClockAutomaticCorrectionEnabled(
Kernel::HLERequestContext& ctx) {
// ogniK(TODO): When clock contexts are implemented, the value should be read from the context
// instead of our shared memory holder
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(shared_memory->GetStandardUserSystemClockAutomaticCorrectionEnabled());
}
void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled(
Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto enabled = rp.Pop<u8>();
LOG_WARNING(Service_Time, "(PARTIAL IMPLEMENTATION) called");
// TODO(ogniK): Update clock contexts and correct timespans
shared_memory->SetStandardUserSystemClockAutomaticCorrectionEnabled(enabled > 0);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
Module::Interface::Interface(std::shared_ptr<Module> time,
std::shared_ptr<SharedMemory> shared_memory, const char* name)
: ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)) {}
Module::Interface::~Interface() = default;
void InstallInterfaces(SM::ServiceManager& service_manager) {
void InstallInterfaces(Core::System& system) {
auto time = std::make_shared<Module>();
std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager);
std::make_shared<Time>(time, "time:s")->InstallAsService(service_manager);
std::make_shared<Time>(time, "time:u")->InstallAsService(service_manager);
auto shared_mem = std::make_shared<SharedMemory>(system);
std::make_shared<Time>(time, shared_mem, "time:a")->InstallAsService(system.ServiceManager());
std::make_shared<Time>(time, shared_mem, "time:s")->InstallAsService(system.ServiceManager());
std::make_shared<Time>(std::move(time), shared_mem, "time:u")
->InstallAsService(system.ServiceManager());
}
} // namespace Service::Time

View File

@@ -10,6 +10,8 @@
namespace Service::Time {
class SharedMemory;
struct LocationName {
std::array<u8, 0x24> name;
};
@@ -77,7 +79,8 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> time, const char* name);
explicit Interface(std::shared_ptr<Module> time,
std::shared_ptr<SharedMemory> shared_memory, const char* name);
~Interface() override;
void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
@@ -87,13 +90,17 @@ public:
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
void GetClockSnapshot(Kernel::HLERequestContext& ctx);
void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
void IsStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);
void SetStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> time;
std::shared_ptr<SharedMemory> shared_memory;
};
};
/// Registers all Time services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(Core::System& system);
} // namespace Service::Time

View File

@@ -0,0 +1,68 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/core.h"
#include "core/hle/service/time/time_sharedmemory.h"
namespace Service::Time {
const std::size_t SHARED_MEMORY_SIZE = 0x1000;
SharedMemory::SharedMemory(Core::System& system) : system(system) {
shared_memory_holder = Kernel::SharedMemory::Create(
system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory");
// Seems static from 1.0.0 -> 8.1.0. Specific games seem to check this value and crash
// if it's set to anything else
shared_memory_format.format_version = 14;
std::memcpy(shared_memory_holder->GetPointer(), &shared_memory_format, sizeof(Format));
}
SharedMemory::~SharedMemory() = default;
Kernel::SharedPtr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() const {
return shared_memory_holder;
}
void SharedMemory::SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint) {
shared_memory_format.standard_steady_clock_timepoint.StoreData(
shared_memory_holder->GetPointer(), timepoint);
}
void SharedMemory::SetStandardLocalSystemClockContext(const SystemClockContext& context) {
shared_memory_format.standard_local_system_clock_context.StoreData(
shared_memory_holder->GetPointer(), context);
}
void SharedMemory::SetStandardNetworkSystemClockContext(const SystemClockContext& context) {
shared_memory_format.standard_network_system_clock_context.StoreData(
shared_memory_holder->GetPointer(), context);
}
void SharedMemory::SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled) {
shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
shared_memory_holder->GetPointer(), enabled);
}
SteadyClockTimePoint SharedMemory::GetStandardSteadyClockTimepoint() {
return shared_memory_format.standard_steady_clock_timepoint.ReadData(
shared_memory_holder->GetPointer());
}
SystemClockContext SharedMemory::GetStandardLocalSystemClockContext() {
return shared_memory_format.standard_local_system_clock_context.ReadData(
shared_memory_holder->GetPointer());
}
SystemClockContext SharedMemory::GetStandardNetworkSystemClockContext() {
return shared_memory_format.standard_network_system_clock_context.ReadData(
shared_memory_holder->GetPointer());
}
bool SharedMemory::GetStandardUserSystemClockAutomaticCorrectionEnabled() {
return shared_memory_format.standard_user_system_clock_automatic_correction.ReadData(
shared_memory_holder->GetPointer());
}
} // namespace Service::Time

View File

@@ -0,0 +1,74 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/time/time.h"
namespace Service::Time {
class SharedMemory {
public:
explicit SharedMemory(Core::System& system);
~SharedMemory();
// Return the shared memory handle
Kernel::SharedPtr<Kernel::SharedMemory> GetSharedMemoryHolder() const;
// Set memory barriers in shared memory and update them
void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint);
void SetStandardLocalSystemClockContext(const SystemClockContext& context);
void SetStandardNetworkSystemClockContext(const SystemClockContext& context);
void SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled);
// Pull from memory barriers in the shared memory
SteadyClockTimePoint GetStandardSteadyClockTimepoint();
SystemClockContext GetStandardLocalSystemClockContext();
SystemClockContext GetStandardNetworkSystemClockContext();
bool GetStandardUserSystemClockAutomaticCorrectionEnabled();
// TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
template <typename T, std::size_t Offset>
struct MemoryBarrier {
static_assert(std::is_trivially_constructible_v<T>, "T must be trivially constructable");
u32_le read_attempt{};
std::array<T, 2> data{};
// These are not actually memory barriers at the moment as we don't have multicore and all
// HLE is mutexed. This will need to properly be implemented when we start updating the time
// points on threads. As of right now, we'll be updated both values synchronously and just
// incrementing the read_attempt to indicate that we waited.
void StoreData(u8* shared_memory, T data_to_store) {
std::memcpy(this, shared_memory + Offset, sizeof(*this));
read_attempt++;
data[read_attempt & 1] = data_to_store;
std::memcpy(shared_memory + Offset, this, sizeof(*this));
}
// For reading we're just going to read the last stored value. If there was no value stored
// it will just end up reading an empty value as intended.
T ReadData(u8* shared_memory) {
std::memcpy(this, shared_memory + Offset, sizeof(*this));
return data[(read_attempt - 1) & 1];
}
};
// Shared memory format
struct Format {
MemoryBarrier<SteadyClockTimePoint, 0x0> standard_steady_clock_timepoint;
MemoryBarrier<SystemClockContext, 0x38> standard_local_system_clock_context;
MemoryBarrier<SystemClockContext, 0x80> standard_network_system_clock_context;
MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction;
u32_le format_version;
};
static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
private:
Kernel::SharedPtr<Kernel::SharedMemory> shared_memory_holder{};
Core::System& system;
Format shared_memory_format{};
};
} // namespace Service::Time

View File

@@ -168,7 +168,8 @@ ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {
}
ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) {
const auto nca = nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Manual);
const auto nca =
nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::HtmlDocument);
if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr)
return ResultStatus::ErrorNoRomFS;
file = nca->GetRomFS();

View File

@@ -134,7 +134,7 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) {
const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
FileSys::ContentRecordType::Manual);
FileSys::ContentRecordType::HtmlDocument);
if (xci->GetStatus() != ResultStatus::Success || nca == nullptr)
return ResultStatus::ErrorXCIMissingPartition;
file = nca->GetRomFS();

View File

@@ -16,11 +16,9 @@
#include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/hle/lock.h"
#include "core/memory.h"
#include "core/memory_setup.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
namespace Memory {

View File

@@ -8,10 +8,6 @@
#include <string>
#include "common/common_types.h"
namespace Common {
struct PageTable;
}
namespace Kernel {
class Process;
}

View File

@@ -2,8 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <ctime>
#include <fstream>
#include <fmt/format.h>
#include <fmt/time.h>
#include <json.hpp>
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/scm_rev.h"
@@ -14,7 +19,6 @@
#include "core/hle/result.h"
#include "core/reporter.h"
#include "core/settings.h"
#include "fmt/time.h"
namespace {
@@ -30,9 +34,11 @@ std::string GetTimestamp() {
using namespace nlohmann;
void SaveToFile(const json& json, const std::string& filename) {
if (!FileUtil::CreateFullPath(filename))
void SaveToFile(json json, const std::string& filename) {
if (!FileUtil::CreateFullPath(filename)) {
LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename);
return;
}
std::ofstream file(
FileUtil::SanitizePath(filename, FileUtil::DirectorySeparator::PlatformDefault));
@@ -61,8 +67,11 @@ json GetReportCommonData(u64 title_id, ResultCode result, const std::string& tim
{"result_description", fmt::format("{:08X}", result.description.Value())},
{"timestamp", timestamp},
};
if (user_id.has_value())
if (user_id.has_value()) {
out["user_id"] = fmt::format("{:016X}{:016X}", (*user_id)[1], (*user_id)[0]);
}
return out;
}
@@ -171,14 +180,14 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx) {
out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC());
out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX());
return std::move(out);
return out;
}
} // Anonymous namespace
namespace Core {
Reporter::Reporter(Core::System& system) : system(system) {}
Reporter::Reporter(System& system) : system(system) {}
Reporter::~Reporter() = default;
@@ -187,8 +196,9 @@ void Reporter::SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u
const std::array<u64, 31>& registers,
const std::array<u64, 32>& backtrace, u32 backtrace_size,
const std::string& arch, u32 unk10) const {
if (!IsReportingEnabled())
if (!IsReportingEnabled()) {
return;
}
const auto timestamp = GetTimestamp();
json out;
@@ -212,8 +222,9 @@ void Reporter::SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u
void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2,
std::optional<std::vector<u8>> resolved_buffer) const {
if (!IsReportingEnabled())
if (!IsReportingEnabled()) {
return;
}
const auto timestamp = GetTimestamp();
const auto title_id = system.CurrentProcess()->GetTitleID();
@@ -238,8 +249,9 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64
void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id,
const std::string& name,
const std::string& service_name) const {
if (!IsReportingEnabled())
if (!IsReportingEnabled()) {
return;
}
const auto timestamp = GetTimestamp();
const auto title_id = system.CurrentProcess()->GetTitleID();
@@ -259,8 +271,9 @@ void Reporter::SaveUnimplementedAppletReport(
u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color,
bool startup_sound, u64 system_tick, std::vector<std::vector<u8>> normal_channel,
std::vector<std::vector<u8>> interactive_channel) const {
if (!IsReportingEnabled())
if (!IsReportingEnabled()) {
return;
}
const auto timestamp = GetTimestamp();
const auto title_id = system.CurrentProcess()->GetTitleID();
@@ -293,8 +306,9 @@ void Reporter::SaveUnimplementedAppletReport(
void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector<std::vector<u8>> data,
std::optional<u128> user_id) const {
if (!IsReportingEnabled())
if (!IsReportingEnabled()) {
return;
}
const auto timestamp = GetTimestamp();
json out;
@@ -316,8 +330,9 @@ void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector<std::vec
void Reporter::SaveErrorReport(u64 title_id, ResultCode result,
std::optional<std::string> custom_text_main,
std::optional<std::string> custom_text_detail) const {
if (!IsReportingEnabled())
if (!IsReportingEnabled()) {
return;
}
const auto timestamp = GetTimestamp();
json out;
@@ -335,10 +350,29 @@ void Reporter::SaveErrorReport(u64 title_id, ResultCode result,
SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp));
}
void Reporter::SaveUserReport() const {
void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
std::string log_message) const {
if (!IsReportingEnabled())
return;
const auto timestamp = GetTimestamp();
const auto title_id = system.CurrentProcess()->GetTitleID();
json out;
out["yuzu_version"] = GetYuzuVersionData();
out["report_common"] = GetReportCommonData(title_id, RESULT_SUCCESS, timestamp);
out["log_mode"] = fmt::format("{:08X}", static_cast<u32>(log_mode));
out["log_message"] = std::move(log_message);
SaveToFile(std::move(out), GetPath("filesystem_access_report", title_id, timestamp));
}
void Reporter::SaveUserReport() const {
if (!IsReportingEnabled()) {
return;
}
const auto timestamp = GetTimestamp();
const auto title_id = system.CurrentProcess()->GetTitleID();

View File

@@ -4,7 +4,9 @@
#pragma once
#include <array>
#include <optional>
#include <string>
#include <vector>
#include "common/common_types.h"
@@ -14,11 +16,17 @@ namespace Kernel {
class HLERequestContext;
} // namespace Kernel
namespace Service::FileSystem {
enum class LogMode : u32;
}
namespace Core {
class System;
class Reporter {
public:
explicit Reporter(Core::System& system);
explicit Reporter(System& system);
~Reporter();
void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp,
@@ -45,12 +53,15 @@ public:
std::optional<std::string> custom_text_main = {},
std::optional<std::string> custom_text_detail = {}) const;
void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
std::string log_message) const;
void SaveUserReport() const;
private:
bool IsReportingEnabled() const;
Core::System& system;
System& system;
};
} // namespace Core

View File

@@ -85,7 +85,6 @@ void LogSettings() {
LogSetting("System_RngSeed", Settings::values.rng_seed.value_or(0));
LogSetting("System_CurrentUser", Settings::values.current_user);
LogSetting("System_LanguageIndex", Settings::values.language_index);
LogSetting("Core_UseCpuJit", Settings::values.use_cpu_jit);
LogSetting("Core_UseMultiCore", Settings::values.use_multi_core);
LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor);
LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit);

View File

@@ -378,7 +378,6 @@ struct Values {
std::atomic_bool is_device_reload_pending{true};
// Core
bool use_cpu_jit;
bool use_multi_core;
// Data Storage
@@ -416,6 +415,7 @@ struct Values {
bool dump_exefs;
bool dump_nso;
bool reporting_services;
bool quest_flag;
// WebService
bool enable_telemetry;

View File

@@ -168,7 +168,6 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id);
AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching",
Settings::values.enable_audio_stretching);
AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit);
AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore",
Settings::values.use_multi_core);
AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor",

View File

@@ -99,24 +99,24 @@ TEST_CASE("CoreTiming[Threadsave]", "[core]") {
core_timing.Advance();
// D -> B -> C -> A -> E
core_timing.ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]);
// Manually force since ScheduleEventThreadsafe doesn't call it
core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
// Manually force since ScheduleEvent doesn't call it
core_timing.ForceExceptionCheck(1000);
REQUIRE(1000 == core_timing.GetDowncount());
core_timing.ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]);
// Manually force since ScheduleEventThreadsafe doesn't call it
core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]);
// Manually force since ScheduleEvent doesn't call it
core_timing.ForceExceptionCheck(500);
REQUIRE(500 == core_timing.GetDowncount());
core_timing.ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]);
// Manually force since ScheduleEventThreadsafe doesn't call it
core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]);
// Manually force since ScheduleEvent doesn't call it
core_timing.ForceExceptionCheck(800);
REQUIRE(500 == core_timing.GetDowncount());
core_timing.ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]);
// Manually force since ScheduleEventThreadsafe doesn't call it
core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]);
// Manually force since ScheduleEvent doesn't call it
core_timing.ForceExceptionCheck(100);
REQUIRE(100 == core_timing.GetDowncount());
core_timing.ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]);
// Manually force since ScheduleEventThreadsafe doesn't call it
core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]);
// Manually force since ScheduleEvent doesn't call it
core_timing.ForceExceptionCheck(1200);
REQUIRE(100 == core_timing.GetDowncount());

View File

@@ -41,12 +41,12 @@ add_library(video_core STATIC
renderer_opengl/gl_buffer_cache.h
renderer_opengl/gl_device.cpp
renderer_opengl/gl_device.h
renderer_opengl/gl_framebuffer_cache.cpp
renderer_opengl/gl_framebuffer_cache.h
renderer_opengl/gl_global_cache.cpp
renderer_opengl/gl_global_cache.h
renderer_opengl/gl_rasterizer.cpp
renderer_opengl/gl_rasterizer.h
renderer_opengl/gl_rasterizer_cache.cpp
renderer_opengl/gl_rasterizer_cache.h
renderer_opengl/gl_resource_manager.cpp
renderer_opengl/gl_resource_manager.h
renderer_opengl/gl_sampler_cache.cpp
@@ -67,6 +67,8 @@ add_library(video_core STATIC
renderer_opengl/gl_state.h
renderer_opengl/gl_stream_buffer.cpp
renderer_opengl/gl_stream_buffer.h
renderer_opengl/gl_texture_cache.cpp
renderer_opengl/gl_texture_cache.h
renderer_opengl/maxwell_to_gl.h
renderer_opengl/renderer_opengl.cpp
renderer_opengl/renderer_opengl.h
@@ -88,6 +90,7 @@ add_library(video_core STATIC
shader/decode/conversion.cpp
shader/decode/memory.cpp
shader/decode/texture.cpp
shader/decode/image.cpp
shader/decode/float_set_predicate.cpp
shader/decode/integer_set_predicate.cpp
shader/decode/half_set_predicate.cpp
@@ -109,6 +112,13 @@ add_library(video_core STATIC
shader/track.cpp
surface.cpp
surface.h
texture_cache/surface_base.cpp
texture_cache/surface_base.h
texture_cache/surface_params.cpp
texture_cache/surface_params.h
texture_cache/surface_view.cpp
texture_cache/surface_view.h
texture_cache/texture_cache.h
textures/astc.cpp
textures/astc.h
textures/convert.cpp
@@ -116,8 +126,6 @@ add_library(video_core STATIC
textures/decoders.cpp
textures/decoders.h
textures/texture.h
texture_cache.cpp
texture_cache.h
video_core.cpp
video_core.h
)

View File

@@ -36,10 +36,10 @@ void State::ProcessData(const u32 data, const bool is_last_call) {
} else {
UNIMPLEMENTED_IF(regs.dest.z != 0);
UNIMPLEMENTED_IF(regs.dest.depth != 1);
UNIMPLEMENTED_IF(regs.dest.BlockWidth() != 1);
UNIMPLEMENTED_IF(regs.dest.BlockDepth() != 1);
UNIMPLEMENTED_IF(regs.dest.BlockWidth() != 0);
UNIMPLEMENTED_IF(regs.dest.BlockDepth() != 0);
const std::size_t dst_size = Tegra::Texture::CalculateSize(
true, 1, regs.dest.width, regs.dest.height, 1, regs.dest.BlockHeight(), 1);
true, 1, regs.dest.width, regs.dest.height, 1, regs.dest.BlockHeight(), 0);
tmp_buffer.resize(dst_size);
memory_manager.ReadBlock(address, tmp_buffer.data(), dst_size);
Tegra::Texture::SwizzleKepler(regs.dest.width, regs.dest.height, regs.dest.x, regs.dest.y,

View File

@@ -39,15 +39,15 @@ struct Registers {
}
u32 BlockWidth() const {
return 1U << block_width.Value();
return block_width.Value();
}
u32 BlockHeight() const {
return 1U << block_height.Value();
return block_height.Value();
}
u32 BlockDepth() const {
return 1U << block_depth.Value();
return block_depth.Value();
}
} dest;
};

View File

@@ -4,7 +4,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/math_util.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
@@ -35,21 +34,31 @@ void Fermi2D::HandleSurfaceCopy() {
static_cast<u32>(regs.operation));
// TODO(Subv): Only raw copies are implemented.
ASSERT(regs.operation == Regs::Operation::SrcCopy);
ASSERT(regs.operation == Operation::SrcCopy);
const u32 src_blit_x1{static_cast<u32>(regs.blit_src_x >> 32)};
const u32 src_blit_y1{static_cast<u32>(regs.blit_src_y >> 32)};
const u32 src_blit_x2{
static_cast<u32>((regs.blit_src_x + (regs.blit_dst_width * regs.blit_du_dx)) >> 32)};
const u32 src_blit_y2{
static_cast<u32>((regs.blit_src_y + (regs.blit_dst_height * regs.blit_dv_dy)) >> 32)};
u32 src_blit_x2, src_blit_y2;
if (regs.blit_control.origin == Origin::Corner) {
src_blit_x2 =
static_cast<u32>((regs.blit_src_x + (regs.blit_du_dx * regs.blit_dst_width)) >> 32);
src_blit_y2 =
static_cast<u32>((regs.blit_src_y + (regs.blit_dv_dy * regs.blit_dst_height)) >> 32);
} else {
src_blit_x2 = static_cast<u32>((regs.blit_src_x >> 32) + regs.blit_dst_width);
src_blit_y2 = static_cast<u32>((regs.blit_src_y >> 32) + regs.blit_dst_height);
}
const Common::Rectangle<u32> src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2};
const Common::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y,
regs.blit_dst_x + regs.blit_dst_width,
regs.blit_dst_y + regs.blit_dst_height};
Config copy_config;
copy_config.operation = regs.operation;
copy_config.filter = regs.blit_control.filter;
copy_config.src_rect = src_rect;
copy_config.dst_rect = dst_rect;
if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst, src_rect, dst_rect)) {
if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {
UNIMPLEMENTED();
}
}

View File

@@ -9,6 +9,7 @@
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/math_util.h"
#include "video_core/gpu.h"
namespace Tegra {
@@ -38,6 +39,26 @@ public:
/// Write the value to the register identified by method.
void CallMethod(const GPU::MethodCall& method_call);
enum class Origin : u32 {
Center = 0,
Corner = 1,
};
enum class Filter : u32 {
PointSample = 0, // Nearest
Linear = 1,
};
enum class Operation : u32 {
SrcCopyAnd = 0,
ROPAnd = 1,
Blend = 2,
SrcCopy = 3,
ROP = 4,
SrcCopyPremult = 5,
BlendPremult = 6,
};
struct Regs {
static constexpr std::size_t NUM_REGS = 0x258;
@@ -63,32 +84,19 @@ public:
}
u32 BlockWidth() const {
// The block width is stored in log2 format.
return 1 << block_width;
return block_width.Value();
}
u32 BlockHeight() const {
// The block height is stored in log2 format.
return 1 << block_height;
return block_height.Value();
}
u32 BlockDepth() const {
// The block depth is stored in log2 format.
return 1 << block_depth;
return block_depth.Value();
}
};
static_assert(sizeof(Surface) == 0x28, "Surface has incorrect size");
enum class Operation : u32 {
SrcCopyAnd = 0,
ROPAnd = 1,
Blend = 2,
SrcCopy = 3,
ROP = 4,
SrcCopyPremult = 5,
BlendPremult = 6,
};
union {
struct {
INSERT_PADDING_WORDS(0x80);
@@ -105,7 +113,11 @@ public:
INSERT_PADDING_WORDS(0x177);
u32 blit_control;
union {
u32 raw;
BitField<0, 1, Origin> origin;
BitField<4, 1, Filter> filter;
} blit_control;
INSERT_PADDING_WORDS(0x8);
@@ -124,6 +136,13 @@ public:
};
} regs{};
struct Config {
Operation operation;
Filter filter;
Common::Rectangle<u32> src_rect;
Common::Rectangle<u32> dst_rect;
};
private:
VideoCore::RasterizerInterface& rasterizer;
MemoryManager& memory_manager;

View File

@@ -430,14 +430,10 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
Texture::TICEntry tic_entry;
memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
ASSERT_MSG(tic_entry.header_version == Texture::TICHeaderVersion::BlockLinear ||
tic_entry.header_version == Texture::TICHeaderVersion::Pitch,
"TIC versions other than BlockLinear or Pitch are unimplemented");
const auto r_type = tic_entry.r_type.Value();
const auto g_type = tic_entry.g_type.Value();
const auto b_type = tic_entry.b_type.Value();
const auto a_type = tic_entry.a_type.Value();
const auto r_type{tic_entry.r_type.Value()};
const auto g_type{tic_entry.g_type.Value()};
const auto b_type{tic_entry.b_type.Value()};
const auto a_type{tic_entry.a_type.Value()};
// TODO(Subv): Different data types for separate components are not supported
DEBUG_ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);

View File

@@ -111,7 +111,7 @@ void MaxwellDMA::HandleCopy() {
memory_manager.WriteBlock(dest, write_buffer.data(), dst_size);
} else {
ASSERT(regs.dst_params.BlockDepth() == 1);
ASSERT(regs.dst_params.BlockDepth() == 0);
const u32 src_bytes_per_pixel = regs.src_pitch / regs.x_count;

View File

@@ -59,11 +59,11 @@ public:
};
u32 BlockHeight() const {
return 1 << block_height;
return block_height.Value();
}
u32 BlockDepth() const {
return 1 << block_depth;
return block_depth.Value();
}
};

View File

@@ -4,6 +4,7 @@
#pragma once
#include <array>
#include <bitset>
#include <optional>
#include <tuple>
@@ -126,6 +127,15 @@ union Sampler {
u64 value{};
};
union Image {
Image() = default;
constexpr explicit Image(u64 value) : value{value} {}
BitField<36, 13, u64> index;
u64 value;
};
} // namespace Tegra::Shader
namespace std {
@@ -344,6 +354,26 @@ enum class TextureMiscMode : u64 {
PTP,
};
enum class SurfaceDataMode : u64 {
P = 0,
D_BA = 1,
};
enum class OutOfBoundsStore : u64 {
Ignore = 0,
Clamp = 1,
Trap = 2,
};
enum class ImageType : u64 {
Texture1D = 0,
TextureBuffer = 1,
Texture1DArray = 2,
Texture2D = 3,
Texture2DArray = 4,
Texture3D = 5,
};
enum class IsberdMode : u64 {
None = 0,
Patch = 1,
@@ -398,7 +428,7 @@ enum class LmemLoadCacheManagement : u64 {
CV = 3,
};
enum class LmemStoreCacheManagement : u64 {
enum class StoreCacheManagement : u64 {
Default = 0,
CG = 1,
CS = 2,
@@ -811,7 +841,7 @@ union Instruction {
} ld_l;
union {
BitField<44, 2, LmemStoreCacheManagement> cache_management;
BitField<44, 2, StoreCacheManagement> cache_management;
} st_l;
union {
@@ -1231,6 +1261,20 @@ union Instruction {
}
} texs;
union {
BitField<28, 1, u64> is_array;
BitField<29, 2, TextureType> texture_type;
BitField<35, 1, u64> aoffi;
BitField<49, 1, u64> nodep_flag;
BitField<50, 1, u64> ms; // Multisample?
BitField<54, 1, u64> cl;
BitField<55, 1, u64> process_mode;
TextureProcessMode GetTextureProcessMode() const {
return process_mode == 0 ? TextureProcessMode::LZ : TextureProcessMode::LL;
}
} tld;
union {
BitField<49, 1, u64> nodep_flag;
BitField<53, 4, u64> texture_info;
@@ -1280,6 +1324,35 @@ union Instruction {
}
} tlds;
union {
BitField<24, 2, StoreCacheManagement> cache_management;
BitField<33, 3, ImageType> image_type;
BitField<49, 2, OutOfBoundsStore> out_of_bounds_store;
BitField<51, 1, u64> is_immediate;
BitField<52, 1, SurfaceDataMode> mode;
BitField<20, 3, StoreType> store_data_layout;
BitField<20, 4, u64> component_mask_selector;
bool IsComponentEnabled(std::size_t component) const {
ASSERT(mode == SurfaceDataMode::P);
constexpr u8 R = 0b0001;
constexpr u8 G = 0b0010;
constexpr u8 B = 0b0100;
constexpr u8 A = 0b1000;
constexpr std::array<u8, 16> mask = {
0, (R), (G), (R | G), (B), (R | B),
(G | B), (R | G | B), (A), (R | A), (G | A), (R | G | A),
(B | A), (R | B | A), (G | B | A), (R | G | B | A)};
return std::bitset<4>{mask.at(component_mask_selector)}.test(component);
}
StoreType GetStoreDataLayout() const {
ASSERT(mode == SurfaceDataMode::D_BA);
return store_data_layout;
}
} sust;
union {
BitField<20, 24, u64> target;
BitField<5, 1, u64> constant_buffer;
@@ -1371,6 +1444,7 @@ union Instruction {
Attribute attribute;
Sampler sampler;
Image image;
u64 value;
};
@@ -1408,11 +1482,13 @@ public:
TXQ, // Texture Query
TXQ_B, // Texture Query Bindless
TEXS, // Texture Fetch with scalar/non-vec4 source/destinations
TLD, // Texture Load
TLDS, // Texture Load with scalar/non-vec4 source/destinations
TLD4, // Texture Load 4
TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations
TMML_B, // Texture Mip Map Level
TMML, // Texture Mip Map Level
SUST, // Surface Store
EXIT,
IPA,
OUT_R, // Emit vertex/primitive
@@ -1543,6 +1619,7 @@ public:
Synch,
Memory,
Texture,
Image,
FloatSet,
FloatSetPredicate,
IntegerSet,
@@ -1682,11 +1759,13 @@ private:
INST("1101111101001---", Id::TXQ, Type::Texture, "TXQ"),
INST("1101111101010---", Id::TXQ_B, Type::Texture, "TXQ_B"),
INST("1101-00---------", Id::TEXS, Type::Texture, "TEXS"),
INST("11011100--11----", Id::TLD, Type::Texture, "TLD"),
INST("1101101---------", Id::TLDS, Type::Texture, "TLDS"),
INST("110010----111---", Id::TLD4, Type::Texture, "TLD4"),
INST("1101111100------", Id::TLD4S, Type::Texture, "TLD4S"),
INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"),
INST("1101111101011---", Id::TMML, Type::Texture, "TMML"),
INST("11101011001-----", Id::SUST, Type::Image, "SUST"),
INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"),
INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"),

View File

@@ -202,11 +202,12 @@ const u8* MemoryManager::GetPointer(GPUVAddr addr) const {
}
bool MemoryManager::IsBlockContinuous(const GPUVAddr start, const std::size_t size) const {
const GPUVAddr end = start + size;
const std::size_t inner_size = size - 1;
const GPUVAddr end = start + inner_size;
const auto host_ptr_start = reinterpret_cast<std::uintptr_t>(GetPointer(start));
const auto host_ptr_end = reinterpret_cast<std::uintptr_t>(GetPointer(end));
const auto range = static_cast<std::size_t>(host_ptr_end - host_ptr_start);
return range == size;
return range == inner_size;
}
void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const {

View File

@@ -169,6 +169,8 @@ protected:
object->MarkAsModified(false, *this);
}
std::recursive_mutex mutex;
private:
/// Returns a list of cached objects from the specified memory region, ordered by access time
std::vector<T> GetSortedObjectsFromRegion(CacheAddr addr, u64 size) {
@@ -208,5 +210,4 @@ private:
IntervalCache interval_cache; ///< Cache of objects
u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing
VideoCore::RasterizerInterface& rasterizer;
std::recursive_mutex mutex;
};

View File

@@ -10,6 +10,10 @@
#include "video_core/engines/fermi_2d.h"
#include "video_core/gpu.h"
namespace Tegra {
class MemoryManager;
}
namespace VideoCore {
enum class LoadCallbackStage {
@@ -46,8 +50,7 @@ public:
/// Attempt to use a faster method to perform a surface copy
virtual bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
const Tegra::Engines::Fermi2D::Regs::Surface& dst,
const Common::Rectangle<u32>& src_rect,
const Common::Rectangle<u32>& dst_rect) {
const Tegra::Engines::Fermi2D::Config& copy_config) {
return false;
}

View File

@@ -23,6 +23,7 @@ OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size)
GLintptr OGLBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size, std::size_t alignment,
bool cache) {
std::lock_guard lock{mutex};
auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
// Cache management is a big overhead, so only cache entries with a given size.
@@ -62,6 +63,7 @@ GLintptr OGLBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size, std::
GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, std::size_t size,
std::size_t alignment) {
std::lock_guard lock{mutex};
AlignBuffer(alignment);
std::memcpy(buffer_ptr, raw_pointer, size);
const GLintptr uploaded_offset = buffer_offset;

View File

@@ -0,0 +1,75 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <tuple>
#include "common/cityhash.h"
#include "common/scope_exit.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_opengl/gl_framebuffer_cache.h"
#include "video_core/renderer_opengl/gl_state.h"
namespace OpenGL {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
FramebufferCacheOpenGL::FramebufferCacheOpenGL() = default;
FramebufferCacheOpenGL::~FramebufferCacheOpenGL() = default;
GLuint FramebufferCacheOpenGL::GetFramebuffer(const FramebufferCacheKey& key) {
const auto [entry, is_cache_miss] = cache.try_emplace(key);
auto& framebuffer{entry->second};
if (is_cache_miss) {
framebuffer = CreateFramebuffer(key);
}
return framebuffer.handle;
}
OGLFramebuffer FramebufferCacheOpenGL::CreateFramebuffer(const FramebufferCacheKey& key) {
OGLFramebuffer framebuffer;
framebuffer.Create();
// TODO(Rodrigo): Use DSA here after Nvidia fixes their framebuffer DSA bugs.
local_state.draw.draw_framebuffer = framebuffer.handle;
local_state.ApplyFramebufferState();
if (key.is_single_buffer) {
if (key.color_attachments[0] != GL_NONE && key.colors[0]) {
key.colors[0]->Attach(key.color_attachments[0], GL_DRAW_FRAMEBUFFER);
glDrawBuffer(key.color_attachments[0]);
} else {
glDrawBuffer(GL_NONE);
}
} else {
for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
if (key.colors[index]) {
key.colors[index]->Attach(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
GL_DRAW_FRAMEBUFFER);
}
}
glDrawBuffers(key.colors_count, key.color_attachments.data());
}
if (key.zeta) {
key.zeta->Attach(key.stencil_enable ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
GL_DRAW_FRAMEBUFFER);
}
return framebuffer;
}
std::size_t FramebufferCacheKey::Hash() const {
static_assert(sizeof(*this) % sizeof(u64) == 0, "Unaligned struct");
return static_cast<std::size_t>(
Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
}
bool FramebufferCacheKey::operator==(const FramebufferCacheKey& rhs) const {
return std::tie(is_single_buffer, stencil_enable, colors_count, color_attachments, colors,
zeta) == std::tie(rhs.is_single_buffer, rhs.stencil_enable, rhs.colors_count,
rhs.color_attachments, rhs.colors, rhs.zeta);
}
} // namespace OpenGL

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