Compare commits

...

153 Commits

Author SHA1 Message Date
Lioncash d72e675df5 common/logging: Apply nodiscard where applicable 2019-04-15 15:46:17 -04:00
Lioncash 4f4691502b common/zstd_compression: Apply nodiscard where applicable 2019-04-15 15:46:17 -04:00
Lioncash 1c23c2ec5e common/uint128: Apply nodiscard and noexcept where applicable 2019-04-15 15:46:17 -04:00
Lioncash 1c13186ec5 common/timer: Apply nodiscard where applicable 2019-04-15 15:46:17 -04:00
Lioncash 5ef9259e64 common/threadsafe_queue: Apply nodiscard where applicable 2019-04-15 15:46:17 -04:00
Lioncash 737fafef56 common/thread_queue_list: Apply nodiscard where applicable 2019-04-15 15:46:17 -04:00
Lioncash 5cbc3dcfe6 common/thread: Apply nodiscard where applicable 2019-04-15 15:46:17 -04:00
Lioncash 1a40a58fd5 common/telemetry: Apply nodiscard where applicable 2019-04-15 15:46:05 -04:00
Lioncash 3519abc87a common/string_util: Apply nodiscard where applicable 2019-04-15 13:18:24 -04:00
Lioncash f811a4fef0 common/ring_buffer: Apply nodiscard where applicable 2019-04-15 13:16:06 -04:00
Lioncash 52d845f59c common/quaternion: Apply nodiscard and noexcept where applicable 2019-04-15 13:13:11 -04:00
Lioncash 406b04c7de common/param_package: Apply nodiscard where applicable 2019-04-15 13:11:26 -04:00
Lioncash 76eb6c89ed common/page_table: Apply nodiscard where applicable 2019-04-15 13:10:24 -04:00
Lioncash 30f35cbd5b common/multi_level_queue: Apply nodiscard where applicable 2019-04-15 13:09:09 -04:00
Lioncash 329dc99635 common/memory_hook: Apply nodiscard where applicable 2019-04-15 13:06:35 -04:00
Lioncash 07fd12f353 common/math_util: Apply nodiscard and noexcept where applicable
Applies the nodiscard attribute where it would be a bug/logic error to
ignore the return value.

Also marks inline member functions as noexcept where applicable.
2019-04-15 13:02:46 -04:00
Lioncash a88b2e8c88 common/lz4_compression: Apply nodiscard where applicable
Applies nodiscard where it would 100% be a bug if the return value is
ignored.
2019-04-15 12:58:51 -04:00
Lioncash 4ddf95aba0 common/hex_util: Apply nodiscard where applicable
Applies nodiscard to functions where ignoring the return value would be
a bug.
2019-04-15 12:57:09 -04:00
Lioncash 016a647623 common/file_util: Apply nodiscard where applicable
Applies nodiscard to functions where it would be guaranteed to be a bug
if the return value is ignored.
2019-04-15 12:54:15 -04:00
Lioncash 6d266f4374 common/common_funcs: Apply nodiscard and noexcept where applicable
In all cases, it would be a bug to ignore the return value.
2019-04-15 12:45:58 -04:00
Lioncash 50e452217e common/bit_util: Apply nodiscard and noexcept where applicable
In all scenarios here, it would be a bug to ignore the return values of
these functions.
2019-04-15 12:43:40 -04:00
Lioncash d0ea421f2d common/bit_field: Apply nodiscard and noexcept where applicable
Marks functions where it would be a bug to ignore the return value with
nodiscard.
2019-04-15 12:43:20 -04:00
Lioncash 10cfa87eb6 common/alignment: Apply nodiscard and noexcept to utility functions
In all scenarios, ignoring the return value of these functions is a bug.
While we're at it, we can also make them noexcept.
2019-04-15 12:36:16 -04:00
bunnei 1f4dfb3998 Merge pull request #2378 from lioncash/ro
ldr: Minor amendments to IPC-related parameters
2019-04-13 22:16:10 -04:00
bunnei c9454c8422 Merge pull request #2373 from FernandoS27/z32
Set Pixel Format to Z32 if its R32F and depth compare enabled, and Implement format ZF32_X24S8
2019-04-13 22:14:51 -04:00
bunnei 6088898b02 Merge pull request #2357 from zarroboogs/force-30fps-mode
Add a toggle to force 30FPS mode
2019-04-13 22:14:04 -04:00
bunnei a788c861bd Merge pull request #2381 from lioncash/fs
fsp_srv: Minor cleanup related changes
2019-04-13 22:09:58 -04:00
bunnei ee2206a1b7 Merge pull request #2386 from ReinUsesLisp/shader-manager
gl_shader_manager: Move code to source file and minor clean up
2019-04-13 22:09:27 -04:00
bunnei 065f83c6c3 Merge pull request #2017 from jroweboy/glwidget
Frontend: Migrate to QOpenGLWindow and support shared contexts
2019-04-13 22:08:40 -04:00
bunnei ee3f576495 Merge pull request #2389 from FreddyFunk/rename-gamedir
ui_settings: Rename game directory variables
2019-04-13 22:06:51 -04:00
bunnei b42595fa6b Merge pull request #2391 from lioncash/scope
common/scope_exit: Replace std::move with std::forward in ScopeExit()
2019-04-12 21:52:35 -04:00
bunnei 0faf7b17a1 Merge pull request #2392 from lioncash/swap
common/swap: Minor cleanup and improvements to byte swapping functions
2019-04-12 21:52:16 -04:00
FreddyFunk 382722b9c4 Fix Clang Format 2019-04-12 16:40:35 +02:00
Lioncash 0d8ef2d3b9 common/swap: Improve codegen of the default swap fallbacks
Uses arithmetic that can be identified more trivially by compilers for
optimizations. e.g. Rather than shifting the halves of the value and
then swapping and combining them, we can swap them in place.

e.g. for the original swap32 code on x86-64, clang 8.0 would generate:

    mov     ecx, edi
    rol     cx, 8
    shl     ecx, 16
    shr     edi, 16
    rol     di, 8
    movzx   eax, di
    or      eax, ecx
    ret

while GCC 8.3 would generate the ideal:

    mov     eax, edi
    bswap   eax
    ret

now both generate the same optimal output.

MSVC used to generate the following with the old code:

    mov     eax, ecx
    rol     cx, 8
    shr     eax, 16
    rol     ax, 8
    movzx   ecx, cx
    movzx   eax, ax
    shl     ecx, 16
    or      eax, ecx
    ret     0

Now MSVC also generates a similar, but equally optimal result as clang/GCC:

    bswap   ecx
    mov     eax, ecx
    ret     0

====

In the swap64 case, for the original code, clang 8.0 would generate:

    mov     eax, edi
    bswap   eax
    shl     rax, 32
    shr     rdi, 32
    bswap   edi
    or      rax, rdi
    ret

(almost there, but still missing the mark)

while, again, GCC 8.3 would generate the more ideal:

    mov     rax, rdi
    bswap   rax
    ret

now clang also generates the optimal sequence for this fallback as well.

This is a case where MSVC unfortunately falls short, despite the new
code, this one still generates a doozy of an output.

    mov     r8, rcx
    mov     r9, rcx
    mov     rax, 71776119061217280
    mov     rdx, r8
    and     r9, rax
    and     edx, 65280
    mov     rax, rcx
    shr     rax, 16
    or      r9, rax
    mov     rax, rcx
    shr     r9, 16
    mov     rcx, 280375465082880
    and     rax, rcx
    mov     rcx, 1095216660480
    or      r9, rax
    mov     rax, r8
    and     rax, rcx
    shr     r9, 16
    or      r9, rax
    mov     rcx, r8
    mov     rax, r8
    shr     r9, 8
    shl     rax, 16
    and     ecx, 16711680
    or      rdx, rax
    mov     eax, -16777216
    and     rax, r8
    shl     rdx, 16
    or      rdx, rcx
    shl     rdx, 16
    or      rax, rdx
    shl     rax, 8
    or      rax, r9
    ret     0

which is pretty unfortunate.
2019-04-12 00:07:39 -04:00
bunnei ea80e2bc57 Merge pull request #2235 from ReinUsesLisp/spirv-decompiler
vk_shader_decompiler: Implement a SPIR-V decompiler
2019-04-11 21:54:23 -04:00
bunnei 83a2fb3c3a Merge pull request #2360 from lioncash/svc-global
kernel/svc: Deglobalize the supervisor call handlers
2019-04-11 21:50:05 -04:00
bunnei e2f2155dab Merge pull request #2388 from lioncash/constexpr
kernel: Make handle type declarations constexpr
2019-04-11 21:49:45 -04:00
bunnei c0b2b7020d Merge pull request #2387 from FernandoS27/fast-copy-relax
gl_rasterizer_cache: Relax restrictions on FastCopySurface
2019-04-11 21:49:21 -04:00
Lioncash 66b73fd399 common/swap: Mark byte swapping free functions with [[nodiscard]] and noexcept
Allows the compiler to inform when the result of a swap function is
being ignored (which is 100% a bug in all usage scenarios). We also mark
them noexcept to allow other functions using them to be able to be
marked as noexcept and play nicely with things that potentially inspect
"nothrowability".
2019-04-11 20:42:44 -04:00
Lioncash 9cb4b7be40 common/swap: Simplify swap function ifdefs
Including every OS' own built-in byte swapping functions is kind of
undesirable, since it adds yet another build path to ensure compilation
succeeds on.

Given we only support clang, GCC, and MSVC for the time being, we can
utilize their built-in functions directly instead of going through the
OS's API functions.

This shrinks the overall code down to just

if (msvc)
  use msvc's functions
else if (clang or gcc)
  use clang/gcc's builtins
else
  use the slow path
2019-04-11 20:36:19 -04:00
Lioncash 598954436f common/swap: Remove 32-bit ARM path
We don't plan to support host 32-bit ARM execution environments, so this
is essentially dead code.
2019-04-11 20:15:47 -04:00
Lioncash b569641098 common/scope_exit: Replace std::move with std::forward in ScopeExit()
The template type here is actually a forwarding reference, not an rvalue
reference in this case, so it's more appropriate to use std::forward to
preserve the value category of the type being moved.
2019-04-11 20:01:33 -04:00
Lioncash 6300ccbc3c kernel: Make handle type declarations constexpr
Some objects declare their handle type as const, while others declare it
as constexpr. This makes the const ones constexpr for consistency, and
prevent unexpected compilation errors if these happen to be attempted to be
used within a constexpr context.
2019-04-11 16:34:53 -04:00
FreddyFunk dffa1a872a ui_settings: Rename game directory variables 2019-04-11 19:55:56 +02:00
Fernando Sahmkow c9305959d3 gl_rasterizer_cache: Relax restrictions on FastCopySurface and FastLayeredCopySurface 2019-04-11 13:14:28 -04:00
bunnei 6951741a94 Merge pull request #2278 from ReinUsesLisp/vc-texture-cache
video_core: Implement API agnostic view based texture cache
2019-04-10 21:17:35 -04:00
bunnei 0371650bd7 Merge pull request #2372 from FernandoS27/fermi-fix
Correct Fermi Copy on Linear Textures.
2019-04-10 21:17:03 -04:00
ReinUsesLisp 93af663683 gl_shader_manager: Move code to source file and minor clean up 2019-04-10 19:29:15 -03:00
Lioncash dae2449880 ldr: Mark IsValidNROHash() as a const member function
This doesn't modify instance state, so it can be made const.
2019-04-10 15:57:02 -04:00
Lioncash 0032cf3818 ldr: Amend parameters for LoadNro/UnloadNro LoadNrr/UnloadNrr
The initial two words indicate a process ID. Also UnloadNro only
specifies one address, not two.
2019-04-10 15:56:43 -04:00
ReinUsesLisp 75d23a3679 vk_shader_decompiler: Implement flow primitives 2019-04-10 14:20:25 -03:00
ReinUsesLisp 58ad8dfac6 vk_shader_decompiler: Implement most common texture primitives 2019-04-10 14:20:25 -03:00
ReinUsesLisp 4667ed8e22 vk_shader_decompiler: Implement texture decompilation helper functions 2019-04-10 14:20:25 -03:00
ReinUsesLisp 676172e20d vk_shader_decompiler: Implement Assign and LogicalAssign 2019-04-10 14:20:25 -03:00
ReinUsesLisp d316d248ab vk_shader_decompiler: Implement non-OperationCode visits 2019-04-10 14:20:25 -03:00
ReinUsesLisp b758c861b0 vk_shader_decompiler: Implement OperationCode decompilation interface 2019-04-10 14:20:25 -03:00
ReinUsesLisp fec4eb9776 vk_shader_decompiler: Implement Visit 2019-04-10 14:20:25 -03:00
ReinUsesLisp ca51f99840 vk_shader_decompiler: Implement labels tree and flow 2019-04-10 14:20:25 -03:00
ReinUsesLisp 13aa664f3f vk_shader_decompiler: Implement declarations 2019-04-10 14:20:25 -03:00
ReinUsesLisp ad53b233c5 vk_shader_decompiler: Declare and stub interface for a SPIR-V decompiler 2019-04-10 14:20:25 -03:00
ReinUsesLisp 970d9e57c8 video_core: Add sirit as optional dependency with Vulkan
sirit is a runtime assembler for SPIR-V
2019-04-10 14:20:25 -03:00
Lioncash 8676832064 fsp_srv: Remove unnecessary parameter popping in IDirectory's Read()
IDirectory's Read() function doesn't take any input parameters. It only
uses the output parameters that we already provide.
2019-04-10 13:04:08 -04:00
Lioncash fc436bb09b fsp_srv: Log out option values in IFile's Read and Write functions
These indicate options that alter how a read/write is performed.

Currently we don't need to handle these, as the only one that seems to
be used is for writes, but all the custom options ever seem to do is
immediate flushing, which we already do by default.
2019-04-10 13:01:52 -04:00
bunnei 97648f4841 Merge pull request #2345 from ReinUsesLisp/multibind
gl_rasterizer: Use ARB_multi_bind to update buffers with a single call per drawcall
2019-04-10 11:23:19 -04:00
bunnei 1312cf15d6 Merge pull request #2377 from lioncash/todo
kernel/server_session: Remove obsolete TODOs
2019-04-10 10:29:24 -04:00
Lioncash 08d507a196 kernel/server_session: Remove obsolete TODOs
These are holdovers from Citra.
2019-04-09 23:34:49 -04:00
bunnei ed9dba89d3 Merge pull request #2375 from FernandoS27/fix-ldc
Remove unnecessary bounding in LD_C
2019-04-09 21:23:24 -04:00
bunnei f46c3164e7 Merge pull request #2353 from lioncash/surface
yuzu/debugger: Remove graphics surface viewer
2019-04-09 21:20:02 -04:00
Fernando Sahmkow c9f35d96be Remove bounding in LD_C 2019-04-09 20:02:11 -04:00
bunnei 2598433f9c Merge pull request #2354 from lioncash/header
video_core/texures/texture: Remove unnecessary includes
2019-04-09 19:19:41 -04:00
bunnei 61f63bb994 Merge pull request #1957 from DarkLordZach/title-provider
file_sys: Provide generic interface for accessing game data
2019-04-09 19:16:37 -04:00
bunnei 353a099481 Merge pull request #2366 from FernandoS27/xmad-fix
Correct XMAD mode, psl and high_b on different encodings.
2019-04-09 19:15:01 -04:00
bunnei 1a3098f11a Merge pull request #2132 from FearlessTobi/port-4437
Port citra-emu/citra#4437: "citra-qt: Make hotkeys configurable via the GUI (Attempt 2)"
2019-04-09 18:08:30 -04:00
bunnei 71182643f7 Merge pull request #2370 from lioncash/qt-warn
yuzu/loading_screen: Resolve runtime Qt string formatting warnings
2019-04-09 17:21:18 -04:00
bunnei bc7e149835 Merge pull request #2369 from FernandoS27/mip-align
gl_backend: Align Pixel Storage
2019-04-09 17:20:43 -04:00
bunnei 088c7c1bb5 Merge pull request #2368 from FernandoS27/fix-lop
Correct LOP_IMM encoding
2019-04-09 17:19:56 -04:00
Fernando Sahmkow cd91e98dab Correct Fermi Copy on Linear Textures. 2019-04-09 14:13:58 -04:00
Hexagon12 b81260c65c Merge pull request #2371 from lioncash/pagetable
kernel/process: Set page table when page table resizes occur.
2019-04-09 20:13:37 +03:00
Lioncash 2abf979c35 kernel/process: Set page table when page table resizes occur.
We need to ensure dynarmic gets a valid pointer if the page table is
resized (the relevant pointers would be invalidated in this scenario).

In this scenario, the page table can be resized depending on what kind
of address space is specified within the NPDM metadata (if it's
present).
2019-04-09 13:00:56 -04:00
Fernando Sahmkow 7c458311d3 Implement Texture Format ZF32_X24S8. 2019-04-09 12:33:46 -04:00
Fernando Sahmkow b0aa8ad736 Correct depth compare with color formats for R32F 2019-04-09 12:06:59 -04:00
Lioncash b73e433dff yuzu/loading_screen: Resolve runtime Qt string formatting warnings
In our error console, when loading a game, the strings:

QString::arg: Argument missing: "Loading...", 0
QString::arg: Argument missing: "Launching...", 0

would occasionally pop up when the loading screen was running. This was
due to the strings being assumed to have formatting indicators in them,
however only two out of the four strings actually have them.

This only applies the arguments to the strings that have formatting
specifiers provided, which avoids these warnings from occurring.
2019-04-09 10:49:38 -04:00
zarroboogs be6466d5c0 added a toggle to force 30fps mode 2019-04-09 02:14:03 +03:00
Fernando Sahmkow 9f16833097 gl_backend: Align Pixel Storage
This commit makes sure GL reads on the correct pack size for the
respective texture buffer.
2019-04-08 17:16:02 -04:00
Fernando Sahmkow 5c55ae4e18 Correct LOP_IMN encoding 2019-04-08 13:39:12 -04:00
Fernando Sahmkow 16adc735a5 Correct XMAD mode, psl and high_b on different encodings. 2019-04-08 13:01:17 -04:00
Lioncash b117ca5fce kernel/svc: Deglobalize the supervisor call handlers
Adjusts the interface of the wrappers to take a system reference, which
allows accessing a system instance without using the global accessors.

This also allows getting rid of all global accessors within the
supervisor call handling code. While this does make the wrappers
themselves slightly more noisy, this will be further cleaned up in a
follow-up. This eliminates the global system accessors in the current
code while preserving the existing interface.
2019-04-07 20:30:05 -04:00
bunnei f14328bf0a Merge pull request #2300 from FernandoS27/null-shader
shader_cache: Permit a Null Shader in case of a bad host_ptr.
2019-04-07 17:58:27 -04:00
bunnei c2fee0e519 Merge pull request #2355 from ReinUsesLisp/sync-point
maxwell_3d: Reduce severity of ProcessSyncPoint
2019-04-07 17:56:11 -04:00
bunnei 06ece52cfe Merge pull request #2359 from FearlessTobi/port-2-prs
Port citra-emu/citra#4718: "fix clang-format target when using a path with spaces on windows"
2019-04-07 17:54:57 -04:00
bunnei 8aaf418bd6 Merge pull request #2306 from ReinUsesLisp/aoffi
shader_ir: Implement AOFFI for TEX and TLD4
2019-04-07 17:52:30 -04:00
bunnei 3c1ce290d0 Merge pull request #2361 from lioncash/pagetable
core/memory: Minor simplifications to page table management
2019-04-07 17:50:31 -04:00
bunnei 6b18a1592f Merge pull request #2321 from ReinUsesLisp/gl-state-rework
gl_state: Rework to enable individual applies
2019-04-07 17:50:07 -04:00
bunnei 21a4e7deea Merge pull request #2098 from FreddyFunk/disk-cache-zstd
gl_shader_disk_cache: Use Zstandard for compression
2019-04-07 17:48:33 -04:00
bunnei 52ad5fa0e8 Merge pull request #2356 from lioncash/pair
kernel/{server_port, server_session}: Return pairs instead of tuples from pair creation functions
2019-04-07 17:48:00 -04:00
bunnei d9b1c24f4f Merge pull request #2362 from lioncash/enum
core/memory: Remove unused enum constants
2019-04-07 17:46:09 -04:00
bunnei 80162888e6 Merge pull request #2352 from bunnei/mem-manager-fixes
memory_manager: Improved implementation of read/write/copy block.
2019-04-07 17:44:59 -04:00
Fernando Sahmkow 021cd56bc9 Permit a Null Shader in case of a bad host_ptr. 2019-04-07 07:52:01 -04:00
Lioncash 36a1e6a982 core/memory: Remove unused enum constants
These are holdovers from Citra and can be removed.
2019-04-07 03:04:55 -04:00
Lioncash abae7577d2 core/memory: Remove GetCurrentPageTable()
Now that nothing actually touches the internal page table aside from the
memory subsystem itself, we can remove the accessor to it.
2019-04-07 02:47:37 -04:00
Lioncash a6a82bb004 arm/arm_dynarmic: Remove unnecessary current_page_table member
Given the page table will always be guaranteed to be that of whatever
the current process is, we no longer need to keep this around.
2019-04-07 02:43:51 -04:00
Lioncash e779686a76 kernel: Handle page table switching within MakeCurrentProcess()
Centralizes the page table switching to one spot, rather than making
calling code deal with it everywhere.
2019-04-07 01:12:54 -04:00
khang06 945e39471d fix clang-format target when using a path with spaces on windows 2019-04-07 02:10:01 +02:00
Lioncash 7a7ffa602d kernel/server_session: Return a std::pair from CreateSessionPair()
Keeps the return type consistent with the function name. While we're at
it, we can also reduce the amount of boilerplate involved with handling
these by using structured bindings.
2019-04-06 01:42:03 -04:00
Lioncash 04d265562f kernel/server_port: Return a std::pair from CreatePortPair()
Returns the same type that the function name describes.
2019-04-06 01:36:53 -04:00
ReinUsesLisp ddcb711ee8 maxwell_3d: Reduce severity of ProcessSyncPoint 2019-04-06 02:18:20 -03:00
Lioncash 89c106e31b video_core/textures/convert: Replace include with a forward declaration
Avoids dragging in a direct dependency in a header.
2019-04-06 00:14:36 -04:00
Lioncash fbf452ab0e video_core/texures/texture: Remove unnecessary includes
Nothing in this header relies on common_funcs or the memory manager.

This gets rid of reliance on indirect inclusions in the OpenGL caches.
2019-04-06 00:03:35 -04:00
bunnei 864280fabc Merge pull request #2317 from FernandoS27/sync
Implement SyncPoint Register in the GPU.
2019-04-05 23:50:54 -04:00
bunnei 7d1c0fd1ad Merge pull request #2325 from lioncash/name
kernel/server_session: Provide a GetName() override
2019-04-05 23:48:13 -04:00
bunnei fddafa14c8 Merge pull request #2342 from lioncash/warning
common/multi_level_queue: Silence truncation warnings
2019-04-05 23:47:27 -04:00
bunnei 54c7e8e40e Merge pull request #2240 from FearlessTobi/port-4651
Port citra-emu/citra#4651: "gdbstub: Fix some bugs in IsMemoryBreak() and ServeBreak. Add workaround to let watchpoints break into GDB."
2019-04-05 23:46:37 -04:00
bunnei e3402d976d Merge pull request #2346 from lioncash/header
video_core/engines: Remove unnecessary inclusions where applicable
2019-04-05 23:44:27 -04:00
bunnei 20be92d5e6 memory_manager: Improved implementation of read/write/copy block.
- Fixes graphical issues with Chocobo's Mystery Dungeon EVERY BUDDY!
- Fixes a crash with Mario Tennis Aces
2019-04-05 23:43:34 -04:00
Fernando Sahmkow fc91e21206 Implement SyncPoint Register in the GPU. 2019-04-05 19:19:30 -04:00
Lioncash 22f02076c6 video_core/engines: Make memory manager members private
These aren't used externally by anything, so they can be made private
data members.
2019-04-05 18:26:43 -04:00
Lioncash 26223f8124 video_core/engines: Remove unnecessary inclusions where applicable
Replaces header inclusions with forward declarations where applicable
and also removes unused headers within the cpp file. This reduces a few
more dependencies on core/memory.h
2019-04-05 18:26:32 -04:00
ReinUsesLisp 34c3e2c786 renderer_opengl/utils: Skip empty binds 2019-04-05 19:19:49 -03:00
ReinUsesLisp b631c09e72 gl_rasterizer: Use ARB_multi_bind to update SSBOs 2019-04-05 19:18:43 -03:00
ReinUsesLisp 2d1f054c61 gl_rasterizer: Use ARB_multi_bind to update UBOs across stages 2019-04-05 19:10:46 -03:00
Lioncash 93b84e9308 common/multi_level_queue: Silence truncation warning in iterator operator++ 2019-04-05 15:35:46 -04:00
Lioncash 33db37e669 common/bit_util: Make CountLeading/CountTrailing functions have the same return types
Makes the return type consistently uniform (like the intrinsics we're
wrapping). This also conveniently silences a truncation warning within
the kernel multi_level_queue.
2019-04-05 15:29:40 -04:00
ReinUsesLisp 78bd66d037 gl_state: Rework to enable individual applies 2019-04-03 20:26:27 -03:00
Lioncash a074363a5d kernel/server_session: Provide a GetName() override
Given server sessions can be given a name, we should allow retrieving
it instead of using the default implementation of GetName(), which would
just return "[UNKNOWN KERNEL OBJECT]".
2019-04-03 10:39:06 -04:00
ReinUsesLisp 38658b38b4 gl_shader_decompiler: Hide local definitions inside an anonymous namespace 2019-03-31 00:26:34 -03:00
Mat M da02946f4f shader_ir/decode: Silent implicit sign conversion warning
Co-Authored-By: ReinUsesLisp <reinuseslisp@airmail.cc>
2019-03-31 00:12:54 -03:00
ReinUsesLisp e8abe4b77c gl_shader_decompiler: Add AOFFI backing implementation 2019-03-30 02:55:18 -03:00
ReinUsesLisp cb68ce7c2f shader_ir/decode: Implement AOFFI for TEX and TLD4 2019-03-30 02:53:29 -03:00
ReinUsesLisp cf4ecc1945 shader_ir: Implement immediate register tracking 2019-03-30 02:53:16 -03:00
unknown eadc834bb3 gitmodules: Replace taps with spaces 2019-03-29 18:22:08 +01:00
unknown b4857e326f common/zstd_compression: simplify decompression interface 2019-03-29 18:22:08 +01:00
unknown aa92da205e gl_shader_disk_cache: Fixup clang format 2019-03-29 18:22:08 +01:00
unknown 35ebbbc167 gl_shader_disk_cache: Use Zstandard for compression 2019-03-29 18:22:08 +01:00
unknown 72477731ed common/zstd_compression: Add Zstandard wrapper 2019-03-29 18:22:08 +01:00
unknown ca82589350 common: Link libzstd_static 2019-03-29 18:22:07 +01:00
unknown d85c1141b9 externals: Add libzstd_static to externals CMakeLists.txt 2019-03-29 18:22:07 +01:00
unknown 93de7a7b40 externals: Add Zstandard v1.3.8 2019-03-29 18:22:07 +01:00
unknown a05f94dcc8 Addressed feedback 2019-03-29 18:22:07 +01:00
unknown cec7da37b9 core: Do not link LZ4 to core. Use common/data_compression for nso segment decompression instead. 2019-03-29 18:20:48 +01:00
Zach Hilman 552d5071fa patch_manager: Dump NSO name with build ID 2019-03-27 20:09:01 -04:00
Zach Hilman 41d2565f29 game_list: Register content with ContentProvider 2019-03-26 22:05:37 -04:00
Zach Hilman 60f39060c6 core: Port current uses of RegisteredCache to ContentProvider 2019-03-26 22:05:37 -04:00
Zach Hilman 45cb41f517 core: Store system-wide ContentProvider for the emulator 2019-03-26 22:05:37 -04:00
Zach Hilman a6c7ae6fe8 file_sys: Create ContentProvider interface and default implementations 2019-03-26 22:03:26 -04:00
ReinUsesLisp 9ebc27234d bootmanager: Bypass input focus issues 2019-03-25 17:10:34 -03:00
ReinUsesLisp bbb396d7f1 bootmanager: Bypass resizing issue 2019-03-25 17:10:34 -03:00
ReinUsesLisp 9ff72ca9f2 bootmanager: Delete container to avoid crash on game restarting
While we are at it, remove nullptr checks for deletion, since the C++
standard defines that delete does it by its own
2019-03-25 17:10:34 -03:00
ReinUsesLisp d708d03d20 video_core: Implement API agnostic view based texture cache
Implements an API agnostic texture view based texture cache. Classes
defined here are intended to be inherited by the API implementation and
used in API-specific code.

This implementation exposes protected virtual functions to be called
from the implementer.

Before executing any surface copies methods (defined in API-specific code)
it tries to detect if the overlapping surface is a superset and if it
is, it creates a view. Views are references of a subset of a surface, it
can be a superset view (the same as referencing the whole texture).
Current code manages 1D, 1D array, 2D, 2D array, cube maps and cube map
arrays with layer and mipmap level views. Texture 3D slices views are
not implemented.

If the view attempt fails, the fast path is invoked with the overlapping
textures (defined in the implementer). If that one fails (returning
nullptr) it will flush and reload the texture.
2019-03-22 13:34:04 -03:00
Adityarup Laha 57a4a2ae0f yuzu: Make hotkeys configurable via the GUI
* Adds a new Hotkeys tab in the Controls group.
* Double-click a Hotkey to rebind it.
2019-03-16 03:55:57 +01:00
Dimitri A 0e7ad1c367 gdbstub: Fix some bugs in IsMemoryBreak() and ServeBreak. Add workaround to let watchpoints break into GDB. (#4651)
* gdbstub: fix IsMemoryBreak() returning false while connected to client

As a result, the only existing codepath for a memory watchpoint hit to break into GDB (InterpeterMainLoop, GDB_BP_CHECK, ARMul_State::RecordBreak) is finally taken,
which exposes incorrect logic* in both RecordBreak and ServeBreak.

* a blank BreakpointAddress structure is passed, which sets r15 (PC) to NULL

* gdbstub: DynCom: default-initialize two members/vars used in conditionals

* gdbstub: DynCom: don't record memory watchpoint hits via RecordBreak()

For now, instead check for GDBStub::IsMemoryBreak() in InterpreterMainLoop and ServeBreak.

Fixes PC being set to a stale/unhit breakpoint address (often zero) when a memory watchpoint (rwatch, watch, awatch) is handled in ServeBreak() and generates a GDB trap.

Reasons for removing a call to RecordBreak() for memory watchpoints:
* The``breakpoint_data`` we pass is typed Execute or None. It describes the predicted next code breakpoint hit relative to PC;

* GDBStub::IsMemoryBreak() returns true if a recent Read/Write operation hit a watchpoint. It doesn't specify which in return, nor does it trace it anywhere. Thus, the only data we could give RecordBreak() is a placeholder BreakpointAddress at offset NULL and type Access. I found the idea silly, compared to simply relying on GDBStub::IsMemoryBreak().

There is currently no measure in the code that remembers the addresses (and types) of any watchpoints that were hit by an instruction, in order to send them to GDB as "extended stop information."
I'm considering an implementation for this.

* gdbstub: Change an ASSERT to DEBUG_ASSERT

I have never seen the (Reg[15] == last_bkpt.address) assert fail in practice, even after several weeks of (locally) developping various branches around GDB.  Only leave it inside Debug builds.
2019-03-15 16:31:06 +01:00
James Rowe 5f2d9f282a QT: Hide GLWidget immediately after showing.
With the loading screen merged, we don't want to actually show at this
point, but it still needs to be shown to actually create the context.
Turns out you can just show and hide it immediately and it'll work.
2019-01-21 16:21:44 -07:00
James Rowe f2a2f818b6 SDL Frontend: Add shared context support 2019-01-21 16:00:01 -07:00
James Rowe c6a0ab9792 QT Frontend: Migrate to QOpenGLWindow 2019-01-21 16:00:01 -07:00
163 changed files with 5533 additions and 2001 deletions
+6
View File
@@ -40,3 +40,9 @@
[submodule "Vulkan-Headers"]
path = externals/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers.git
[submodule "externals/zstd"]
path = externals/zstd
url = https://github.com/facebook/zstd
[submodule "sirit"]
path = externals/sirit
url = https://github.com/ReinUsesLisp/sirit
+1 -1
View File
@@ -309,7 +309,7 @@ if (CLANG_FORMAT)
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
if (WIN32)
add_custom_target(clang-format
COMMAND powershell.exe -Command "Get-ChildItem ${SRCS}/* -Include *.cpp,*.h -Recurse | Foreach {${CLANG_FORMAT} -i $_.fullname}"
COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}"
COMMENT ${CCOMMENT})
elseif(MINGW)
add_custom_target(clang-format
+9
View File
@@ -49,6 +49,10 @@ add_subdirectory(open_source_archives EXCLUDE_FROM_ALL)
add_library(unicorn-headers INTERFACE)
target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
# Zstandard
add_subdirectory(zstd/build/cmake EXCLUDE_FROM_ALL)
target_include_directories(libzstd_static INTERFACE ./zstd/lib)
# SoundTouch
add_subdirectory(soundtouch)
@@ -68,6 +72,11 @@ if (USE_DISCORD_PRESENCE)
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
endif()
# Sirit
if (ENABLE_VULKAN)
add_subdirectory(sirit)
endif()
if (ENABLE_WEB_SERVICE)
# LibreSSL
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
Vendored Submodule
+1
Submodule externals/sirit added at f7c4b07a7e
Vendored Submodule
+1
Submodule externals/zstd added at 470344d33e
+3 -1
View File
@@ -125,6 +125,8 @@ add_library(common STATIC
uint128.h
vector_math.h
web_result.h
zstd_compression.cpp
zstd_compression.h
)
if(ARCHITECTURE_x86_64)
@@ -138,4 +140,4 @@ endif()
create_target_directory_groups(common)
target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
target_link_libraries(common PRIVATE lz4_static)
target_link_libraries(common PRIVATE lz4_static libzstd_static)
+4 -4
View File
@@ -8,25 +8,25 @@
namespace Common {
template <typename T>
constexpr T AlignUp(T value, std::size_t size) {
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) noexcept {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value + (size - value % size) % size);
}
template <typename T>
constexpr T AlignDown(T value, std::size_t size) {
[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) noexcept {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value - value % size);
}
template <typename T>
constexpr bool Is4KBAligned(T value) {
[[nodiscard]] constexpr bool Is4KBAligned(T value) noexcept {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return (value & 0xFFF) == 0;
}
template <typename T>
constexpr bool IsWordAligned(T value) {
[[nodiscard]] constexpr bool IsWordAligned(T value) noexcept {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return (value & 0b11) == 0;
}
+18
View File
@@ -57,3 +57,21 @@ __declspec(noinline, noreturn)
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
// If the assert is ignored, execute _b_
#define ASSERT_OR_EXECUTE(_a_, _b_) \
do { \
ASSERT(_a_); \
if (!(_a_)) { \
_b_ \
} \
} while (0)
// If the assert is ignored, execute _b_
#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
do { \
ASSERT_MSG(_a_, __VA_ARGS__); \
if (!(_a_)) { \
_b_ \
} \
} while (0)
+8 -7
View File
@@ -135,8 +135,8 @@ public:
* containing several bitfields can be assembled by formatting each of their values and ORing
* the results together.
*/
static constexpr FORCE_INLINE StorageType FormatValue(const T& value) {
return ((StorageType)value << position) & mask;
[[nodiscard]] static constexpr FORCE_INLINE StorageType FormatValue(const T& value) noexcept {
return (static_cast<StorageType>(value) << position) & mask;
}
/**
@@ -144,7 +144,8 @@ public:
* (such as Value() or operator T), but this can be used to extract a value from a bitfield
* union in a constexpr context.
*/
static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) {
[[nodiscard]] static constexpr FORCE_INLINE T
ExtractValue(const StorageType& storage) noexcept {
if constexpr (std::numeric_limits<UnderlyingType>::is_signed) {
std::size_t shift = 8 * sizeof(T) - bits;
return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >>
@@ -168,19 +169,19 @@ public:
constexpr BitField(BitField&&) noexcept = default;
constexpr BitField& operator=(BitField&&) noexcept = default;
constexpr FORCE_INLINE operator T() const {
[[nodiscard]] constexpr FORCE_INLINE operator T() const noexcept {
return Value();
}
constexpr FORCE_INLINE void Assign(const T& value) {
constexpr FORCE_INLINE void Assign(const T& value) noexcept {
storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value);
}
constexpr T Value() const {
[[nodiscard]] constexpr T Value() const noexcept {
return ExtractValue(storage);
}
constexpr explicit operator bool() const {
[[nodiscard]] constexpr explicit operator bool() const noexcept {
return Value() != 0;
}
+13 -13
View File
@@ -17,12 +17,12 @@ namespace Common {
/// Gets the size of a specified type T in bits.
template <typename T>
constexpr std::size_t BitSize() {
[[nodiscard]] constexpr std::size_t BitSize() noexcept {
return sizeof(T) * CHAR_BIT;
}
#ifdef _MSC_VER
inline u32 CountLeadingZeroes32(u32 value) {
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) noexcept {
unsigned long leading_zero = 0;
if (_BitScanReverse(&leading_zero, value) != 0) {
@@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
return 32;
}
inline u64 CountLeadingZeroes64(u64 value) {
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) noexcept {
unsigned long leading_zero = 0;
if (_BitScanReverse64(&leading_zero, value) != 0) {
@@ -42,25 +42,25 @@ inline u64 CountLeadingZeroes64(u64 value) {
return 64;
}
#else
inline u32 CountLeadingZeroes32(u32 value) {
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) noexcept {
if (value == 0) {
return 32;
}
return __builtin_clz(value);
return static_cast<u32>(__builtin_clz(value));
}
inline u64 CountLeadingZeroes64(u64 value) {
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) noexcept {
if (value == 0) {
return 64;
}
return __builtin_clzll(value);
return static_cast<u32>(__builtin_clzll(value));
}
#endif
#ifdef _MSC_VER
inline u32 CountTrailingZeroes32(u32 value) {
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) noexcept {
unsigned long trailing_zero = 0;
if (_BitScanForward(&trailing_zero, value) != 0) {
@@ -70,7 +70,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
return 32;
}
inline u64 CountTrailingZeroes64(u64 value) {
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) noexcept {
unsigned long trailing_zero = 0;
if (_BitScanForward64(&trailing_zero, value) != 0) {
@@ -80,20 +80,20 @@ inline u64 CountTrailingZeroes64(u64 value) {
return 64;
}
#else
inline u32 CountTrailingZeroes32(u32 value) {
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) noexcept {
if (value == 0) {
return 32;
}
return __builtin_ctz(value);
return static_cast<u32>(__builtin_ctz(value));
}
inline u64 CountTrailingZeroes64(u64 value) {
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) noexcept {
if (value == 0) {
return 64;
}
return __builtin_ctzll(value);
return static_cast<u32>(__builtin_ctzll(value));
}
#endif
+2 -2
View File
@@ -52,11 +52,11 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
// Call directly after the command or use the error num.
// This function might change the error code.
// Defined in Misc.cpp.
std::string GetLastErrorMsg();
[[nodiscard]] std::string GetLastErrorMsg();
namespace Common {
constexpr u32 MakeMagic(char a, char b, char c, char d) {
[[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) noexcept {
return a | b << 8 | c << 16 | d << 24;
}
+27 -25
View File
@@ -46,19 +46,19 @@ struct FSTEntry {
};
// Returns true if file filename exists
bool Exists(const std::string& filename);
[[nodiscard]] bool Exists(const std::string& filename);
// Returns true if filename is a directory
bool IsDirectory(const std::string& filename);
[[nodiscard]] bool IsDirectory(const std::string& filename);
// Returns the size of filename (64bit)
u64 GetSize(const std::string& filename);
[[nodiscard]] u64 GetSize(const std::string& filename);
// Overloaded GetSize, accepts file descriptor
u64 GetSize(const int fd);
[[nodiscard]] u64 GetSize(int fd);
// Overloaded GetSize, accepts FILE*
u64 GetSize(FILE* f);
[[nodiscard]] u64 GetSize(FILE* f);
// Returns true if successful, or path already exists.
bool CreateDir(const std::string& filename);
@@ -118,7 +118,7 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
// Returns the current directory
std::string GetCurrentDir();
[[nodiscard]] std::string GetCurrentDir();
// Create directory and copy contents (does not overwrite existing files)
void CopyDir(const std::string& source_path, const std::string& dest_path);
@@ -128,22 +128,22 @@ bool SetCurrentDir(const std::string& directory);
// Returns a pointer to a string with a yuzu data dir in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
[[nodiscard]] const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
std::string GetHactoolConfigurationPath();
[[nodiscard]] std::string GetHactoolConfigurationPath();
std::string GetNANDRegistrationDir(bool system = false);
[[nodiscard]] std::string GetNANDRegistrationDir(bool system = false);
// Returns the path to where the sys file are
std::string GetSysDirectory();
[[nodiscard]] std::string GetSysDirectory();
#ifdef __APPLE__
std::string GetBundleDirectory();
[[nodiscard]] std::string GetBundleDirectory();
#endif
#ifdef _WIN32
const std::string& GetExeDirectory();
std::string AppDataRoamingDirectory();
[[nodiscard]] const std::string& GetExeDirectory();
[[nodiscard]] std::string AppDataRoamingDirectory();
#endif
std::size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename);
@@ -162,26 +162,27 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
// Splits the path on '/' or '\' and put the components into a vector
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
std::vector<std::string> SplitPathComponents(std::string_view filename);
[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
// Gets all of the text up to the last '/' or '\' in the path.
std::string_view GetParentPath(std::string_view path);
[[nodiscard]] std::string_view GetParentPath(std::string_view path);
// Gets all of the text after the first '/' or '\' in the path.
std::string_view GetPathWithoutTop(std::string_view path);
[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
// Gets the filename of the path
std::string_view GetFilename(std::string_view path);
[[nodiscard]] std::string_view GetFilename(std::string_view path);
// Gets the extension of the filename
std::string_view GetExtensionFromFilename(std::string_view name);
[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name);
// Removes the final '/' or '\' if one exists
std::string_view RemoveTrailingSlash(std::string_view path);
[[nodiscard]] std::string_view RemoveTrailingSlash(std::string_view path);
// Creates a new vector containing indices [first, last) from the original.
template <typename T>
std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first, std::size_t last) {
[[nodiscard]] std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first,
std::size_t last) {
if (first >= last)
return {};
last = std::min<std::size_t>(last, vector.size());
@@ -192,8 +193,9 @@ enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault };
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
std::string SanitizePath(std::string_view path,
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
[[nodiscard]] std::string SanitizePath(
std::string_view path,
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
// simple wrapper for cstdlib file functions to
// hopefully will make error checking easier
@@ -261,13 +263,13 @@ public:
return WriteArray(str.c_str(), str.length());
}
bool IsOpen() const {
[[nodiscard]] bool IsOpen() const {
return nullptr != m_file;
}
bool Seek(s64 off, int origin) const;
u64 Tell() const;
u64 GetSize() const;
[[nodiscard]] u64 Tell() const;
[[nodiscard]] u64 GetSize() const;
bool Resize(u64 size);
bool Flush();
+7 -7
View File
@@ -13,12 +13,12 @@
namespace Common {
u8 ToHexNibble(char c1);
[[nodiscard]] u8 ToHexNibble(char c1);
std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
template <std::size_t Size, bool le = false>
std::array<u8, Size> HexStringToArray(std::string_view str) {
[[nodiscard]] std::array<u8, Size> HexStringToArray(std::string_view str) {
std::array<u8, Size> out{};
if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2)
@@ -30,17 +30,17 @@ std::array<u8, Size> HexStringToArray(std::string_view str) {
return out;
}
std::string HexVectorToString(const std::vector<u8>& vector, bool upper = true);
[[nodiscard]] std::string HexVectorToString(const std::vector<u8>& vector, bool upper = true);
template <std::size_t Size>
std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) {
[[nodiscard]] std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) {
std::string out;
for (u8 c : array)
out += fmt::format(upper ? "{:02X}" : "{:02x}", c);
return out;
}
std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len);
std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len);
[[nodiscard]] std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len);
[[nodiscard]] std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len);
} // namespace Common
+17 -12
View File
@@ -46,7 +46,7 @@ public:
virtual void SetFilter(const Filter& new_filter) {
filter = new_filter;
}
virtual const char* GetName() const = 0;
[[nodiscard]] virtual const char* GetName() const = 0;
virtual void Write(const Entry& entry) = 0;
private:
@@ -58,12 +58,14 @@ private:
*/
class ConsoleBackend : public Backend {
public:
static const char* Name() {
[[nodiscard]] static const char* Name() {
return "console";
}
const char* GetName() const override {
[[nodiscard]] const char* GetName() const override {
return Name();
}
void Write(const Entry& entry) override;
};
@@ -72,13 +74,14 @@ public:
*/
class ColorConsoleBackend : public Backend {
public:
static const char* Name() {
[[nodiscard]] static const char* Name() {
return "color_console";
}
const char* GetName() const override {
[[nodiscard]] const char* GetName() const override {
return Name();
}
void Write(const Entry& entry) override;
};
@@ -89,11 +92,11 @@ class FileBackend : public Backend {
public:
explicit FileBackend(const std::string& filename);
static const char* Name() {
[[nodiscard]] static const char* Name() {
return "file";
}
const char* GetName() const override {
[[nodiscard]] const char* GetName() const override {
return Name();
}
@@ -109,12 +112,14 @@ private:
*/
class DebuggerBackend : public Backend {
public:
static const char* Name() {
[[nodiscard]] static const char* Name() {
return "debugger";
}
const char* GetName() const override {
[[nodiscard]] const char* GetName() const override {
return Name();
}
void Write(const Entry& entry) override;
};
@@ -122,18 +127,18 @@ void AddBackend(std::unique_ptr<Backend> backend);
void RemoveBackend(std::string_view backend_name);
Backend* GetBackend(std::string_view backend_name);
[[nodiscard]] Backend* GetBackend(std::string_view backend_name);
/**
* Returns the name of the passed log class as a C-string. Subclasses are separated by periods
* instead of underscores as in the enumeration.
*/
const char* GetLogClassName(Class log_class);
[[nodiscard]] const char* GetLogClassName(Class log_class);
/**
* Returns the name of the passed log level as a C-string.
*/
const char* GetLevelName(Level log_level);
[[nodiscard]] const char* GetLevelName(Level log_level);
/**
* The global filter will prevent any messages from even being processed if they are filtered. Each
+2 -2
View File
@@ -43,10 +43,10 @@ public:
void ParseFilterString(std::string_view filter_view);
/// Matches class/level combination against the filter, returning true if it passed.
bool CheckMessage(Class log_class, Level level) const;
[[nodiscard]] bool CheckMessage(Class log_class, Level level) const;
/// Returns true if any logging classes are set to debug
bool IsDebug() const;
[[nodiscard]] bool IsDebug() const;
private:
std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels;
+1 -1
View File
@@ -12,7 +12,7 @@ namespace Log {
struct Entry;
/// Formats a log entry into the provided text buffer.
std::string FormatLogMessage(const Entry& entry);
[[nodiscard]] std::string FormatLogMessage(const Entry& entry);
/// Formats and prints a log entry to stderr.
void PrintMessage(const Entry& entry);
/// Prints the same message as `PrintMessage`, but colored according to the severity level.
+6 -4
View File
@@ -16,7 +16,7 @@ namespace Common::Compression {
*
* @return the compressed data.
*/
std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
[[nodiscard]] std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
/**
* Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
@@ -30,7 +30,8 @@ std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
*
* @return the compressed data.
*/
std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level);
[[nodiscard]] std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
s32 compression_level);
/**
* Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
@@ -40,7 +41,7 @@ std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32
*
* @return the compressed data.
*/
std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
[[nodiscard]] std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
/**
* Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
@@ -50,6 +51,7 @@ std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
*
* @return the decompressed data.
*/
std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size);
[[nodiscard]] std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
std::size_t uncompressed_size);
} // namespace Common::Compression
+7 -7
View File
@@ -18,24 +18,24 @@ struct Rectangle {
T right{};
T bottom{};
constexpr Rectangle() = default;
constexpr Rectangle() noexcept = default;
constexpr Rectangle(T left, T top, T right, T bottom)
constexpr Rectangle(T left, T top, T right, T bottom) noexcept
: left(left), top(top), right(right), bottom(bottom) {}
T GetWidth() const {
[[nodiscard]] T GetWidth() const noexcept {
return std::abs(static_cast<std::make_signed_t<T>>(right - left));
}
T GetHeight() const {
[[nodiscard]] T GetHeight() const noexcept {
return std::abs(static_cast<std::make_signed_t<T>>(bottom - top));
}
Rectangle<T> TranslateX(const T x) const {
[[nodiscard]] Rectangle<T> TranslateX(const T x) const noexcept {
return Rectangle{left + x, top, right + x, bottom};
}
Rectangle<T> TranslateY(const T y) const {
[[nodiscard]] Rectangle<T> TranslateY(const T y) const noexcept {
return Rectangle{left, top + y, right, bottom + y};
}
Rectangle<T> Scale(const float s) const {
[[nodiscard]] Rectangle<T> Scale(const float s) const noexcept {
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
static_cast<T>(top + GetHeight() * s)};
}
+12 -11
View File
@@ -26,21 +26,22 @@ class MemoryHook {
public:
virtual ~MemoryHook();
virtual std::optional<bool> IsValidAddress(VAddr addr) = 0;
[[nodiscard]] virtual std::optional<bool> IsValidAddress(VAddr addr) = 0;
virtual std::optional<u8> Read8(VAddr addr) = 0;
virtual std::optional<u16> Read16(VAddr addr) = 0;
virtual std::optional<u32> Read32(VAddr addr) = 0;
virtual std::optional<u64> Read64(VAddr addr) = 0;
[[nodiscard]] virtual std::optional<u8> Read8(VAddr addr) = 0;
[[nodiscard]] virtual std::optional<u16> Read16(VAddr addr) = 0;
[[nodiscard]] virtual std::optional<u32> Read32(VAddr addr) = 0;
[[nodiscard]] virtual std::optional<u64> Read64(VAddr addr) = 0;
virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0;
[[nodiscard]] virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0;
virtual bool Write8(VAddr addr, u8 data) = 0;
virtual bool Write16(VAddr addr, u16 data) = 0;
virtual bool Write32(VAddr addr, u32 data) = 0;
virtual bool Write64(VAddr addr, u64 data) = 0;
[[nodiscard]] virtual bool Write8(VAddr addr, u8 data) = 0;
[[nodiscard]] virtual bool Write16(VAddr addr, u16 data) = 0;
[[nodiscard]] virtual bool Write32(VAddr addr, u32 data) = 0;
[[nodiscard]] virtual bool Write64(VAddr addr, u64 data) = 0;
virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0;
[[nodiscard]] virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer,
std::size_t size) = 0;
};
using MemoryHookPointer = std::shared_ptr<MemoryHook>;
+27 -26
View File
@@ -43,21 +43,21 @@ public:
using reference = std::conditional_t<is_constant, const T&, T&>;
using difference_type = typename std::pointer_traits<pointer>::difference_type;
friend bool operator==(const iterator_impl& lhs, const iterator_impl& rhs) {
[[nodiscard]] friend bool operator==(const iterator_impl& lhs, const iterator_impl& rhs) {
if (lhs.IsEnd() && rhs.IsEnd())
return true;
return std::tie(lhs.current_priority, lhs.it) == std::tie(rhs.current_priority, rhs.it);
}
friend bool operator!=(const iterator_impl& lhs, const iterator_impl& rhs) {
[[nodiscard]] friend bool operator!=(const iterator_impl& lhs, const iterator_impl& rhs) {
return !operator==(lhs, rhs);
}
reference operator*() const {
[[nodiscard]] reference operator*() const {
return *it;
}
pointer operator->() const {
[[nodiscard]] pointer operator->() const {
return it.operator->();
}
@@ -72,7 +72,7 @@ public:
u64 prios = mlq.used_priorities;
prios &= ~((1ULL << (current_priority + 1)) - 1);
if (prios == 0) {
current_priority = mlq.depth();
current_priority = static_cast<u32>(mlq.depth());
} else {
current_priority = CountTrailingZeroes64(prios);
it = GetBeginItForPrio();
@@ -143,15 +143,15 @@ public:
explicit iterator_impl(container_ref mlq, u32 current_priority)
: mlq(mlq), it(), current_priority(current_priority) {}
bool IsEnd() const {
[[nodiscard]] bool IsEnd() const {
return current_priority == mlq.depth();
}
list_iterator GetBeginItForPrio() const {
[[nodiscard]] list_iterator GetBeginItForPrio() const {
return mlq.levels[current_priority].begin();
}
list_iterator GetEndItForPrio() const {
[[nodiscard]] list_iterator GetEndItForPrio() const {
return mlq.levels[current_priority].end();
}
@@ -223,15 +223,15 @@ public:
ListShiftForward(levels[priority], n);
}
std::size_t depth() const {
[[nodiscard]] std::size_t depth() const {
return Depth;
}
std::size_t size(u32 priority) const {
[[nodiscard]] std::size_t size(u32 priority) const {
return levels[priority].size();
}
std::size_t size() const {
[[nodiscard]] std::size_t size() const {
u64 priorities = used_priorities;
std::size_t size = 0;
while (priorities != 0) {
@@ -242,64 +242,64 @@ public:
return size;
}
bool empty() const {
[[nodiscard]] bool empty() const {
return used_priorities == 0;
}
bool empty(u32 priority) const {
[[nodiscard]] bool empty(u32 priority) const {
return (used_priorities & (1ULL << priority)) == 0;
}
u32 highest_priority_set(u32 max_priority = 0) const {
[[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const {
const u64 priorities =
max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1));
return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities));
}
u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
[[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
const u64 priorities = min_priority >= Depth - 1
? used_priorities
: (used_priorities & ((1ULL << (min_priority + 1)) - 1));
return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities);
}
const_iterator cbegin(u32 max_prio = 0) const {
[[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const {
const u32 priority = highest_priority_set(max_prio);
return priority == Depth ? cend()
: const_iterator{*this, levels[priority].cbegin(), priority};
}
const_iterator begin(u32 max_prio = 0) const {
[[nodiscard]] const_iterator begin(u32 max_prio = 0) const {
return cbegin(max_prio);
}
iterator begin(u32 max_prio = 0) {
[[nodiscard]] iterator begin(u32 max_prio = 0) {
const u32 priority = highest_priority_set(max_prio);
return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority};
}
const_iterator cend(u32 min_prio = Depth - 1) const {
[[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const {
return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1);
}
const_iterator end(u32 min_prio = Depth - 1) const {
[[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const {
return cend(min_prio);
}
iterator end(u32 min_prio = Depth - 1) {
[[nodiscard]] iterator end(u32 min_prio = Depth - 1) {
return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1);
}
T& front(u32 max_priority = 0) {
[[nodiscard]] T& front(u32 max_priority = 0) {
const u32 priority = highest_priority_set(max_priority);
return levels[priority == Depth ? 0 : priority].front();
}
const T& front(u32 max_priority = 0) const {
[[nodiscard]] const T& front(u32 max_priority = 0) const {
const u32 priority = highest_priority_set(max_priority);
return levels[priority == Depth ? 0 : priority].front();
}
T back(u32 min_priority = Depth - 1) {
[[nodiscard]] T back(u32 min_priority = Depth - 1) {
const u32 priority = lowest_priority_set(min_priority); // intended
return levels[priority == Depth ? 63 : priority].back();
}
const T& back(u32 min_priority = Depth - 1) const {
[[nodiscard]] const T& back(u32 min_priority = Depth - 1) const {
const u32 priority = lowest_priority_set(min_priority); // intended
return levels[priority == Depth ? 63 : priority].back();
}
@@ -322,7 +322,8 @@ private:
in_list.splice(position, out_list, element);
}
static const_list_iterator ListIterateTo(const std::list<T>& list, const T& element) {
[[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list,
const T& element) {
auto it = list.cbegin();
while (it != list.cend() && *it != element) {
++it;
+2 -2
View File
@@ -33,11 +33,11 @@ struct SpecialRegion {
MemoryHookPointer handler;
bool operator<(const SpecialRegion& other) const {
[[nodiscard]] bool operator<(const SpecialRegion& other) const {
return std::tie(type, handler) < std::tie(other.type, other.handler);
}
bool operator==(const SpecialRegion& other) const {
[[nodiscard]] bool operator==(const SpecialRegion& other) const {
return std::tie(type, handler) == std::tie(other.type, other.handler);
}
};
+5 -5
View File
@@ -24,14 +24,14 @@ public:
ParamPackage& operator=(const ParamPackage& other) = default;
ParamPackage& operator=(ParamPackage&& other) = default;
std::string Serialize() const;
std::string Get(const std::string& key, const std::string& default_value) const;
int Get(const std::string& key, int default_value) const;
float Get(const std::string& key, float default_value) const;
[[nodiscard]] std::string Serialize() const;
[[nodiscard]] std::string Get(const std::string& key, const std::string& default_value) const;
[[nodiscard]] int Get(const std::string& key, int default_value) const;
[[nodiscard]] float Get(const std::string& key, float default_value) const;
void Set(const std::string& key, std::string value);
void Set(const std::string& key, int value);
void Set(const std::string& key, float value);
bool Has(const std::string& key) const;
[[nodiscard]] bool Has(const std::string& key) const;
void Erase(const std::string& key);
void Clear();
+11 -7
View File
@@ -14,35 +14,39 @@ public:
Vec3<T> xyz;
T w{};
Quaternion<decltype(-T{})> Inverse() const {
[[nodiscard]] Quaternion<decltype(-T{})> Inverse() const noexcept {
return {-xyz, w};
}
Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
[[nodiscard]] Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const
noexcept {
return {xyz + other.xyz, w + other.w};
}
Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
[[nodiscard]] Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const
noexcept {
return {xyz - other.xyz, w - other.w};
}
Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(const Quaternion& other) const {
[[nodiscard]] Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(
const Quaternion& other) const noexcept {
return {xyz * other.w + other.xyz * w + Cross(xyz, other.xyz),
w * other.w - Dot(xyz, other.xyz)};
}
Quaternion<T> Normalized() const {
[[nodiscard]] Quaternion<T> Normalized() const noexcept {
T length = std::sqrt(xyz.Length2() + w * w);
return {xyz / length, w / length};
}
};
template <typename T>
auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
[[nodiscard]] auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) noexcept {
return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
}
inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
[[nodiscard]] inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis,
float angle) noexcept {
return {axis * std::sin(angle / 2), std::cos(angle / 2)};
}
+4 -4
View File
@@ -64,7 +64,7 @@ public:
/// @param output Where to store the popped slots
/// @param max_slots Maximum number of slots to pop
/// @returns The number of slots actually popped
std::size_t Pop(void* output, std::size_t max_slots = ~std::size_t(0)) {
[[nodiscard]] std::size_t Pop(void* output, std::size_t max_slots = ~std::size_t(0)) {
const std::size_t read_index = m_read_index.load();
const std::size_t slots_filled = m_write_index.load() - read_index;
const std::size_t pop_count = std::min(slots_filled, max_slots);
@@ -83,7 +83,7 @@ public:
return pop_count;
}
std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) {
[[nodiscard]] std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) {
std::vector<T> out(std::min(max_slots, capacity) * granularity);
const std::size_t count = Pop(out.data(), out.size() / granularity);
out.resize(count * granularity);
@@ -91,12 +91,12 @@ public:
}
/// @returns Number of slots used
std::size_t Size() const {
[[nodiscard]] std::size_t Size() const {
return m_write_index.load() - m_read_index.load();
}
/// @returns Maximum size of ring buffer
constexpr std::size_t Capacity() const {
[[nodiscard]] constexpr std::size_t Capacity() const {
return capacity;
}
+1 -1
View File
@@ -20,7 +20,7 @@ struct ScopeExitHelper {
template <typename Func>
ScopeExitHelper<Func> ScopeExit(Func&& func) {
return ScopeExitHelper<Func>(std::move(func));
return ScopeExitHelper<Func>(std::forward<Func>(func));
}
} // namespace detail
+19 -18
View File
@@ -12,19 +12,19 @@
namespace Common {
/// Make a string lowercase
std::string ToLower(std::string str);
[[nodiscard]] std::string ToLower(std::string str);
/// Make a string uppercase
std::string ToUpper(std::string str);
[[nodiscard]] std::string ToUpper(std::string str);
std::string StringFromBuffer(const std::vector<u8>& data);
[[nodiscard]] std::string StringFromBuffer(const std::vector<u8>& data);
std::string StripSpaces(const std::string& s);
std::string StripQuotes(const std::string& s);
[[nodiscard]] std::string StripSpaces(const std::string& s);
[[nodiscard]] std::string StripQuotes(const std::string& s);
std::string StringFromBool(bool value);
[[nodiscard]] std::string StringFromBool(bool value);
std::string TabsToSpaces(int tab_size, std::string in);
[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in);
void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
@@ -34,15 +34,15 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
const std::string& _Filename);
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest);
[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
const std::string& dest);
std::string UTF16ToUTF8(const std::u16string& input);
std::u16string UTF8ToUTF16(const std::string& input);
[[nodiscard]] std::string UTF16ToUTF8(const std::u16string& input);
[[nodiscard]] std::u16string UTF8ToUTF16(const std::string& input);
#ifdef _WIN32
std::string UTF16ToUTF8(const std::wstring& input);
std::wstring UTF8ToUTF16W(const std::string& str);
[[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);
[[nodiscard]] std::wstring UTF8ToUTF16W(const std::string& str);
#endif
/**
@@ -50,7 +50,7 @@ std::wstring UTF8ToUTF16W(const std::string& str);
* `other` for equality.
*/
template <typename InIt>
bool ComparePartialString(InIt begin, InIt end, const char* other) {
[[nodiscard]] bool ComparePartialString(InIt begin, InIt end, const char* other) {
for (; begin != end && *other != '\0'; ++begin, ++other) {
if (*begin != *other) {
return false;
@@ -64,15 +64,16 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
* Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
* NUL-terminated then the string ends at max_len characters.
*/
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len);
[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(const char* buffer,
std::size_t max_len);
/**
* Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
* null-terminated, then the string ends at the greatest multiple of two less then or equal to
* max_len_bytes.
*/
std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
std::size_t max_len);
[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
std::size_t max_len);
/**
* Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
@@ -84,6 +85,6 @@ std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buff
* including the last occurrence of this name will be stripped
* @return A pointer to the same string passed as `path`, but starting at the trimmed portion
*/
const char* TrimSourcePath(const char* path, const char* root = "src");
[[nodiscard]] const char* TrimSourcePath(const char* path, const char* root = "src");
} // namespace Common
+27 -69
View File
@@ -21,11 +21,6 @@
#if defined(_MSC_VER)
#include <cstdlib>
#elif defined(__linux__)
#include <byteswap.h>
#elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/endian.h>
#endif
#include <cstring>
#include "common/common_types.h"
@@ -62,86 +57,49 @@
namespace Common {
#ifdef _MSC_VER
inline u16 swap16(u16 _data) {
return _byteswap_ushort(_data);
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
return _byteswap_ushort(data);
}
inline u32 swap32(u32 _data) {
return _byteswap_ulong(_data);
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
return _byteswap_ulong(data);
}
inline u64 swap64(u64 _data) {
return _byteswap_uint64(_data);
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
return _byteswap_uint64(data);
}
#elif defined(ARCHITECTURE_ARM) && (__ARM_ARCH >= 6)
inline u16 swap16(u16 _data) {
u32 data = _data;
__asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data));
return (u16)data;
}
inline u32 swap32(u32 _data) {
__asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data));
return _data;
}
inline u64 swap64(u64 _data) {
return ((u64)swap32(_data) << 32) | swap32(_data >> 32);
}
#elif __linux__
inline u16 swap16(u16 _data) {
return bswap_16(_data);
}
inline u32 swap32(u32 _data) {
return bswap_32(_data);
}
inline u64 swap64(u64 _data) {
return bswap_64(_data);
}
#elif __APPLE__
inline __attribute__((always_inline)) u16 swap16(u16 _data) {
return (_data >> 8) | (_data << 8);
}
inline __attribute__((always_inline)) u32 swap32(u32 _data) {
return __builtin_bswap32(_data);
}
inline __attribute__((always_inline)) u64 swap64(u64 _data) {
return __builtin_bswap64(_data);
}
#elif defined(__Bitrig__) || defined(__OpenBSD__)
#elif defined(__clang__) || defined(__GNUC__)
#if defined(__Bitrig__) || defined(__OpenBSD__)
// redefine swap16, swap32, swap64 as inline functions
#undef swap16
#undef swap32
#undef swap64
inline u16 swap16(u16 _data) {
return __swap16(_data);
#endif
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
return __builtin_bswap16(data);
}
inline u32 swap32(u32 _data) {
return __swap32(_data);
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
return __builtin_bswap32(data);
}
inline u64 swap64(u64 _data) {
return __swap64(_data);
}
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
inline u16 swap16(u16 _data) {
return bswap16(_data);
}
inline u32 swap32(u32 _data) {
return bswap32(_data);
}
inline u64 swap64(u64 _data) {
return bswap64(_data);
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
return __builtin_bswap64(data);
}
#else
// Slow generic implementation.
inline u16 swap16(u16 data) {
// Generic implementation.
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
return (data >> 8) | (data << 8);
}
inline u32 swap32(u32 data) {
return (swap16(data) << 16) | swap16(data >> 16);
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
return ((data & 0xFF000000U) >> 24) | ((data & 0x00FF0000U) >> 8) |
((data & 0x0000FF00U) << 8) | ((data & 0x000000FFU) << 24);
}
inline u64 swap64(u64 data) {
return ((u64)swap32(data) << 32) | swap32(data >> 32);
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
return ((data & 0xFF00000000000000ULL) >> 56) | ((data & 0x00FF000000000000ULL) >> 40) |
((data & 0x0000FF0000000000ULL) >> 24) | ((data & 0x000000FF00000000ULL) >> 8) |
((data & 0x00000000FF000000ULL) << 8) | ((data & 0x0000000000FF0000ULL) << 24) |
((data & 0x000000000000FF00ULL) << 40) | ((data & 0x00000000000000FFULL) << 56);
}
#endif
inline float swapf(float f) {
[[nodiscard]] inline float swapf(float f) noexcept {
static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
u32 value;
@@ -153,7 +111,7 @@ inline float swapf(float f) {
return f;
}
inline double swapd(double f) {
[[nodiscard]] inline double swapd(double f) noexcept {
static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
u64 value;
+6 -6
View File
@@ -42,7 +42,7 @@ public:
* Gets the name of this field.
* @returns Name of this field as a string.
*/
virtual const std::string& GetName() const = 0;
[[nodiscard]] virtual const std::string& GetName() const = 0;
};
/**
@@ -63,29 +63,29 @@ public:
void Accept(VisitorInterface& visitor) const override;
const std::string& GetName() const override {
[[nodiscard]] const std::string& GetName() const override {
return name;
}
/**
* Returns the type of the field.
*/
FieldType GetType() const {
[[nodiscard]] FieldType GetType() const {
return type;
}
/**
* Returns the value of the field.
*/
const T& GetValue() const {
[[nodiscard]] const T& GetValue() const {
return value;
}
bool operator==(const Field& other) const {
[[nodiscard]] bool operator==(const Field& other) const {
return (type == other.type) && (name == other.name) && (value == other.value);
}
bool operator!=(const Field& other) const {
[[nodiscard]] bool operator!=(const Field& other) const {
return !(*this == other);
}
+1 -1
View File
@@ -29,7 +29,7 @@ public:
}
template <class Clock, class Duration>
bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
[[nodiscard]] bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
std::unique_lock lk{mutex};
if (!condvar.wait_until(lk, time, [this] { return is_set; }))
return false;
+4 -4
View File
@@ -25,7 +25,7 @@ struct ThreadQueueList {
}
// Only for debugging, returns priority level.
Priority contains(const T& uid) const {
[[nodiscard]] Priority contains(const T& uid) const {
for (Priority i = 0; i < NUM_QUEUES; ++i) {
const Queue& cur = queues[i];
if (std::find(cur.data.cbegin(), cur.data.cend(), uid) != cur.data.cend()) {
@@ -36,7 +36,7 @@ struct ThreadQueueList {
return -1;
}
T get_first() const {
[[nodiscard]] T get_first() const {
const Queue* cur = first;
while (cur != nullptr) {
if (!cur->data.empty()) {
@@ -49,7 +49,7 @@ struct ThreadQueueList {
}
template <typename UnaryPredicate>
T get_first_filter(UnaryPredicate filter) const {
[[nodiscard]] T get_first_filter(UnaryPredicate filter) const {
const Queue* cur = first;
while (cur != nullptr) {
if (!cur->data.empty()) {
@@ -129,7 +129,7 @@ struct ThreadQueueList {
first = nullptr;
}
bool empty(Priority priority) const {
[[nodiscard]] bool empty(Priority priority) const {
const Queue* cur = &queues[priority];
return cur->data.empty();
}
+6 -6
View File
@@ -25,15 +25,15 @@ public:
delete read_ptr;
}
std::size_t Size() const {
[[nodiscard]] std::size_t Size() const {
return size.load();
}
bool Empty() const {
[[nodiscard]] bool Empty() const {
return Size() == 0;
}
T& Front() const {
[[nodiscard]] T& Front() const {
return read_ptr->current;
}
@@ -123,15 +123,15 @@ private:
template <typename T>
class MPSCQueue {
public:
std::size_t Size() const {
[[nodiscard]] std::size_t Size() const {
return spsc_queue.Size();
}
bool Empty() const {
[[nodiscard]] bool Empty() const {
return spsc_queue.Empty();
}
T& Front() const {
[[nodiscard]] T& Front() const {
return spsc_queue.Front();
}
+8 -8
View File
@@ -19,18 +19,18 @@ public:
// The time difference is always returned in milliseconds, regardless of alternative internal
// representation
std::chrono::milliseconds GetTimeDifference();
[[nodiscard]] std::chrono::milliseconds GetTimeDifference();
void AddTimeDifference();
static std::chrono::seconds GetTimeSinceJan1970();
static std::chrono::seconds GetLocalTimeSinceJan1970();
static double GetDoubleTime();
[[nodiscard]] static std::chrono::seconds GetTimeSinceJan1970();
[[nodiscard]] static std::chrono::seconds GetLocalTimeSinceJan1970();
[[nodiscard]] static double GetDoubleTime();
static std::string GetTimeFormatted();
std::string GetTimeElapsedFormatted() const;
std::chrono::milliseconds GetTimeElapsed();
[[nodiscard]] static std::string GetTimeFormatted();
[[nodiscard]] std::string GetTimeElapsedFormatted() const;
[[nodiscard]] std::chrono::milliseconds GetTimeElapsed();
static std::chrono::milliseconds GetTimeMs();
[[nodiscard]] static std::chrono::milliseconds GetTimeMs();
private:
std::chrono::milliseconds m_LastTime;
+2 -2
View File
@@ -12,7 +12,7 @@
namespace Common {
u128 Multiply64Into128(u64 a, u64 b) {
u128 Multiply64Into128(u64 a, u64 b) noexcept {
u128 result;
#ifdef _MSC_VER
result[0] = _umul128(a, b, &result[1]);
@@ -24,7 +24,7 @@ u128 Multiply64Into128(u64 a, u64 b) {
return result;
}
std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) {
std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) noexcept {
u64 remainder = dividend[0] % divisor;
u64 accum = dividend[0] / divisor;
if (dividend[1] == 0)
+2 -2
View File
@@ -10,10 +10,10 @@
namespace Common {
// This function multiplies 2 u64 values and produces a u128 value;
u128 Multiply64Into128(u64 a, u64 b);
[[nodiscard]] u128 Multiply64Into128(u64 a, u64 b) noexcept;
// This function divides a u128 by a u32 value and produces two u64 values:
// the result of division and the remainder
std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
[[nodiscard]] std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) noexcept;
} // namespace Common
+53
View File
@@ -0,0 +1,53 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <algorithm>
#include <zstd.h>
#include "common/assert.h"
#include "common/zstd_compression.h"
namespace Common::Compression {
std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level) {
compression_level = std::clamp(compression_level, 1, ZSTD_maxCLevel());
const std::size_t max_compressed_size = ZSTD_compressBound(source_size);
std::vector<u8> compressed(max_compressed_size);
const std::size_t compressed_size =
ZSTD_compress(compressed.data(), compressed.size(), source, source_size, compression_level);
if (ZSTD_isError(compressed_size)) {
// Compression failed
return {};
}
compressed.resize(compressed_size);
return compressed;
}
std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size) {
return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT);
}
std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) {
const std::size_t decompressed_size =
ZSTD_getDecompressedSize(compressed.data(), compressed.size());
std::vector<u8> decompressed(decompressed_size);
const std::size_t uncompressed_result_size = ZSTD_decompress(
decompressed.data(), decompressed.size(), compressed.data(), compressed.size());
if (decompressed_size != uncompressed_result_size || ZSTD_isError(uncompressed_result_size)) {
// Decompression failed
return {};
}
return decompressed;
}
} // namespace Common::Compression
+43
View File
@@ -0,0 +1,43 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <vector>
#include "common/common_types.h"
namespace Common::Compression {
/**
* Compresses a source memory region with Zstandard and returns the compressed data in a vector.
*
* @param source the uncompressed source memory region.
* @param source_size the size in bytes of the uncompressed source memory region.
* @param compression_level the used compression level. Should be between 1 and 22.
*
* @return the compressed data.
*/
[[nodiscard]] std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size,
s32 compression_level);
/**
* Compresses a source memory region with Zstandard with the default compression level and returns
* the compressed data in a vector.
*
* @param source the uncompressed source memory region.
* @param source_size the size in bytes of the uncompressed source memory region.
*
* @return the compressed data.
*/
[[nodiscard]] std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
/**
* Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
*
* @param compressed the compressed source memory region.
*
* @return the decompressed data.
*/
[[nodiscard]] std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
} // namespace Common::Compression
+9 -10
View File
@@ -14,6 +14,7 @@
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/vm_manager.h"
@@ -99,7 +100,7 @@ public:
}
void CallSVC(u32 swi) override {
Kernel::CallSVC(swi);
Kernel::CallSVC(parent.system, swi);
}
void AddTicks(u64 ticks) override {
@@ -112,14 +113,14 @@ public:
// Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1);
parent.core_timing.AddTicks(amortized_ticks);
parent.system.CoreTiming().AddTicks(amortized_ticks);
num_interpreted_instructions = 0;
}
u64 GetTicksRemaining() override {
return std::max(parent.core_timing.GetDowncount(), 0);
return std::max(parent.system.CoreTiming().GetDowncount(), 0);
}
u64 GetCNTPCT() override {
return Timing::CpuCyclesToClockCycles(parent.core_timing.GetTicks());
return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks());
}
ARM_Dynarmic& parent;
@@ -129,7 +130,7 @@ public:
};
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
auto* current_process = Core::CurrentProcess();
auto* current_process = system.Kernel().CurrentProcess();
auto** const page_table = current_process->VMManager().page_table.pointers.data();
Dynarmic::A64::UserConfig config;
@@ -163,7 +164,6 @@ MICROPROFILE_DEFINE(ARM_Jit_Dynarmic, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)
void ARM_Dynarmic::Run() {
MICROPROFILE_SCOPE(ARM_Jit_Dynarmic);
ASSERT(Memory::GetCurrentPageTable() == current_page_table);
jit->Run();
}
@@ -172,10 +172,10 @@ void ARM_Dynarmic::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
}
ARM_Dynarmic::ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index)
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{core_timing},
core_index{core_index}, core_timing{core_timing},
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
core_index{core_index}, system{system},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {
ThreadContext ctx{};
inner_unicorn.SaveContext(ctx);
@@ -278,7 +278,6 @@ void ARM_Dynarmic::ClearExclusiveState() {
void ARM_Dynarmic::PageTableChanged() {
jit = MakeJit();
current_page_table = Memory::GetCurrentPageTable();
}
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
+3 -13
View File
@@ -12,23 +12,15 @@
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
namespace Common {
struct PageTable;
}
namespace Core::Timing {
class CoreTiming;
}
namespace Core {
class ARM_Dynarmic_Callbacks;
class DynarmicExclusiveMonitor;
class System;
class ARM_Dynarmic final : public ARM_Interface {
public:
ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index);
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,
@@ -67,10 +59,8 @@ private:
ARM_Unicorn inner_unicorn;
std::size_t core_index;
Timing::CoreTiming& core_timing;
System& system;
DynarmicExclusiveMonitor& exclusive_monitor;
Common::PageTable* current_page_table = nullptr;
};
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
+22 -20
View File
@@ -10,7 +10,6 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
namespace Core {
@@ -49,20 +48,6 @@ static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_
}
}
static void InterruptHook(uc_engine* uc, u32 intNo, void* user_data) {
u32 esr{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
auto ec = esr >> 26;
auto iss = esr & 0xFFFFFF;
switch (ec) {
case 0x15: // SVC
Kernel::CallSVC(iss);
break;
}
}
static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
void* user_data) {
ARM_Interface::ThreadContext ctx{};
@@ -72,7 +57,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
return {};
}
ARM_Unicorn::ARM_Unicorn(Timing::CoreTiming& core_timing) : core_timing{core_timing} {
ARM_Unicorn::ARM_Unicorn(System& system) : system{system} {
CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
auto fpv = 3 << 20;
@@ -177,7 +162,7 @@ void ARM_Unicorn::Run() {
if (GDBStub::IsServerEnabled()) {
ExecuteInstructions(std::max(4000000, 0));
} else {
ExecuteInstructions(std::max(core_timing.GetDowncount(), 0));
ExecuteInstructions(std::max(system.CoreTiming().GetDowncount(), 0));
}
}
@@ -190,14 +175,15 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
core_timing.AddTicks(num_instructions);
system.CoreTiming().AddTicks(num_instructions);
if (GDBStub::IsServerEnabled()) {
if (last_bkpt_hit) {
if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
}
Kernel::Thread* thread = Kernel::GetCurrentThread();
SaveContext(thread->GetContext());
if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) {
if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
last_bkpt_hit = false;
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
@@ -272,4 +258,20 @@ void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
last_bkpt_hit = true;
}
void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
u32 esr{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
const auto ec = esr >> 26;
const auto iss = esr & 0xFFFFFF;
auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
switch (ec) {
case 0x15: // SVC
Kernel::CallSVC(arm_instance->system, iss);
break;
}
}
} // namespace Core
+7 -7
View File
@@ -9,15 +9,13 @@
#include "core/arm/arm_interface.h"
#include "core/gdbstub/gdbstub.h"
namespace Core::Timing {
class CoreTiming;
}
namespace Core {
class System;
class ARM_Unicorn final : public ARM_Interface {
public:
explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
explicit ARM_Unicorn(System& system);
~ARM_Unicorn() override;
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
@@ -47,10 +45,12 @@ public:
void RecordBreak(GDBStub::BreakpointAddress bkpt);
private:
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
uc_engine* uc{};
Timing::CoreTiming& core_timing;
System& system;
GDBStub::BreakpointAddress last_bkpt{};
bool last_bkpt_hit;
bool last_bkpt_hit = false;
};
} // namespace Core
+26
View File
@@ -17,6 +17,7 @@
#include "core/core_timing.h"
#include "core/cpu_core_manager.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h"
@@ -108,6 +109,8 @@ struct System::Impl {
// Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr)
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
if (content_provider == nullptr)
content_provider = std::make_unique<FileSys::ContentProviderUnion>();
/// Create default implementations of applets if one is not provided.
if (profile_selector == nullptr)
@@ -249,6 +252,8 @@ struct System::Impl {
Kernel::KernelCore kernel;
/// RealVfsFilesystem instance
FileSys::VirtualFilesystem virtual_filesystem;
/// ContentProviderUnion instance
std::unique_ptr<FileSys::ContentProviderUnion> content_provider;
/// AppLoader used to load the current executing application
std::unique_ptr<Loader::AppLoader> app_loader;
std::unique_ptr<VideoCore::RendererBase> renderer;
@@ -488,6 +493,27 @@ const Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
return *impl->software_keyboard;
}
void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) {
impl->content_provider = std::move(provider);
}
FileSys::ContentProvider& System::GetContentProvider() {
return *impl->content_provider;
}
const FileSys::ContentProvider& System::GetContentProvider() const {
return *impl->content_provider;
}
void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
FileSys::ContentProvider* provider) {
impl->content_provider->SetSlot(slot, provider);
}
void System::ClearContentProvider(FileSys::ContentProviderUnionSlot slot) {
impl->content_provider->ClearSlot(slot);
}
void System::SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet) {
impl->web_browser = std::move(applet);
}
+14
View File
@@ -21,6 +21,9 @@ class WebBrowserApplet;
namespace FileSys {
class CheatList;
class ContentProvider;
class ContentProviderUnion;
enum class ContentProviderUnionSlot;
class VfsFilesystem;
} // namespace FileSys
@@ -270,6 +273,17 @@ public:
Frontend::WebBrowserApplet& GetWebBrowser();
const Frontend::WebBrowserApplet& GetWebBrowser() const;
void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
FileSys::ContentProvider& GetContentProvider();
const FileSys::ContentProvider& GetContentProvider() const;
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
FileSys::ContentProvider* provider);
void ClearContentProvider(FileSys::ContentProviderUnionSlot slot);
private:
System();
+3 -3
View File
@@ -55,13 +55,13 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
: 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>(core_timing, exclusive_monitor, core_index);
arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
#else
arm_interface = std::make_unique<ARM_Unicorn>();
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>(core_timing);
arm_interface = std::make_unique<ARM_Unicorn>(system);
}
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface);
+2 -1
View File
@@ -22,6 +22,7 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/partition_data_manager.h"
@@ -794,7 +795,7 @@ void KeyManager::DeriveBase() {
void KeyManager::DeriveETicket(PartitionDataManager& data) {
// ETicket keys
const auto es = Service::FileSystem::GetUnionContents().GetEntry(
const auto es = Core::System::GetInstance().GetContentProvider().GetEntry(
0x0100000000000033, FileSys::ContentRecordType::Program);
if (es == nullptr)
+12 -10
View File
@@ -10,6 +10,7 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/ips_layer.h"
@@ -69,7 +70,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
}
const auto installed = Service::FileSystem::GetUnionContents();
const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
@@ -155,7 +156,7 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD
return out;
}
std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const {
std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::string& name) const {
if (nso.size() < sizeof(Loader::NSOHeader)) {
return nso;
}
@@ -171,18 +172,19 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const {
const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
if (Settings::values.dump_nso) {
LOG_INFO(Loader, "Dumping NSO for build_id={}, title_id={:016X}", build_id, title_id);
LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
title_id);
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
const auto file = nso_dir->CreateFile(fmt::format("{}.nso", build_id));
const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id));
file->Resize(nso.size());
file->WriteBytes(nso);
}
}
LOG_INFO(Loader, "Patching NSO for build_id={}", build_id);
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
auto patch_dirs = load_dir->GetSubdirectories();
@@ -345,7 +347,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
if (romfs == nullptr)
return romfs;
const auto installed = Service::FileSystem::GetUnionContents();
const auto& installed = Core::System::GetInstance().GetContentProvider();
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
@@ -392,7 +394,7 @@ static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
VirtualFile update_raw) const {
std::map<std::string, std::string, std::less<>> out;
const auto installed = Service::FileSystem::GetUnionContents();
const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto& disabled = Settings::values.disabled_addons[title_id];
// Game Updates
@@ -466,10 +468,10 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
// DLC
const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
std::vector<RegisteredCacheEntry> dlc_match;
std::vector<ContentProviderEntry> dlc_match;
dlc_match.reserve(dlc_entries.size());
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
[this, &installed](const RegisteredCacheEntry& entry) {
[this, &installed](const ContentProviderEntry& entry) {
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
});
@@ -492,7 +494,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
const auto installed{Service::FileSystem::GetUnionContents()};
const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr)
+1 -1
View File
@@ -44,7 +44,7 @@ public:
// Currently tracked NSO patches:
// - IPS
// - IPSwitch
std::vector<u8> PatchNSO(const std::vector<u8>& nso) const;
std::vector<u8> PatchNSO(const std::vector<u8>& nso, const std::string& name) const;
// Checks to see if PatchNSO() will have any effect given the NSO's build ID.
// Used to prevent expensive copies in NSO loader.
+176 -101
View File
@@ -23,19 +23,19 @@ namespace FileSys {
// The size of blocks to use when vfs raw copying into nand.
constexpr size_t VFS_RC_LARGE_COPY_BLOCK = 0x400000;
std::string RegisteredCacheEntry::DebugInfo() const {
std::string ContentProviderEntry::DebugInfo() const {
return fmt::format("title_id={:016X}, content_type={:02X}", title_id, static_cast<u8>(type));
}
bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
bool operator<(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs) {
return (lhs.title_id < rhs.title_id) || (lhs.title_id == rhs.title_id && lhs.type < rhs.type);
}
bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
bool operator==(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs) {
return std::tie(lhs.title_id, lhs.type) == std::tie(rhs.title_id, rhs.type);
}
bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
bool operator!=(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs) {
return !operator==(lhs, rhs);
}
@@ -84,7 +84,7 @@ static std::string GetCNMTName(TitleType type, u64 title_id) {
return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id);
}
static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
switch (type) {
case NCAContentType::Program:
// TODO(DarkLordZach): Differentiate between Program and Patch
@@ -104,6 +104,28 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
}
}
ContentProvider::~ContentProvider() = default;
bool ContentProvider::HasEntry(ContentProviderEntry entry) const {
return HasEntry(entry.title_id, entry.type);
}
VirtualFile ContentProvider::GetEntryUnparsed(ContentProviderEntry entry) const {
return GetEntryUnparsed(entry.title_id, entry.type);
}
VirtualFile ContentProvider::GetEntryRaw(ContentProviderEntry entry) const {
return GetEntryRaw(entry.title_id, entry.type);
}
std::unique_ptr<NCA> ContentProvider::GetEntry(ContentProviderEntry entry) const {
return GetEntry(entry.title_id, entry.type);
}
std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
}
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
std::string_view path) const {
const auto file = dir->GetFileRelative(path);
@@ -161,8 +183,8 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
return file;
}
static std::optional<NcaID> CheckMapForContentRecord(
const boost::container::flat_map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
static std::optional<NcaID> CheckMapForContentRecord(const std::map<u64, CNMT>& map, u64 title_id,
ContentRecordType type) {
if (map.find(title_id) == map.end())
return {};
@@ -268,7 +290,7 @@ void RegisteredCache::Refresh() {
AccumulateYuzuMeta();
}
RegisteredCache::RegisteredCache(VirtualDir dir_, RegisteredCacheParsingFunction parsing_function)
RegisteredCache::RegisteredCache(VirtualDir dir_, ContentProviderParsingFunction parsing_function)
: dir(std::move(dir_)), parser(std::move(parsing_function)) {
Refresh();
}
@@ -279,19 +301,11 @@ bool RegisteredCache::HasEntry(u64 title_id, ContentRecordType type) const {
return GetEntryRaw(title_id, type) != nullptr;
}
bool RegisteredCache::HasEntry(RegisteredCacheEntry entry) const {
return GetEntryRaw(entry) != nullptr;
}
VirtualFile RegisteredCache::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
const auto id = GetNcaIDFromMetadata(title_id, type);
return id ? GetFileAtID(*id) : nullptr;
}
VirtualFile RegisteredCache::GetEntryUnparsed(RegisteredCacheEntry entry) const {
return GetEntryUnparsed(entry.title_id, entry.type);
}
std::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
const auto meta_iter = meta.find(title_id);
if (meta_iter != meta.end())
@@ -309,10 +323,6 @@ VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) c
return id ? parser(GetFileAtID(*id), *id) : nullptr;
}
VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const {
return GetEntryRaw(entry.title_id, entry.type);
}
std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType type) const {
const auto raw = GetEntryRaw(title_id, type);
if (raw == nullptr)
@@ -320,10 +330,6 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t
return std::make_unique<NCA>(raw, nullptr, 0, keys);
}
std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
return GetEntry(entry.title_id, entry.type);
}
template <typename T>
void RegisteredCache::IterateAllMetadata(
std::vector<T>& out, std::function<T(const CNMT&, const ContentRecord&)> proc,
@@ -348,25 +354,14 @@ void RegisteredCache::IterateAllMetadata(
}
}
std::vector<RegisteredCacheEntry> RegisteredCache::ListEntries() const {
std::vector<RegisteredCacheEntry> out;
IterateAllMetadata<RegisteredCacheEntry>(
out,
[](const CNMT& c, const ContentRecord& r) {
return RegisteredCacheEntry{c.GetTitleID(), r.type};
},
[](const CNMT& c, const ContentRecord& r) { return true; });
return out;
}
std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
std::vector<ContentProviderEntry> RegisteredCache::ListEntriesFilter(
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const {
std::vector<RegisteredCacheEntry> out;
IterateAllMetadata<RegisteredCacheEntry>(
std::vector<ContentProviderEntry> out;
IterateAllMetadata<ContentProviderEntry>(
out,
[](const CNMT& c, const ContentRecord& r) {
return RegisteredCacheEntry{c.GetTitleID(), r.type};
return ContentProviderEntry{c.GetTitleID(), r.type};
},
[&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
if (title_type && *title_type != c.GetType())
@@ -521,37 +516,56 @@ bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
}) != yuzu_meta.end();
}
RegisteredCacheUnion::RegisteredCacheUnion(std::vector<RegisteredCache*> caches)
: caches(std::move(caches)) {}
ContentProviderUnion::~ContentProviderUnion() = default;
void RegisteredCacheUnion::Refresh() {
for (const auto& c : caches)
c->Refresh();
void ContentProviderUnion::SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider) {
providers[slot] = provider;
}
bool RegisteredCacheUnion::HasEntry(u64 title_id, ContentRecordType type) const {
return std::any_of(caches.begin(), caches.end(), [title_id, type](const auto& cache) {
return cache->HasEntry(title_id, type);
});
void ContentProviderUnion::ClearSlot(ContentProviderUnionSlot slot) {
providers[slot] = nullptr;
}
bool RegisteredCacheUnion::HasEntry(RegisteredCacheEntry entry) const {
return HasEntry(entry.title_id, entry.type);
void ContentProviderUnion::Refresh() {
for (auto& provider : providers) {
if (provider.second == nullptr)
continue;
provider.second->Refresh();
}
}
std::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const {
for (const auto& c : caches) {
const auto res = c->GetEntryVersion(title_id);
if (res)
bool ContentProviderUnion::HasEntry(u64 title_id, ContentRecordType type) const {
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
if (provider.second->HasEntry(title_id, type))
return true;
}
return false;
}
std::optional<u32> ContentProviderUnion::GetEntryVersion(u64 title_id) const {
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
const auto res = provider.second->GetEntryVersion(title_id);
if (res != std::nullopt)
return res;
}
return {};
return std::nullopt;
}
VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
for (const auto& c : caches) {
const auto res = c->GetEntryUnparsed(title_id, type);
VirtualFile ContentProviderUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
const auto res = provider.second->GetEntryUnparsed(title_id, type);
if (res != nullptr)
return res;
}
@@ -559,13 +573,12 @@ VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordTy
return nullptr;
}
VirtualFile RegisteredCacheUnion::GetEntryUnparsed(RegisteredCacheEntry entry) const {
return GetEntryUnparsed(entry.title_id, entry.type);
}
VirtualFile ContentProviderUnion::GetEntryRaw(u64 title_id, ContentRecordType type) const {
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
VirtualFile RegisteredCacheUnion::GetEntryRaw(u64 title_id, ContentRecordType type) const {
for (const auto& c : caches) {
const auto res = c->GetEntryRaw(title_id, type);
const auto res = provider.second->GetEntryRaw(title_id, type);
if (res != nullptr)
return res;
}
@@ -573,30 +586,30 @@ VirtualFile RegisteredCacheUnion::GetEntryRaw(u64 title_id, ContentRecordType ty
return nullptr;
}
VirtualFile RegisteredCacheUnion::GetEntryRaw(RegisteredCacheEntry entry) const {
return GetEntryRaw(entry.title_id, entry.type);
std::unique_ptr<NCA> ContentProviderUnion::GetEntry(u64 title_id, ContentRecordType type) const {
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
auto res = provider.second->GetEntry(title_id, type);
if (res != nullptr)
return res;
}
return nullptr;
}
std::unique_ptr<NCA> RegisteredCacheUnion::GetEntry(u64 title_id, ContentRecordType type) const {
const auto raw = GetEntryRaw(title_id, type);
if (raw == nullptr)
return nullptr;
return std::make_unique<NCA>(raw);
}
std::vector<ContentProviderEntry> ContentProviderUnion::ListEntriesFilter(
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const {
std::vector<ContentProviderEntry> out;
std::unique_ptr<NCA> RegisteredCacheUnion::GetEntry(RegisteredCacheEntry entry) const {
return GetEntry(entry.title_id, entry.type);
}
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const {
std::vector<RegisteredCacheEntry> out;
for (const auto& c : caches) {
c->IterateAllMetadata<RegisteredCacheEntry>(
out,
[](const CNMT& c, const ContentRecord& r) {
return RegisteredCacheEntry{c.GetTitleID(), r.type};
},
[](const CNMT& c, const ContentRecord& r) { return true; });
const auto vec = provider.second->ListEntriesFilter(title_type, record_type, title_id);
std::copy(vec.begin(), vec.end(), std::back_inserter(out));
}
std::sort(out.begin(), out.end());
@@ -604,25 +617,87 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const {
return out;
}
std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter(
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>>
ContentProviderUnion::ListEntriesFilterOrigin(std::optional<ContentProviderUnionSlot> origin,
std::optional<TitleType> title_type,
std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const {
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> out;
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
if (origin.has_value() && *origin != provider.first)
continue;
const auto vec = provider.second->ListEntriesFilter(title_type, record_type, title_id);
std::transform(vec.begin(), vec.end(), std::back_inserter(out),
[&provider](const ContentProviderEntry& entry) {
return std::make_pair(provider.first, entry);
});
}
std::sort(out.begin(), out.end());
out.erase(std::unique(out.begin(), out.end()), out.end());
return out;
}
ManualContentProvider::~ManualContentProvider() = default;
void ManualContentProvider::AddEntry(TitleType title_type, ContentRecordType content_type,
u64 title_id, VirtualFile file) {
entries.insert_or_assign({title_type, content_type, title_id}, file);
}
void ManualContentProvider::ClearAllEntries() {
entries.clear();
}
void ManualContentProvider::Refresh() {}
bool ManualContentProvider::HasEntry(u64 title_id, ContentRecordType type) const {
return GetEntryRaw(title_id, type) != nullptr;
}
std::optional<u32> ManualContentProvider::GetEntryVersion(u64 title_id) const {
return std::nullopt;
}
VirtualFile ManualContentProvider::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
return GetEntryRaw(title_id, type);
}
VirtualFile ManualContentProvider::GetEntryRaw(u64 title_id, ContentRecordType type) const {
const auto iter =
std::find_if(entries.begin(), entries.end(), [title_id, type](const auto& entry) {
const auto [title_type, content_type, e_title_id] = entry.first;
return content_type == type && e_title_id == title_id;
});
if (iter == entries.end())
return nullptr;
return iter->second;
}
std::unique_ptr<NCA> ManualContentProvider::GetEntry(u64 title_id, ContentRecordType type) const {
const auto res = GetEntryRaw(title_id, type);
if (res == nullptr)
return nullptr;
return std::make_unique<NCA>(res, nullptr, 0, keys);
}
std::vector<ContentProviderEntry> ManualContentProvider::ListEntriesFilter(
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const {
std::vector<RegisteredCacheEntry> out;
for (const auto& c : caches) {
c->IterateAllMetadata<RegisteredCacheEntry>(
out,
[](const CNMT& c, const ContentRecord& r) {
return RegisteredCacheEntry{c.GetTitleID(), r.type};
},
[&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
if (title_type && *title_type != c.GetType())
return false;
if (record_type && *record_type != r.type)
return false;
if (title_id && *title_id != c.GetTitleID())
return false;
return true;
});
std::vector<ContentProviderEntry> out;
for (const auto& entry : entries) {
const auto [e_title_type, e_content_type, e_title_id] = entry.first;
if ((title_type == std::nullopt || e_title_type == *title_type) &&
(record_type == std::nullopt || e_content_type == *record_type) &&
(title_id == std::nullopt || e_title_id == *title_id)) {
out.emplace_back(ContentProviderEntry{e_title_id, e_content_type});
}
}
std::sort(out.begin(), out.end());
+101 -49
View File
@@ -21,12 +21,13 @@ class NSP;
class XCI;
enum class ContentRecordType : u8;
enum class NCAContentType : u8;
enum class TitleType : u8;
struct ContentRecord;
using NcaID = std::array<u8, 0x10>;
using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
using VfsCopyFunction = std::function<bool(const VirtualFile&, const VirtualFile&, size_t)>;
enum class InstallResult {
@@ -36,7 +37,7 @@ enum class InstallResult {
ErrorMetaFailed,
};
struct RegisteredCacheEntry {
struct ContentProviderEntry {
u64 title_id;
ContentRecordType type;
@@ -47,12 +48,46 @@ constexpr u64 GetUpdateTitleID(u64 base_title_id) {
return base_title_id | 0x800;
}
ContentRecordType GetCRTypeFromNCAType(NCAContentType type);
// boost flat_map requires operator< for O(log(n)) lookups.
bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
bool operator<(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
// std unique requires operator== to identify duplicates.
bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
bool operator==(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
bool operator!=(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
class ContentProvider {
public:
virtual ~ContentProvider();
virtual void Refresh() = 0;
virtual bool HasEntry(u64 title_id, ContentRecordType type) const = 0;
virtual bool HasEntry(ContentProviderEntry entry) const;
virtual std::optional<u32> GetEntryVersion(u64 title_id) const = 0;
virtual VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const = 0;
virtual VirtualFile GetEntryUnparsed(ContentProviderEntry entry) const;
virtual VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const = 0;
virtual VirtualFile GetEntryRaw(ContentProviderEntry entry) const;
virtual std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const = 0;
virtual std::unique_ptr<NCA> GetEntry(ContentProviderEntry entry) const;
virtual std::vector<ContentProviderEntry> ListEntries() const;
// If a parameter is not std::nullopt, it will be filtered for from all entries.
virtual std::vector<ContentProviderEntry> ListEntriesFilter(
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
std::optional<u64> title_id = {}) const = 0;
protected:
// A single instance of KeyManager to be used by GetEntry()
Core::Crypto::KeyManager keys;
};
/*
* A class that catalogues NCAs in the registered directory structure.
@@ -67,39 +102,32 @@ bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs
* (This impl also supports substituting the nca dir for an nca file, as that's more convenient
* when 4GB splitting can be ignored.)
*/
class RegisteredCache {
friend class RegisteredCacheUnion;
class RegisteredCache : public ContentProvider {
public:
// Parsing function defines the conversion from raw file to NCA. If there are other steps
// besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
// parsing function.
explicit RegisteredCache(VirtualDir dir,
RegisteredCacheParsingFunction parsing_function =
ContentProviderParsingFunction parsing_function =
[](const VirtualFile& file, const NcaID& id) { return file; });
~RegisteredCache();
~RegisteredCache() override;
void Refresh();
void Refresh() override;
bool HasEntry(u64 title_id, ContentRecordType type) const;
bool HasEntry(RegisteredCacheEntry entry) const;
bool HasEntry(u64 title_id, ContentRecordType type) const override;
std::optional<u32> GetEntryVersion(u64 title_id) const;
std::optional<u32> GetEntryVersion(u64 title_id) const override;
VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
std::vector<RegisteredCacheEntry> ListEntries() const;
// If a parameter is not std::nullopt, it will be filtered for from all entries.
std::vector<RegisteredCacheEntry> ListEntriesFilter(
std::vector<ContentProviderEntry> ListEntriesFilter(
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
std::optional<u64> title_id = {}) const;
std::optional<u64> title_id = {}) const override;
// Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
// there is a meta NCA and all of them are accessible.
@@ -131,46 +159,70 @@ private:
bool RawInstallYuzuMeta(const CNMT& cnmt);
VirtualDir dir;
RegisteredCacheParsingFunction parser;
Core::Crypto::KeyManager keys;
ContentProviderParsingFunction parser;
// maps tid -> NcaID of meta
boost::container::flat_map<u64, NcaID> meta_id;
std::map<u64, NcaID> meta_id;
// maps tid -> meta
boost::container::flat_map<u64, CNMT> meta;
std::map<u64, CNMT> meta;
// maps tid -> meta for CNMT in yuzu_meta
boost::container::flat_map<u64, CNMT> yuzu_meta;
std::map<u64, CNMT> yuzu_meta;
};
// Combines multiple RegisteredCaches (i.e. SysNAND, UserNAND, SDMC) into one interface.
class RegisteredCacheUnion {
enum class ContentProviderUnionSlot {
SysNAND, ///< System NAND
UserNAND, ///< User NAND
SDMC, ///< SD Card
FrontendManual, ///< Frontend-defined game list or similar
};
// Combines multiple ContentProvider(s) (i.e. SysNAND, UserNAND, SDMC) into one interface.
class ContentProviderUnion : public ContentProvider {
public:
explicit RegisteredCacheUnion(std::vector<RegisteredCache*> caches);
~ContentProviderUnion() override;
void Refresh();
void SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider);
void ClearSlot(ContentProviderUnionSlot slot);
bool HasEntry(u64 title_id, ContentRecordType type) const;
bool HasEntry(RegisteredCacheEntry entry) const;
void Refresh() override;
bool HasEntry(u64 title_id, ContentRecordType type) const override;
std::optional<u32> GetEntryVersion(u64 title_id) const override;
VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
std::vector<ContentProviderEntry> ListEntriesFilter(
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const override;
std::optional<u32> GetEntryVersion(u64 title_id) const;
VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
std::vector<RegisteredCacheEntry> ListEntries() const;
// If a parameter is not std::nullopt, it will be filtered for from all entries.
std::vector<RegisteredCacheEntry> ListEntriesFilter(
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> ListEntriesFilterOrigin(
std::optional<ContentProviderUnionSlot> origin = {},
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
std::optional<u64> title_id = {}) const;
private:
std::vector<RegisteredCache*> caches;
std::map<ContentProviderUnionSlot, ContentProvider*> providers;
};
class ManualContentProvider : public ContentProvider {
public:
~ManualContentProvider() override;
void AddEntry(TitleType title_type, ContentRecordType content_type, u64 title_id,
VirtualFile file);
void ClearAllEntries();
void Refresh() override;
bool HasEntry(u64 title_id, ContentRecordType type) const override;
std::optional<u32> GetEntryVersion(u64 title_id) const override;
VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
std::vector<ContentProviderEntry> ListEntriesFilter(
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const override;
private:
std::map<std::tuple<TitleType, ContentRecordType, u64>, VirtualFile> entries;
};
} // namespace FileSys
+1 -1
View File
@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
switch (storage) {
case StorageId::None:
res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type);
break;
case StorageId::NandSystem:
res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
+7 -6
View File
@@ -143,11 +143,12 @@ std::multimap<u64, std::shared_ptr<NCA>> NSP::GetNCAsByTitleID() const {
return out;
}
std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> NSP::GetNCAs() const {
std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>>
NSP::GetNCAs() const {
return ncas;
}
std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type) const {
std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType title_type) const {
if (extracted)
LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
@@ -155,14 +156,14 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type) const {
if (title_id_iter == ncas.end())
return nullptr;
const auto type_iter = title_id_iter->second.find(type);
const auto type_iter = title_id_iter->second.find({title_type, type});
if (type_iter == title_id_iter->second.end())
return nullptr;
return type_iter->second;
}
VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type) const {
VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type, TitleType title_type) const {
if (extracted)
LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
const auto nca = GetNCA(title_id, type);
@@ -240,7 +241,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
const CNMT cnmt(inner_file);
auto& ncas_title = ncas[cnmt.GetTitleID()];
ncas_title[ContentRecordType::Meta] = nca;
ncas_title[{cnmt.GetType(), ContentRecordType::Meta}] = nca;
for (const auto& rec : cnmt.GetContentRecords()) {
const auto id_string = Common::HexArrayToString(rec.nca_id, false);
const auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
@@ -258,7 +259,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
(next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
(cnmt.GetTitleID() & 0x800) != 0)) {
ncas_title[rec.type] = std::move(next_nca);
ncas_title[{cnmt.GetType(), rec.type}] = std::move(next_nca);
}
}
+7 -4
View File
@@ -42,9 +42,12 @@ public:
// Type 0 Only (Collection of NCAs + Certificate + Ticket + Meta XML)
std::vector<std::shared_ptr<NCA>> GetNCAsCollapsed() const;
std::multimap<u64, std::shared_ptr<NCA>> GetNCAsByTitleID() const;
std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> GetNCAs() const;
std::shared_ptr<NCA> GetNCA(u64 title_id, ContentRecordType type) const;
VirtualFile GetNCAFile(u64 title_id, ContentRecordType type) const;
std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> GetNCAs()
const;
std::shared_ptr<NCA> GetNCA(u64 title_id, ContentRecordType type,
TitleType title_type = TitleType::Application) const;
VirtualFile GetNCAFile(u64 title_id, ContentRecordType type,
TitleType title_type = TitleType::Application) const;
std::vector<Core::Crypto::Key128> GetTitlekey() const;
std::vector<VirtualFile> GetFiles() const override;
@@ -67,7 +70,7 @@ private:
std::shared_ptr<PartitionFilesystem> pfs;
// Map title id -> {map type -> NCA}
std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas;
std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas;
std::vector<VirtualFile> ticket_files;
Core::Crypto::KeyManager keys;
+30 -9
View File
@@ -12,6 +12,23 @@
namespace Core::Frontend {
/**
* Represents a graphics context that can be used for background computation or drawing. If the
* graphics backend doesn't require the context, then the implementation of these methods can be
* stubs
*/
class GraphicsContext {
public:
/// Makes the graphics context current for the caller thread
virtual void MakeCurrent() = 0;
/// Releases (dunno if this is the "right" word) the context from the caller thread
virtual void DoneCurrent() = 0;
/// Swap buffers to display the next frame
virtual void SwapBuffers() = 0;
};
/**
* Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...).
@@ -30,7 +47,7 @@ namespace Core::Frontend {
* - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
* re-read the upper points again and think about it if you don't see this.
*/
class EmuWindow {
class EmuWindow : public GraphicsContext {
public:
/// Data structure to store emuwindow configuration
struct WindowConfig {
@@ -40,17 +57,21 @@ public:
std::pair<unsigned, unsigned> min_client_area_size;
};
/// Swap buffers to display the next frame
virtual void SwapBuffers() = 0;
/// Polls window events
virtual void PollEvents() = 0;
/// Makes the graphics context current for the caller thread
virtual void MakeCurrent() = 0;
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
virtual void DoneCurrent() = 0;
/**
* Returns a GraphicsContext that the frontend provides that is shared with the emu window. This
* context can be used from other threads for background graphics computation. If the frontend
* is using a graphics backend that doesn't need anything specific to run on a different thread,
* then it can use a stubbed implemenation for GraphicsContext.
*
* If the return value is null, then the core should assume that the frontend cannot provide a
* Shared Context
*/
virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const {
return nullptr;
}
/**
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
+1 -1
View File
@@ -1030,7 +1030,7 @@ static void Step() {
/// Tell the CPU if we hit a memory breakpoint.
bool IsMemoryBreak() {
if (IsConnected()) {
if (!IsConnected()) {
return false;
}
+1 -3
View File
@@ -139,10 +139,8 @@ public:
context->AddDomainObject(std::move(iface));
} else {
auto& kernel = Core::System::GetInstance().Kernel();
auto sessions =
auto [server, client] =
Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName());
auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions);
auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions);
iface->ClientConnected(server);
context->AddMoveObject(std::move(client));
}
+4 -6
View File
@@ -2,8 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <tuple>
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
@@ -31,18 +29,18 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
active_sessions++;
// Create a new session pair, let the created sessions inherit the parent port's HLE handler.
auto sessions = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this);
auto [server, client] = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this);
if (server_port->HasHLEHandler()) {
server_port->GetHLEHandler()->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
server_port->GetHLEHandler()->ClientConnected(server);
} else {
server_port->AppendPendingSession(std::get<SharedPtr<ServerSession>>(sessions));
server_port->AppendPendingSession(server);
}
// Wake the threads waiting on the ServerPort
server_port->WakeupAllWaitingThreads();
return MakeResult(std::get<SharedPtr<ClientSession>>(sessions));
return MakeResult(client);
}
void ClientPort::ConnectionClosed() {
+1 -1
View File
@@ -25,7 +25,7 @@ public:
return name;
}
static const HandleType HANDLE_TYPE = HandleType::ClientPort;
static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
+1 -1
View File
@@ -29,7 +29,7 @@ public:
return name;
}
static const HandleType HANDLE_TYPE = HandleType::ClientSession;
static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
+2
View File
@@ -21,6 +21,7 @@
#include "core/hle/kernel/thread.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/memory.h"
namespace Kernel {
@@ -181,6 +182,7 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
void KernelCore::MakeCurrentProcess(Process* process) {
impl->current_process = process;
Memory::SetCurrentPageTable(&process->VMManager().page_table);
}
Process* KernelCore::CurrentProcess() {
+2 -3
View File
@@ -32,9 +32,6 @@ namespace {
* @param priority The priority to give the main thread
*/
void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_point, u32 priority) {
// Setup page table so we can write to memory
Memory::SetCurrentPageTable(&owner_process.VMManager().page_table);
// Initialize new "main" thread
const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0,
@@ -109,6 +106,8 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
is_64bit_process = metadata.Is64BitProgram();
vm_manager.Reset(metadata.GetAddressSpaceType());
// Ensure that the potentially resized page table is seen by CPU backends.
Memory::SetCurrentPageTable(&vm_manager.page_table);
const auto& caps = metadata.GetKernelCapabilities();
const auto capability_init_result =
+1 -1
View File
@@ -85,7 +85,7 @@ public:
return name;
}
static const HandleType HANDLE_TYPE = HandleType::Process;
static constexpr HandleType HANDLE_TYPE = HandleType::Process;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
+1 -1
View File
@@ -31,7 +31,7 @@ public:
return reset_type;
}
static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
+1 -1
View File
@@ -41,7 +41,7 @@ public:
return GetTypeName();
}
static const HandleType HANDLE_TYPE = HandleType::ResourceLimit;
static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
-1
View File
@@ -101,7 +101,6 @@ void Scheduler::SwitchContext(Thread* new_thread) {
auto* const thread_owner_process = current_thread->GetOwnerProcess();
if (previous_process != thread_owner_process) {
system.Kernel().MakeCurrentProcess(thread_owner_process);
Memory::SetCurrentPageTable(&thread_owner_process->VMManager().page_table);
}
cpu_core.LoadContext(new_thread->GetContext());
+3 -4
View File
@@ -39,9 +39,8 @@ void ServerPort::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
}
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
KernelCore& kernel, u32 max_sessions, std::string name) {
ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
std::string name) {
SharedPtr<ServerPort> server_port(new ServerPort(kernel));
SharedPtr<ClientPort> client_port(new ClientPort(kernel));
@@ -51,7 +50,7 @@ std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortP
client_port->max_sessions = max_sessions;
client_port->active_sessions = 0;
return std::make_tuple(std::move(server_port), std::move(client_port));
return std::make_pair(std::move(server_port), std::move(client_port));
}
} // namespace Kernel
+5 -4
View File
@@ -6,7 +6,7 @@
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
@@ -23,6 +23,7 @@ class SessionRequestHandler;
class ServerPort final : public WaitObject {
public:
using HLEHandler = std::shared_ptr<SessionRequestHandler>;
using PortPair = std::pair<SharedPtr<ServerPort>, SharedPtr<ClientPort>>;
/**
* Creates a pair of ServerPort and an associated ClientPort.
@@ -32,8 +33,8 @@ public:
* @param name Optional name of the ports
* @return The created port tuple
*/
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
KernelCore& kernel, u32 max_sessions, std::string name = "UnknownPort");
static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions,
std::string name = "UnknownPort");
std::string GetTypeName() const override {
return "ServerPort";
@@ -42,7 +43,7 @@ public:
return name;
}
static const HandleType HANDLE_TYPE = HandleType::ServerPort;
static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
+3 -8
View File
@@ -28,11 +28,9 @@ ServerSession::~ServerSession() {
// the emulated application.
// Decrease the port's connection count.
if (parent->port)
if (parent->port) {
parent->port->ConnectionClosed();
// TODO(Subv): Wake up all the ClientSession's waiting threads and set
// the SendSyncRequest result to 0xC920181A.
}
parent->server = nullptr;
}
@@ -74,9 +72,6 @@ void ServerSession::ClientDisconnected() {
handler->ClientDisconnected(this);
}
// TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set
// their WaitSynchronization result to 0xC920181A.
// Clean up the list of client threads with pending requests, they are unneeded now that the
// client endpoint is closed.
pending_requesting_threads.clear();
@@ -204,6 +199,6 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel,
client_session->parent = parent;
server_session->parent = parent;
return std::make_tuple(std::move(server_session), std::move(client_session));
return std::make_pair(std::move(server_session), std::move(client_session));
}
} // namespace Kernel
+7 -2
View File
@@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "core/hle/kernel/object.h"
@@ -41,7 +42,11 @@ public:
return "ServerSession";
}
static const HandleType HANDLE_TYPE = HandleType::ServerSession;
std::string GetName() const override {
return name;
}
static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
@@ -54,7 +59,7 @@ public:
return parent.get();
}
using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
using SessionPair = std::pair<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
/**
* Creates a pair of ServerSession and an associated ClientSession.
+1 -1
View File
@@ -76,7 +76,7 @@ public:
return name;
}
static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -6,8 +6,12 @@
#include "common/common_types.h"
namespace Core {
class System;
}
namespace Kernel {
void CallSVC(u32 immediate);
void CallSVC(Core::System& system, u32 immediate);
} // namespace Kernel
+199 -165
View File
@@ -11,278 +11,312 @@
namespace Kernel {
static inline u64 Param(int n) {
return Core::CurrentArmInterface().GetReg(n);
static inline u64 Param(const Core::System& system, int n) {
return system.CurrentArmInterface().GetReg(n);
}
/**
* HLE a function return from the current ARM userland process
* @param res Result to return
* @param system System context
* @param result Result to return
*/
static inline void FuncReturn(u64 res) {
Core::CurrentArmInterface().SetReg(0, res);
static inline void FuncReturn(Core::System& system, u64 result) {
system.CurrentArmInterface().SetReg(0, result);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type ResultCode
template <ResultCode func(u64)>
void SvcWrap() {
FuncReturn(func(Param(0)).raw);
template <ResultCode func(Core::System&, u64)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0)).raw);
}
template <ResultCode func(u32)>
void SvcWrap() {
FuncReturn(func(static_cast<u32>(Param(0))).raw);
template <ResultCode func(Core::System&, u32)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
}
template <ResultCode func(u32, u32)>
void SvcWrap() {
FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
template <ResultCode func(Core::System&, u32, u32)>
void SvcWrap(Core::System& system) {
FuncReturn(
system,
func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
}
template <ResultCode func(u32*)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32*)>
void SvcWrap(Core::System& system) {
u32 param = 0;
const u32 retval = func(&param).raw;
Core::CurrentArmInterface().SetReg(1, param);
FuncReturn(retval);
const u32 retval = func(system, &param).raw;
system.CurrentArmInterface().SetReg(1, param);
FuncReturn(system, retval);
}
template <ResultCode func(u32*, u32)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32*, u32)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
u32 retval = func(&param_1, static_cast<u32>(Param(1))).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1))).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u32*, u32*)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32*, u32*)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
u32 param_2 = 0;
const u32 retval = func(&param_1, &param_2).raw;
const u32 retval = func(system, &param_1, &param_2).raw;
auto& arm_interface = Core::CurrentArmInterface();
auto& arm_interface = system.CurrentArmInterface();
arm_interface.SetReg(1, param_1);
arm_interface.SetReg(2, param_2);
FuncReturn(retval);
FuncReturn(system, retval);
}
template <ResultCode func(u32*, u64)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32*, u64)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(&param_1, Param(1)).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval = func(system, &param_1, Param(system, 1)).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u32*, u64, u32)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32*, u64, u32)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(&param_1, Param(1), static_cast<u32>(Param(2))).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval =
func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2))).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u64*, u32)>
void SvcWrap() {
template <ResultCode func(Core::System&, u64*, u32)>
void SvcWrap(Core::System& system) {
u64 param_1 = 0;
const u32 retval = func(&param_1, static_cast<u32>(Param(1))).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1))).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u64, s32)>
void SvcWrap() {
FuncReturn(func(Param(0), static_cast<s32>(Param(1))).raw);
template <ResultCode func(Core::System&, u64, s32)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), static_cast<s32>(Param(system, 1))).raw);
}
template <ResultCode func(u64, u32)>
void SvcWrap() {
FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw);
template <ResultCode func(Core::System&, u64, u32)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1))).raw);
}
template <ResultCode func(u64*, u64)>
void SvcWrap() {
template <ResultCode func(Core::System&, u64*, u64)>
void SvcWrap(Core::System& system) {
u64 param_1 = 0;
u32 retval = func(&param_1, Param(1)).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval = func(system, &param_1, Param(system, 1)).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u64*, u32, u32)>
void SvcWrap() {
template <ResultCode func(Core::System&, u64*, u32, u32)>
void SvcWrap(Core::System& system) {
u64 param_1 = 0;
u32 retval = func(&param_1, static_cast<u32>(Param(1)), static_cast<u32>(Param(2))).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1)),
static_cast<u32>(Param(system, 2)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u32, u64)>
void SvcWrap() {
FuncReturn(func(static_cast<u32>(Param(0)), Param(1)).raw);
template <ResultCode func(Core::System&, u32, u64)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
}
template <ResultCode func(u32, u32, u64)>
void SvcWrap() {
FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1)), Param(2)).raw);
template <ResultCode func(Core::System&, u32, u32, u64)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
static_cast<u32>(Param(system, 1)), Param(system, 2))
.raw);
}
template <ResultCode func(u32, u32*, u64*)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32, u32*, u64*)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
u64 param_2 = 0;
ResultCode retval = func(static_cast<u32>(Param(2)), &param_1, &param_2);
Core::CurrentArmInterface().SetReg(1, param_1);
Core::CurrentArmInterface().SetReg(2, param_2);
FuncReturn(retval.raw);
const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), &param_1, &param_2);
system.CurrentArmInterface().SetReg(1, param_1);
system.CurrentArmInterface().SetReg(2, param_2);
FuncReturn(system, retval.raw);
}
template <ResultCode func(u64, u64, u32, u32)>
void SvcWrap() {
template <ResultCode func(Core::System&, u64, u64, u32, u32)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
.raw);
}
template <ResultCode func(Core::System&, u64, u64, u32, u64)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
static_cast<u32>(Param(system, 2)), Param(system, 3))
.raw);
}
template <ResultCode func(Core::System&, u32, u64, u32)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
static_cast<u32>(Param(system, 2)))
.raw);
}
template <ResultCode func(Core::System&, u64, u64, u64)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1), Param(system, 2)).raw);
}
template <ResultCode func(Core::System&, u64, u64, u32)>
void SvcWrap(Core::System& system) {
FuncReturn(
func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw);
system,
func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
}
template <ResultCode func(u64, u64, u32, u64)>
void SvcWrap() {
FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2)), Param(3)).raw);
template <ResultCode func(Core::System&, u32, u64, u64, u32)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
Param(system, 2), static_cast<u32>(Param(system, 3)))
.raw);
}
template <ResultCode func(u32, u64, u32)>
void SvcWrap() {
FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw);
}
template <ResultCode func(u64, u64, u64)>
void SvcWrap() {
FuncReturn(func(Param(0), Param(1), Param(2)).raw);
}
template <ResultCode func(u64, u64, u32)>
void SvcWrap() {
FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2))).raw);
}
template <ResultCode func(u32, u64, u64, u32)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32, u64, u64)>
void SvcWrap(Core::System& system) {
FuncReturn(
func(static_cast<u32>(Param(0)), Param(1), Param(2), static_cast<u32>(Param(3))).raw);
system,
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw);
}
template <ResultCode func(u32, u64, u64)>
void SvcWrap() {
FuncReturn(func(static_cast<u32>(Param(0)), Param(1), Param(2)).raw);
}
template <ResultCode func(u32*, u64, u64, s64)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32*, u64, u64, s64)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
ResultCode retval =
func(&param_1, Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3)));
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval.raw);
const u32 retval = func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
static_cast<s64>(Param(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u64, u64, u32, s64)>
void SvcWrap() {
FuncReturn(
func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))).raw);
template <ResultCode func(Core::System&, u64, u64, u32, s64)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
static_cast<u32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
.raw);
}
template <ResultCode func(u64*, u64, u64, u64)>
void SvcWrap() {
template <ResultCode func(Core::System&, u64*, u64, u64, u64)>
void SvcWrap(Core::System& system) {
u64 param_1 = 0;
u32 retval = func(&param_1, Param(1), Param(2), Param(3)).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval =
func(system, &param_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u32*, u64, u64, u64, u32, s32)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32*, u64, u64, u64, u32, s32)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
u32 retval = func(&param_1, Param(1), Param(2), Param(3), static_cast<u32>(Param(4)),
static_cast<s32>(Param(5)))
.raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2), Param(system, 3),
static_cast<u32>(Param(system, 4)), static_cast<s32>(Param(system, 5)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u32*, u64, u64, u32)>
void SvcWrap() {
template <ResultCode func(Core::System&, u32*, u64, u64, u32)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
u32 retval = func(&param_1, Param(1), Param(2), static_cast<u32>(Param(3))).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2),
static_cast<u32>(Param(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(Handle*, u64, u32, u32)>
void SvcWrap() {
template <ResultCode func(Core::System&, Handle*, u64, u32, u32)>
void SvcWrap(Core::System& system) {
u32 param_1 = 0;
u32 retval =
func(&param_1, Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw;
Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
const u32 retval = func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
static_cast<u32>(Param(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <ResultCode func(u64, u32, s32, s64)>
void SvcWrap() {
FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
static_cast<s64>(Param(3)))
.raw);
template <ResultCode func(Core::System&, u64, u32, s32, s64)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
static_cast<s32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
.raw);
}
template <ResultCode func(u64, u32, s32, s32)>
void SvcWrap() {
FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
static_cast<s32>(Param(3)))
.raw);
template <ResultCode func(Core::System&, u64, u32, s32, s32)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3)))
.raw);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u32
template <u32 func()>
void SvcWrap() {
FuncReturn(func());
template <u32 func(Core::System&)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u64
template <u64 func()>
void SvcWrap() {
FuncReturn(func());
template <u64 func(Core::System&)>
void SvcWrap(Core::System& system) {
FuncReturn(system, func(system));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Function wrappers that return type void
template <void func()>
void SvcWrap() {
func();
template <void func(Core::System&)>
void SvcWrap(Core::System& system) {
func(system);
}
template <void func(s64)>
void SvcWrap() {
func(static_cast<s64>(Param(0)));
template <void func(Core::System&, s64)>
void SvcWrap(Core::System& system) {
func(system, static_cast<s64>(Param(system, 0)));
}
template <void func(u64, u64 len)>
void SvcWrap() {
func(Param(0), Param(1));
template <void func(Core::System&, u64, u64)>
void SvcWrap(Core::System& system) {
func(system, Param(system, 0), Param(system, 1));
}
template <void func(u64, u64, u64)>
void SvcWrap() {
func(Param(0), Param(1), Param(2));
template <void func(Core::System&, u64, u64, u64)>
void SvcWrap(Core::System& system) {
func(system, Param(system, 0), Param(system, 1), Param(system, 2));
}
template <void func(u32, u64, u64)>
void SvcWrap() {
func(static_cast<u32>(Param(0)), Param(1), Param(2));
template <void func(Core::System&, u32, u64, u64)>
void SvcWrap(Core::System& system) {
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2));
}
} // namespace Kernel
+1 -1
View File
@@ -106,7 +106,7 @@ public:
return "Thread";
}
static const HandleType HANDLE_TYPE = HandleType::Thread;
static constexpr HandleType HANDLE_TYPE = HandleType::Thread;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
+1 -1
View File
@@ -37,7 +37,7 @@ public:
return name;
}
static const HandleType HANDLE_TYPE = HandleType::WritableEvent;
static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
@@ -86,7 +86,7 @@ static FileSys::VirtualFile GetManualRomFS() {
if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
return out;
const auto& installed{FileSystem::GetUnionContents()};
const auto& installed{Core::System::GetInstance().GetContentProvider()};
const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(),
FileSys::ContentRecordType::Manual);
+2 -2
View File
@@ -33,11 +33,11 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
static std::vector<u64> AccumulateAOCTitleIDs() {
std::vector<u64> add_on_content;
const auto rcu = FileSystem::GetUnionContents();
const auto& rcu = Core::System::GetInstance().GetContentProvider();
const auto list =
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
[](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
[](const FileSys::ContentProviderEntry& rce) { return rce.title_id; });
add_on_content.erase(
std::remove_if(
add_on_content.begin(), add_on_content.end(),
@@ -391,11 +391,6 @@ void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
}
FileSys::RegisteredCacheUnion GetUnionContents() {
return FileSys::RegisteredCacheUnion{
{GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
}
FileSys::RegisteredCache* GetSystemNANDContents() {
LOG_TRACE(Service_FS, "Opening System NAND Contents");
@@ -460,6 +455,10 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (bis_factory == nullptr) {
bis_factory =
std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory);
Core::System::GetInstance().RegisterContentProvider(
FileSys::ContentProviderUnionSlot::SysNAND, bis_factory->GetSystemNANDContents());
Core::System::GetInstance().RegisterContentProvider(
FileSys::ContentProviderUnionSlot::UserNAND, bis_factory->GetUserNANDContents());
}
if (save_data_factory == nullptr) {
@@ -468,6 +467,8 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (sdmc_factory == nullptr) {
sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
Core::System::GetInstance().RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC,
sdmc_factory->GetSDMCContents());
}
}
@@ -54,8 +54,6 @@ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
FileSys::SaveDataSize new_value);
FileSys::RegisteredCacheUnion GetUnionContents();
FileSys::RegisteredCache* GetSystemNANDContents();
FileSys::RegisteredCache* GetUserNANDContents();
FileSys::RegisteredCache* GetSDMCContents();
+7 -8
View File
@@ -115,11 +115,12 @@ private:
void Read(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 unk = rp.Pop<u64>();
const u64 option = rp.Pop<u64>();
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
length);
// Error checking
if (length < 0) {
@@ -148,11 +149,12 @@ private:
void Write(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 unk = rp.Pop<u64>();
const u64 option = rp.Pop<u64>();
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
length);
// Error checking
if (length < 0) {
@@ -250,10 +252,7 @@ private:
u64 next_entry_index = 0;
void Read(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 unk = rp.Pop<u64>();
LOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk);
LOG_DEBUG(Service_FS, "called.");
// Calculate how many entries we can fit in the output buffer
const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
+86 -66
View File
@@ -93,12 +93,18 @@ public:
}
void LoadNrr(Kernel::HLERequestContext& ctx) {
struct Parameters {
u64_le process_id;
u64_le nrr_address;
u64_le nrr_size;
};
IPC::RequestParser rp{ctx};
rp.Skip(2, false);
const VAddr nrr_addr{rp.Pop<VAddr>()};
const u64 nrr_size{rp.Pop<u64>()};
LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}, nrr_size={:016X}", nrr_addr,
nrr_size);
const auto [process_id, nrr_address, nrr_size] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_LDR,
"called with process_id={:016X}, nrr_address={:016X}, nrr_size={:016X}",
process_id, nrr_address, nrr_size);
if (!initialized) {
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
@@ -116,24 +122,26 @@ public:
}
// NRR Address does not fall on 0x1000 byte boundary
if (!Common::Is4KBAligned(nrr_addr)) {
LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
if (!Common::Is4KBAligned(nrr_address)) {
LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!",
nrr_address);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_ALIGNMENT);
return;
}
// NRR Size is zero or causes overflow
if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || !Common::Is4KBAligned(nrr_size)) {
if (nrr_address + nrr_size <= nrr_address || nrr_size == 0 ||
!Common::Is4KBAligned(nrr_size)) {
LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})",
nrr_addr, nrr_size);
nrr_address, nrr_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_SIZE);
return;
}
// Read NRR data from memory
std::vector<u8> nrr_data(nrr_size);
Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size);
Memory::ReadBlock(nrr_address, nrr_data.data(), nrr_size);
NRRHeader header;
std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
@@ -174,7 +182,7 @@ public:
hashes.emplace_back(hash);
}
nrr.insert_or_assign(nrr_addr, std::move(hashes));
nrr.insert_or_assign(nrr_address, std::move(hashes));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -188,23 +196,30 @@ public:
return;
}
IPC::RequestParser rp{ctx};
rp.Skip(2, false);
const auto nrr_addr{rp.Pop<VAddr>()};
LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}", nrr_addr);
struct Parameters {
u64_le process_id;
u64_le nrr_address;
};
if (!Common::Is4KBAligned(nrr_addr)) {
LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
IPC::RequestParser rp{ctx};
const auto [process_id, nrr_address] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_LDR, "called with process_id={:016X}, nrr_addr={:016X}", process_id,
nrr_address);
if (!Common::Is4KBAligned(nrr_address)) {
LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!",
nrr_address);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_ALIGNMENT);
return;
}
const auto iter = nrr.find(nrr_addr);
const auto iter = nrr.find(nrr_address);
if (iter == nrr.end()) {
LOG_ERROR(Service_LDR,
"Attempting to unload NRR which has not been loaded! (addr={:016X})",
nrr_addr);
nrr_address);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_NRR_ADDRESS);
return;
@@ -216,16 +231,22 @@ public:
}
void LoadNro(Kernel::HLERequestContext& ctx) {
struct Parameters {
u64_le process_id;
u64_le image_address;
u64_le image_size;
u64_le bss_address;
u64_le bss_size;
};
IPC::RequestParser rp{ctx};
rp.Skip(2, false);
const VAddr nro_addr{rp.Pop<VAddr>()};
const u64 nro_size{rp.Pop<u64>()};
const VAddr bss_addr{rp.Pop<VAddr>()};
const u64 bss_size{rp.Pop<u64>()};
LOG_DEBUG(
Service_LDR,
"called with nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, bss_size={:016X}",
nro_addr, nro_size, bss_addr, bss_size);
const auto [process_id, nro_address, nro_size, bss_address, bss_size] =
rp.PopRaw<Parameters>();
LOG_DEBUG(Service_LDR,
"called with pid={:016X}, nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, "
"bss_size={:016X}",
process_id, nro_address, nro_size, bss_address, bss_size);
if (!initialized) {
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
@@ -243,8 +264,9 @@ public:
}
// NRO Address does not fall on 0x1000 byte boundary
if (!Common::Is4KBAligned(nro_addr)) {
LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", nro_addr);
if (!Common::Is4KBAligned(nro_address)) {
LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!",
nro_address);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_ALIGNMENT);
return;
@@ -252,15 +274,15 @@ public:
// NRO Size or BSS Size is zero or causes overflow
const auto nro_size_valid =
nro_size != 0 && nro_addr + nro_size > nro_addr && Common::Is4KBAligned(nro_size);
const auto bss_size_valid =
nro_size + bss_size >= nro_size && (bss_size == 0 || bss_addr + bss_size > bss_addr);
nro_size != 0 && nro_address + nro_size > nro_address && Common::Is4KBAligned(nro_size);
const auto bss_size_valid = nro_size + bss_size >= nro_size &&
(bss_size == 0 || bss_address + bss_size > bss_address);
if (!nro_size_valid || !bss_size_valid) {
LOG_ERROR(Service_LDR,
"NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, "
"bss_address={:016X}, bss_size={:016X})",
nro_addr, nro_size, bss_addr, bss_size);
nro_address, nro_size, bss_address, bss_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_SIZE);
return;
@@ -268,7 +290,7 @@ public:
// Read NRO data from memory
std::vector<u8> nro_data(nro_size);
Memory::ReadBlock(nro_addr, nro_data.data(), nro_size);
Memory::ReadBlock(nro_address, nro_data.data(), nro_size);
SHA256Hash hash{};
mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0);
@@ -318,17 +340,18 @@ public:
return;
}
ASSERT(vm_manager
.MirrorMemory(*map_address, nro_addr, nro_size, Kernel::MemoryState::ModuleCode)
.IsSuccess());
ASSERT(vm_manager.UnmapRange(nro_addr, nro_size).IsSuccess());
ASSERT(
vm_manager
.MirrorMemory(*map_address, nro_address, nro_size, Kernel::MemoryState::ModuleCode)
.IsSuccess());
ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess());
if (bss_size > 0) {
ASSERT(vm_manager
.MirrorMemory(*map_address + nro_size, bss_addr, bss_size,
.MirrorMemory(*map_address + nro_size, bss_address, bss_size,
Kernel::MemoryState::ModuleCode)
.IsSuccess());
ASSERT(vm_manager.UnmapRange(bss_addr, bss_size).IsSuccess());
ASSERT(vm_manager.UnmapRange(bss_address, bss_size).IsSuccess());
}
vm_manager.ReprotectRange(*map_address, header.text_size,
@@ -348,13 +371,6 @@ public:
}
void UnloadNro(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
rp.Skip(2, false);
const VAddr mapped_addr{rp.PopRaw<VAddr>()};
const VAddr heap_addr{rp.PopRaw<VAddr>()};
LOG_DEBUG(Service_LDR, "called with mapped_addr={:016X}, heap_addr={:016X}", mapped_addr,
heap_addr);
if (!initialized) {
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
IPC::ResponseBuilder rb{ctx, 2};
@@ -362,22 +378,30 @@ public:
return;
}
if (!Common::Is4KBAligned(mapped_addr) || !Common::Is4KBAligned(heap_addr)) {
LOG_ERROR(Service_LDR,
"NRO/BSS Address has invalid alignment (actual nro_addr={:016X}, "
"bss_addr={:016X})!",
mapped_addr, heap_addr);
struct Parameters {
u64_le process_id;
u64_le nro_address;
};
IPC::RequestParser rp{ctx};
const auto [process_id, nro_address] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_LDR, "called with process_id={:016X}, nro_address=0x{:016X}", process_id,
nro_address);
if (!Common::Is4KBAligned(nro_address)) {
LOG_ERROR(Service_LDR, "NRO address has invalid alignment (nro_address=0x{:016X})",
nro_address);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_ALIGNMENT);
return;
}
const auto iter = nro.find(mapped_addr);
const auto iter = nro.find(nro_address);
if (iter == nro.end()) {
LOG_ERROR(Service_LDR,
"The NRO attempting to unmap was not mapped or has an invalid address "
"(actual {:016X})!",
mapped_addr);
"The NRO attempting to be unmapped was not mapped or has an invalid address "
"(nro_address=0x{:016X})!",
nro_address);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_INVALID_NRO_ADDRESS);
return;
@@ -386,10 +410,7 @@ public:
auto& vm_manager = Core::CurrentProcess()->VMManager();
const auto& nro_size = iter->second.size;
ASSERT(vm_manager
.MirrorMemory(heap_addr, mapped_addr, nro_size, Kernel::MemoryState::ModuleCode)
.IsSuccess());
ASSERT(vm_manager.UnmapRange(mapped_addr, nro_size).IsSuccess());
ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess());
Core::System::GetInstance().InvalidateCpuInstructionCaches();
@@ -459,11 +480,10 @@ private:
std::map<VAddr, NROInfo> nro;
std::map<VAddr, std::vector<SHA256Hash>> nrr;
bool IsValidNROHash(const SHA256Hash& hash) {
return std::any_of(
nrr.begin(), nrr.end(), [&hash](const std::pair<VAddr, std::vector<SHA256Hash>>& p) {
return std::find(p.second.begin(), p.second.end(), hash) != p.second.end();
});
bool IsValidNROHash(const SHA256Hash& hash) const {
return std::any_of(nrr.begin(), nrr.end(), [&hash](const auto& p) {
return std::find(p.second.begin(), p.second.end(), hash) != p.second.end();
});
}
static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
+10 -6
View File
@@ -21,12 +21,13 @@
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/perf_stats.h"
#include "core/settings.h"
#include "video_core/renderer_base.h"
namespace Service::NVFlinger {
constexpr std::size_t SCREEN_REFRESH_RATE = 60;
constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30);
NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} {
displays.emplace_back(0, "Default");
@@ -36,13 +37,15 @@ NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_t
displays.emplace_back(4, "Null");
// Schedule the screen composition events
composition_event =
core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) {
const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : frame_ticks;
composition_event = core_timing.RegisterEvent(
"ScreenComposition", [this, ticks](u64 userdata, s64 cycles_late) {
Compose();
this->core_timing.ScheduleEvent(frame_ticks - cycles_late, composition_event);
this->core_timing.ScheduleEvent(ticks - cycles_late, composition_event);
});
core_timing.ScheduleEvent(frame_ticks, composition_event);
core_timing.ScheduleEvent(ticks, composition_event);
}
NVFlinger::~NVFlinger() {
@@ -62,6 +65,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
const auto itr =
std::find_if(displays.begin(), displays.end(),
[&](const VI::Display& display) { return display.GetName() == name; });
if (itr == displays.end()) {
return {};
}
+4 -2
View File
@@ -21,6 +21,8 @@
#include "core/memory.h"
#include "core/settings.h"
#pragma optimize("", off)
namespace Loader {
namespace {
struct MODHeader {
@@ -136,13 +138,13 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
// Apply patches if necessary
if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
std::vector<u8> pi_header(sizeof(NSOHeader) + program_image.size());
std::vector<u8> pi_header;
pi_header.insert(pi_header.begin(), reinterpret_cast<u8*>(&nso_header),
reinterpret_cast<u8*>(&nso_header) + sizeof(NSOHeader));
pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.begin(),
program_image.end());
pi_header = pm->PatchNSO(pi_header);
pi_header = pm->PatchNSO(pi_header, file.GetName());
std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.begin());
}
-4
View File
@@ -38,10 +38,6 @@ void SetCurrentPageTable(Common::PageTable* page_table) {
}
}
Common::PageTable* GetCurrentPageTable() {
return current_page_table;
}
static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory,
Common::PageType type) {
LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
+1 -12
View File
@@ -28,16 +28,6 @@ constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
/// Virtual user-space memory regions
enum : VAddr {
/// Read-only page containing kernel and system configuration values.
CONFIG_MEMORY_VADDR = 0x1FF80000,
CONFIG_MEMORY_SIZE = 0x00001000,
CONFIG_MEMORY_VADDR_END = CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE,
/// Usually read-only page containing mostly values read from hardware.
SHARED_PAGE_VADDR = 0x1FF81000,
SHARED_PAGE_SIZE = 0x00001000,
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
/// TLS (Thread-Local Storage) related.
TLS_ENTRY_SIZE = 0x200,
@@ -50,9 +40,8 @@ enum : VAddr {
KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
};
/// Currently active page table
/// Changes the currently active page table.
void SetCurrentPageTable(Common::PageTable* page_table);
Common::PageTable* GetCurrentPageTable();
/// Determines if the given VAddr is valid for the specified process.
bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
+1
View File
@@ -393,6 +393,7 @@ struct Values {
bool use_disk_shader_cache;
bool use_accurate_gpu_emulation;
bool use_asynchronous_gpu_emulation;
bool force_30fps_mode;
float bg_red;
float bg_green;
+1 -2
View File
@@ -17,7 +17,6 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
: mutable_memory(mutable_memory_),
test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} {
auto process = Kernel::Process::Create(Core::System::GetInstance(), "");
kernel.MakeCurrentProcess(process.get());
page_table = &process->VMManager().page_table;
std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
@@ -28,7 +27,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
Memory::SetCurrentPageTable(page_table);
kernel.MakeCurrentProcess(process.get());
}
TestEnvironment::~TestEnvironment() {
+8 -1
View File
@@ -106,6 +106,8 @@ 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
)
@@ -127,12 +129,14 @@ if (ENABLE_VULKAN)
renderer_vulkan/vk_sampler_cache.h
renderer_vulkan/vk_scheduler.cpp
renderer_vulkan/vk_scheduler.h
renderer_vulkan/vk_shader_decompiler.cpp
renderer_vulkan/vk_shader_decompiler.h
renderer_vulkan/vk_stream_buffer.cpp
renderer_vulkan/vk_stream_buffer.h
renderer_vulkan/vk_swapchain.cpp
renderer_vulkan/vk_swapchain.h)
target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include)
target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
target_compile_definitions(video_core PRIVATE HAS_VULKAN)
endif()
@@ -140,3 +144,6 @@ create_target_directory_groups(video_core)
target_link_libraries(video_core PUBLIC common core)
target_link_libraries(video_core PRIVATE glad)
if (ENABLE_VULKAN)
target_link_libraries(video_core PRIVATE sirit)
endif()
+1
View File
@@ -8,6 +8,7 @@
#include "video_core/dma_pusher.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
namespace Tegra {
+2 -1
View File
@@ -6,12 +6,13 @@
#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"
namespace Tegra::Engines {
Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
: memory_manager(memory_manager), rasterizer{rasterizer} {}
: rasterizer{rasterizer}, memory_manager{memory_manager} {}
void Fermi2D::CallMethod(const GPU::MethodCall& method_call) {
ASSERT_MSG(method_call.method < Regs::NUM_REGS,
+5 -3
View File
@@ -10,7 +10,10 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
namespace Tegra {
class MemoryManager;
}
namespace VideoCore {
class RasterizerInterface;
@@ -115,10 +118,9 @@ public:
};
} regs{};
MemoryManager& memory_manager;
private:
VideoCore::RasterizerInterface& rasterizer;
MemoryManager& memory_manager;
/// Performs the copy from the source surface to the destination surface as configured in the
/// registers.
+7 -3
View File
@@ -9,7 +9,10 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
namespace Tegra {
class MemoryManager;
}
namespace Tegra::Engines {
@@ -40,10 +43,11 @@ public:
static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32),
"KeplerCompute Regs has wrong size");
MemoryManager& memory_manager;
/// Write the value to the register identified by method.
void CallMethod(const GPU::MethodCall& method_call);
private:
MemoryManager& memory_manager;
};
#define ASSERT_REG_POSITION(field_name, position) \
+2 -2
View File
@@ -5,9 +5,9 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/kepler_memory.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
@@ -15,7 +15,7 @@ namespace Tegra::Engines {
KeplerMemory::KeplerMemory(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
MemoryManager& memory_manager)
: system{system}, memory_manager(memory_manager), rasterizer{rasterizer} {}
: system{system}, rasterizer{rasterizer}, memory_manager{memory_manager} {}
KeplerMemory::~KeplerMemory() = default;
+5 -2
View File
@@ -10,12 +10,15 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
namespace Core {
class System;
}
namespace Tegra {
class MemoryManager;
}
namespace VideoCore {
class RasterizerInterface;
}
@@ -82,8 +85,8 @@ public:
private:
Core::System& system;
MemoryManager& memory_manager;
VideoCore::RasterizerInterface& rasterizer;
MemoryManager& memory_manager;
void ProcessData(u32 data);
};
+15 -4
View File
@@ -7,11 +7,10 @@
#include "common/assert.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/memory.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
#include "video_core/textures/texture.h"
namespace Tegra::Engines {
@@ -21,8 +20,8 @@ constexpr u32 MacroRegistersStart = 0xE00;
Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
MemoryManager& memory_manager)
: memory_manager(memory_manager), system{system}, rasterizer{rasterizer},
macro_interpreter(*this) {
: system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, macro_interpreter{
*this} {
InitializeRegisterDefaults();
}
@@ -250,6 +249,10 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
ProcessQueryGet();
break;
}
case MAXWELL3D_REG_INDEX(sync_info): {
ProcessSyncPoint();
break;
}
default:
break;
}
@@ -327,6 +330,14 @@ void Maxwell3D::ProcessQueryGet() {
}
}
void Maxwell3D::ProcessSyncPoint() {
const u32 sync_point = regs.sync_info.sync_point.Value();
const u32 increment = regs.sync_info.increment.Value();
const u32 cache_flush = regs.sync_info.unknown.Value();
LOG_DEBUG(HW_GPU, "Syncpoint set {}, increment: {}, unk: {}", sync_point, increment,
cache_flush);
}
void Maxwell3D::DrawArrays() {
LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
regs.vertex_buffer.count);
+21 -3
View File
@@ -16,13 +16,16 @@
#include "common/math_util.h"
#include "video_core/gpu.h"
#include "video_core/macro_interpreter.h"
#include "video_core/memory_manager.h"
#include "video_core/textures/texture.h"
namespace Core {
class System;
}
namespace Tegra {
class MemoryManager;
}
namespace VideoCore {
class RasterizerInterface;
}
@@ -576,7 +579,17 @@ public:
u32 bind;
} macros;
INSERT_PADDING_WORDS(0x188);
INSERT_PADDING_WORDS(0x69);
struct {
union {
BitField<0, 16, u32> sync_point;
BitField<16, 1, u32> unknown;
BitField<20, 1, u32> increment;
};
} sync_info;
INSERT_PADDING_WORDS(0x11E);
u32 tfb_enabled;
@@ -1093,7 +1106,6 @@ public:
};
State state{};
MemoryManager& memory_manager;
struct DirtyFlags {
std::bitset<8> color_buffer{0xFF};
@@ -1141,6 +1153,8 @@ private:
VideoCore::RasterizerInterface& rasterizer;
MemoryManager& memory_manager;
/// Start offsets of each macro in macro_memory
std::unordered_map<u32, u32> macro_offsets;
@@ -1180,6 +1194,9 @@ private:
/// Handles a write to the QUERY_GET register.
void ProcessQueryGet();
/// Handles writes to syncing register.
void ProcessSyncPoint();
/// Handles a write to the CB_DATA[i] register.
void ProcessCBData(u32 value);
@@ -1195,6 +1212,7 @@ private:
"Field " #field_name " has invalid position")
ASSERT_REG_POSITION(macros, 0x45);
ASSERT_REG_POSITION(sync_info, 0xB2);
ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
ASSERT_REG_POSITION(rt, 0x200);
ASSERT_REG_POSITION(viewport_transform, 0x280);
+2 -2
View File
@@ -5,9 +5,9 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/maxwell_dma.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
#include "video_core/textures/decoders.h"
@@ -16,7 +16,7 @@ namespace Tegra::Engines {
MaxwellDMA::MaxwellDMA(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
MemoryManager& memory_manager)
: memory_manager(memory_manager), system{system}, rasterizer{rasterizer} {}
: system{system}, rasterizer{rasterizer}, memory_manager{memory_manager} {}
void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) {
ASSERT_MSG(method_call.method < Regs::NUM_REGS,
+6 -3
View File
@@ -10,12 +10,15 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
namespace Core {
class System;
}
namespace Tegra {
class MemoryManager;
}
namespace VideoCore {
class RasterizerInterface;
}
@@ -139,13 +142,13 @@ public:
};
} regs{};
MemoryManager& memory_manager;
private:
Core::System& system;
VideoCore::RasterizerInterface& rasterizer;
MemoryManager& memory_manager;
/// Performs the copy from the source buffer to the destination buffer as configured in the
/// registers.
void HandleCopy();
+4 -1
View File
@@ -1238,13 +1238,16 @@ union Instruction {
union {
BitField<20, 16, u64> imm20_16;
BitField<35, 1, u64> high_b_rr; // used on RR
BitField<36, 1, u64> product_shift_left;
BitField<37, 1, u64> merge_37;
BitField<48, 1, u64> sign_a;
BitField<49, 1, u64> sign_b;
BitField<50, 2, XmadMode> mode_cbf; // used by CR, RC
BitField<50, 3, XmadMode> mode;
BitField<52, 1, u64> high_b;
BitField<53, 1, u64> high_a;
BitField<55, 1, u64> product_shift_left_second; // used on CR
BitField<56, 1, u64> merge_56;
} xmad;
@@ -1662,7 +1665,7 @@ private:
INST("0011011-11110---", Id::BFI_IMM_R, Type::Bfi, "BFI_IMM_R"),
INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"),
INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"),
INST("0011100001000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"),
INST("0011100-01000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"),
INST("000001----------", Id::LOP32I, Type::ArithmeticIntegerImmediate, "LOP32I"),
INST("0000001---------", Id::LOP3_C, Type::ArithmeticInteger, "LOP3_C"),
INST("0101101111100---", Id::LOP3_R, Type::ArithmeticInteger, "LOP3_R"),
+1 -1
View File
@@ -31,7 +31,7 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer) : renderer{renderer} {
auto& rasterizer{renderer.Rasterizer()};
memory_manager = std::make_unique<Tegra::MemoryManager>();
memory_manager = std::make_unique<Tegra::MemoryManager>(rasterizer);
dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
+77 -10
View File
@@ -5,16 +5,13 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
namespace Tegra {
MemoryManager::MemoryManager() {
MemoryManager::MemoryManager(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {
std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
std::fill(page_table.attributes.begin(), page_table.attributes.end(),
Common::PageType::Unmapped);
@@ -70,8 +67,7 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
const u64 aligned_size{Common::AlignUp(size, page_size)};
const CacheAddr cache_addr{ToCacheAddr(GetPointer(gpu_addr))};
Core::System::GetInstance().Renderer().Rasterizer().FlushAndInvalidateRegion(cache_addr,
aligned_size);
rasterizer.FlushAndInvalidateRegion(cache_addr, aligned_size);
UnmapRange(gpu_addr, aligned_size);
return gpu_addr;
@@ -204,14 +200,85 @@ const u8* MemoryManager::GetPointer(GPUVAddr addr) const {
}
void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const {
std::memcpy(dest_buffer, GetPointer(src_addr), size);
std::size_t remaining_size{size};
std::size_t page_index{src_addr >> page_bits};
std::size_t page_offset{src_addr & page_mask};
while (remaining_size > 0) {
const std::size_t copy_amount{
std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
switch (page_table.attributes[page_index]) {
case Common::PageType::Memory: {
const u8* src_ptr{page_table.pointers[page_index] + page_offset};
rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
std::memcpy(dest_buffer, src_ptr, copy_amount);
break;
}
default:
UNREACHABLE();
}
page_index++;
page_offset = 0;
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
remaining_size -= copy_amount;
}
}
void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size) {
std::memcpy(GetPointer(dest_addr), src_buffer, size);
std::size_t remaining_size{size};
std::size_t page_index{dest_addr >> page_bits};
std::size_t page_offset{dest_addr & page_mask};
while (remaining_size > 0) {
const std::size_t copy_amount{
std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
switch (page_table.attributes[page_index]) {
case Common::PageType::Memory: {
u8* dest_ptr{page_table.pointers[page_index] + page_offset};
rasterizer.InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
std::memcpy(dest_ptr, src_buffer, copy_amount);
break;
}
default:
UNREACHABLE();
}
page_index++;
page_offset = 0;
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
remaining_size -= copy_amount;
}
}
void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size) {
std::memcpy(GetPointer(dest_addr), GetPointer(src_addr), size);
std::size_t remaining_size{size};
std::size_t page_index{src_addr >> page_bits};
std::size_t page_offset{src_addr & page_mask};
while (remaining_size > 0) {
const std::size_t copy_amount{
std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
switch (page_table.attributes[page_index]) {
case Common::PageType::Memory: {
const u8* src_ptr{page_table.pointers[page_index] + page_offset};
rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
WriteBlock(dest_addr, src_ptr, copy_amount);
break;
}
default:
UNREACHABLE();
}
page_index++;
page_offset = 0;
dest_addr += static_cast<VAddr>(copy_amount);
src_addr += static_cast<VAddr>(copy_amount);
remaining_size -= copy_amount;
}
}
void MemoryManager::MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
@@ -351,7 +418,7 @@ MemoryManager::VMAIter MemoryManager::CarveVMA(GPUVAddr base, u64 size) {
const VirtualMemoryArea& vma{vma_handle->second};
if (vma.type == VirtualMemoryArea::Type::Mapped) {
// Region is already allocated
return {};
return vma_handle;
}
const VAddr start_in_vma{base - vma.base};
+6 -1
View File
@@ -10,6 +10,10 @@
#include "common/common_types.h"
#include "common/page_table.h"
namespace VideoCore {
class RasterizerInterface;
}
namespace Tegra {
/**
@@ -43,7 +47,7 @@ struct VirtualMemoryArea {
class MemoryManager final {
public:
MemoryManager();
MemoryManager(VideoCore::RasterizerInterface& rasterizer);
GPUVAddr AllocateSpace(u64 size, u64 align);
GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
@@ -144,6 +148,7 @@ private:
Common::PageTable page_table{page_bits};
VMAMap vma_map;
VideoCore::RasterizerInterface& rasterizer;
};
} // namespace Tegra

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