Compare commits

...

563 Commits

Author SHA1 Message Date
bunnei
93e20867b0 hle: kernel: Migrate PageHeap/PageTable to KPageHeap/KPageTable. 2021-02-18 16:16:25 -08:00
bunnei
b1e27890e8 hle: kernel: Migrate MemoryManager to KMemoryManager. 2021-02-18 16:16:25 -08:00
bunnei
93109c870e hle: kernel: Migrate PageLinkedList to KPageLinkedList. 2021-02-18 16:16:25 -08:00
bunnei
65e0178cc0 hle: kernel: Migrate to KMemoryBlock, KMemoryBlockManager, and others. 2021-02-18 16:16:25 -08:00
bunnei
9e520e8f12 hle: kernel: Migrate SlabHeap to KSlabHeap. 2021-02-18 16:16:25 -08:00
bunnei
1d162f28d1 hle: kernel: Migrate MemoryLayout to KMemoryLayout. 2021-02-18 16:16:25 -08:00
bunnei
7ed5dd0d62 hle: kernel: Migrate AddressSpaceInfo to KAddressSpaceInfo. 2021-02-18 16:16:25 -08:00
bunnei
701ef616b2 hle: kernel: memory_manager: Rename AllocateContinuous to AllocateContinuous. 2021-02-18 16:16:24 -08:00
bunnei
f7a008d77f hle: kernel: KSystemControl does not belong in Memory namespace. 2021-02-18 16:16:24 -08:00
bunnei
6a19086001 hle: kernel: memory: PageHeap: Migrate to KPageBitmap class. 2021-02-18 16:16:24 -08:00
bunnei
a02566136c hle: kernel: Add KPageBitmap class. 2021-02-18 16:16:24 -08:00
bunnei
e7c33d1ad6 hle: kernel: system_control: Add function GenerateRandomU64. 2021-02-18 16:16:24 -08:00
bunnei
c9235764c7 common: Add implementation of TinyMT (Mersenne Twister RNG). 2021-02-18 16:16:24 -08:00
bunnei
6da91da08e hle: kernel: Add KSpinLock implementation. 2021-02-18 16:16:24 -08:00
bunnei
24e1e17a8a core: memory: Add templated GetPointer methods. 2021-02-18 16:16:24 -08:00
bunnei
b5b92fd1e5 common: alignment: Add DivideUp utility method. 2021-02-18 16:16:24 -08:00
bunnei
0d62f30b00 hle: kernel: Rename SharedMemory to KSharedMemory. 2021-02-18 16:16:12 -08:00
bunnei
51e8b2733c Merge pull request #5957 from lat9nq/update-dynarmic
externals: Update dynarmic to latest
2021-02-18 15:53:44 -08:00
bunnei
9cae3e6e90 Merge pull request #4973 from ameerj/nvdec-opt
nvdec: Reuse allocated buffers and general cleanup
2021-02-18 15:12:07 -08:00
lat9nq
0c24ae300c externals: Update dynarmic to latest
Updates dynarmic to its latest commit. Includes a fix for argument
limits while compiling with Clang 12.
2021-02-18 14:44:49 -05:00
Morph
6686468df0 Merge pull request #5955 from yuzu-emu/revert-3603-port-5123
Revert "Port citra-emu/citra#5123: "SDL: Disable hidapi drivers due to compatibility problems with certain controllers""
2021-02-19 00:26:02 +08:00
Morph
1c550ff954 Revert "Port citra-emu/citra#5123: "SDL: Disable hidapi drivers due to compatibility problems with certain controllers"" 2021-02-18 11:16:14 -05:00
LC
c864f2c532 Merge pull request #5952 from ReinUsesLisp/cityhash
common/cityhash: Use common types
2021-02-18 04:28:54 -05:00
LC
90f93a408a Merge pull request #5954 from lat9nq/ffmpeg-431-2
cmake: Update FFmpeg to 4.3.1
2021-02-18 04:26:59 -05:00
ReinUsesLisp
f3805376f7 common/cityhash: Use common types
Allow sharing return types with the rest of the code base. For example,
we use 'u128 = std::array<u64, 2>', meanwhile Google's code uses
'uint128 = std::pair<u64, u64>'.

While we are at it, use size_t instead of std::size_t.
2021-02-18 00:45:17 -03:00
ReinUsesLisp
9ca5e52f07 tests: Add tests for CityHash 2021-02-18 00:44:57 -03:00
bunnei
6be0975bf2 Merge pull request #5121 from bunnei/optimize-core-timing
core: Optimize core timing utility functions to avoid unnecessary math
2021-02-16 13:17:22 -08:00
Morph
723e038dba Merge pull request #5929 from german77/mousePanning
Improve mouse panning
2021-02-16 22:52:35 +08:00
bunnei
aaccb21f81 Merge pull request #4298 from FearlessTobi/remove-cache-setting
yuzu/configure_filesystem: Remove "Select Cache Directory" option
2021-02-15 20:31:16 -08:00
LC
df1a9d09a9 Merge pull request #5942 from ReinUsesLisp/fixup-rebase
vk_rasterizer: Fix loading shader addresses twice
2021-02-15 19:35:56 -05:00
ReinUsesLisp
24d0cc3ab8 vk_rasterizer: Fix loading shader addresses twice
This was recently introduced on a wrongly rebased commit.
2021-02-15 21:34:13 -03:00
bunnei
86212d4bcd Merge pull request #3603 from FearlessTobi/port-5123
Port citra-emu/citra#5123: "SDL: Disable hidapi drivers due to compatibility problems with certain controllers"
2021-02-15 16:25:53 -08:00
bunnei
f3345e84ad core: core_timing_util: Optimize core timing math.
- Avoids a lot of unnecessary 128-bit math for imperceptible accuracy.
2021-02-15 14:54:06 -08:00
bunnei
592a649918 common: wall_clock: Optimize GetClockCycles/GetCPUCycles to use a single MUL instruction. 2021-02-15 14:51:43 -08:00
bunnei
0a91599aec common: Merge uint128 to a single header file with inlines. 2021-02-15 14:46:04 -08:00
bunnei
cffa6f4e62 Merge pull request #5923 from ReinUsesLisp/vk-dirty-pipeline
fixed_pipeline_cache: Use dirty flags to lazily update key
2021-02-15 13:17:27 -08:00
LC
ed543c4d5c Merge pull request #5939 from Morph1984/web_types
core/CMakeLists: Add web_types.h
2021-02-15 14:02:10 -05:00
bunnei
b53b50adec Merge pull request #4940 from german77/nativeGC
HID: Implement GC controller in game
2021-02-15 10:32:19 -08:00
Morph
48cfc47050 core/CMakeLists: Add web_types.h 2021-02-15 09:40:30 -05:00
bunnei
90610bde9b Merge pull request #5935 from lat9nq/controller_access_keys
debugger: controller: Add access key
2021-02-14 22:33:59 -08:00
bunnei
8378b8a61f Merge pull request #5909 from ogniK5377/I3dl2Reverb
audren: Implement I3dl2Reverb
2021-02-14 20:09:15 -08:00
lat9nq
6269cd7f1d debugger: controller: Add access key
Adds the access key to the Controller P1 selection at View -> Debugger
-> Controller P1. Avoids using the windowTitle as that would add a
literal & to the beginning of the window title.
2021-02-14 16:10:12 -05:00
bunnei
b0a3915351 Merge pull request #5920 from bunnei/am-ldn-fix
Fix LDN Initialization return code & resulting AM overflow
2021-02-14 02:46:01 -08:00
bunnei
eae9f2e440 yuzu: Various frontend improvements to avoid crashes and improve experience on Linux. 2021-02-14 00:20:41 -08:00
bunnei
d9a8060ce3 hle: service: ldn: IUserLocalCommunicationService: Improve the stub. 2021-02-13 21:45:09 -08:00
german
594973bdd2 Improve mouse panning 2021-02-13 22:23:32 -06:00
bunnei
51c13606d6 hle: service: ldn: IUserLocalCommunicationService: Indicate that LDN is disabled.
- Fixes crash on Pokemon Sword/Shield when pressing 'Y'.
2021-02-13 20:11:26 -08:00
bunnei
d25011c92f hle: service: am: IStorageAccessor: Fix out of bounds error handling. 2021-02-13 20:11:26 -08:00
LC
0bbf5e61f1 Merge pull request #5925 from ReinUsesLisp/resource-pool-clean
vk_resource_pool: Load GPU tick once and compare with it
2021-02-13 20:57:44 -05:00
ReinUsesLisp
b8ffdbb167 vk_resource_pool: Load GPU tick once and compare with it
Other minor style improvements. Rename free_iterator to hint_iterator,
to describe better what it does.
2021-02-13 17:53:58 -03:00
ReinUsesLisp
70353649d7 fixed_pipeline_cache: Use dirty flags to lazily update key
Use dirty flags to avoid building pipeline key from scratch on each draw
call. This saves a bit of unnecesary work on each draw call.
2021-02-13 17:44:47 -03:00
Rodrigo Locatti
95722823b9 Merge pull request #5921 from ameerj/srgb-views
gl_texture_cache: Lazily create non-sRGB texture views for sRGB formats
2021-02-13 16:51:53 -03:00
ameerj
c7325c6a4c gl_texture_cache: Lazily create non-sRGB texture views for sRGB formats
This creates non-sRGB texture views for sRGB texture formats to allow for interfacing with these views in compute shaders using imageLoad and imageStore.

Co-Authored-By: Rodrigo Locatti <reinuseslisp@airmail.cc>
2021-02-13 13:27:50 -05:00
ameerj
b675c44e49 rebase, fix name shadowing, more const 2021-02-13 13:07:56 -05:00
ameerj
3c37d66c28 Address PR feedback
Co-Authored-By: LC <712067+lioncash@users.noreply.github.com>
2021-02-13 13:07:56 -05:00
ameerj
09722cb4a7 streamline cdma_pusher/command_classes 2021-02-13 13:07:56 -05:00
ameerj
77564f987c streamline cdma_pusher/command_classes 2021-02-13 13:07:53 -05:00
ameerj
ac265a72ce nvdec cleanup 2021-02-13 13:07:31 -05:00
Morph
83227ad981 Merge pull request #5919 from ReinUsesLisp/stream-buffer-tragic
gl_stream_buffer/vk_staging_buffer_pool: Fix size check
2021-02-13 21:25:45 +08:00
ReinUsesLisp
dd9caf9aa0 vk_master_semaphore: Mark gpu_tick atomic operations with relaxed order 2021-02-13 05:57:28 -03:00
ReinUsesLisp
6171566296 vk_staging_buffer_pool: Inline tick tests
Load the current tick to a local variable, moving it out of an atomic
and allowing us to compare the value without going through a pointer
each time. This should make the loop more optimizable.
2021-02-13 05:14:11 -03:00
ReinUsesLisp
682d82faf3 gl_stream_buffer/vk_staging_buffer_pool: Fix size check
Fix a tragic off-by-one condition that causes Vulkan's stream buffer to
think it's always full, using fallback memory. The OpenGL was also
affected by this bug to a lesser extent.
2021-02-13 05:11:48 -03:00
LC
710aa22f7c Merge pull request #5915 from lat9nq/screenshots-dir-fix
yuzu: Create screenshot path before capture
2021-02-13 02:56:23 -05:00
LC
6f1ad6aa9f Merge pull request #5916 from ameerj/maxwell-gl-unused
maxwell_to_gl: Remove unused code
2021-02-13 02:55:59 -05:00
LC
06e3d3a658 Merge pull request #5917 from ReinUsesLisp/require-robustness2
vulkan_device: Require VK_EXT_robustness2
2021-02-13 02:55:31 -05:00
ReinUsesLisp
757fd1e917 vulkan_device: Require VK_EXT_robustness2
We are already using robustness2 features without requiring it
explicitly, causing potential crashes on drivers without the extension.
Requiring this at boot allows better diagnostics for it and formalizes
our usage on the extension.
2021-02-13 03:31:50 -03:00
bunnei
d3c7a7e7cf Merge pull request #5741 from ReinUsesLisp/new-bufcache
video_core: Reimplement the buffer cache
2021-02-12 22:22:18 -08:00
ReinUsesLisp
13becdf18a config: Make high GPU accuracy the default
This is a better default for most games, yielding better performance and
less graphical issues.
2021-02-13 02:38:05 -03:00
ReinUsesLisp
5b35b01070 video_core: Fix clang build issues 2021-02-13 02:26:47 -03:00
ReinUsesLisp
025fe458ae vk_staging_buffer_pool: Fix softlock when stream buffer overflows
There was still a code path that could wait on a timeline semaphore tick
that would never be signalled.

While we are at it, make use of more STL algorithms.
2021-02-13 02:18:38 -03:00
ReinUsesLisp
3a2eefb16c vk_buffer_cache: Add support for null index buffers
Games can bind a null index buffer (size=0) where all indices are
evaluated as zero. VK_EXT_robustness2 doesn't support this and all
drivers segfault when a null index buffer is passed to
vkCmdBindIndexBuffer.

Workaround this by creating a 4 byte buffer and filling it with zeroes.
If it's read out of bounds, robustness takes care of returning zeroes as
indices.
2021-02-13 02:18:38 -03:00
ReinUsesLisp
0b8b961442 buffer_cache: Add extra bytes to guest SSBOs
Bind extra bytes beyond the guest API's bound range.
This is due to some games like Astral Chain operating out of bounds.
Binding the whole map range would be technically correct, but games
have large maps that make this approach unaffordable for now.
2021-02-13 02:18:38 -03:00
ReinUsesLisp
93a69b6cc8 Merge branch 'bytes-to-map-end' into new-bufcache-wip 2021-02-13 02:18:35 -03:00
ReinUsesLisp
7402442442 vk_staging_buffer_pool: Get a staging buffer instead of waiting
Avoids waiting idle while the GPU finishes to do work, and fixes an
issue where we'd wait forever if a single command buffer (logic tick)
all the data.
2021-02-13 02:18:05 -03:00
ReinUsesLisp
75fd3f95a3 yuzu/config: Disable assembly shaders by default
Due to BindBufferRangeNV limitations and poor quality code emission from
our side, assembly shaders are currently slower than GLSL. Their build
time and feature advantages are still relevant, but they are outweighted
by their runtime performance.
2021-02-13 02:18:05 -03:00
ReinUsesLisp
0b631f22fc renderer_opengl: Remove interop
Remove unused interop code from the OpenGL backend.
2021-02-13 02:18:04 -03:00
ReinUsesLisp
3da87d3f12 gl_buffer_cache: Drop interop based parameter buffer workarounds
Sacrify runtime performance to avoid generating kernel exceptions on
Windows due to our abusive aliasing of interop buffer objects.
2021-02-13 02:17:24 -03:00
ReinUsesLisp
2b95c137ff buffer_cache: Heuristically detect stream buffers
Detect when a memory region has been joined several times and increase
the size of the created buffer on those instances. The buffer is assumed
to be a "stream buffer", increasing its size should stop us from
constantly recreating it and fragmenting memory.
2021-02-13 02:17:24 -03:00
ReinUsesLisp
ec9354d6d9 buffer_cache: Split CreateBuffer in separate functions
Allow adding functionality to each function without making CreateBuffer
more complex.
2021-02-13 02:17:24 -03:00
ReinUsesLisp
a02b4e1df6 buffer_cache: Skip cache on small uploads on Vulkan
Ports from OpenGL the optimization to skip small 3D uniform buffer
uploads. This will take advantage of the previously introduced stream
buffer.

Fixes instances where the staging buffer offset was being ignored.
2021-02-13 02:17:24 -03:00
ReinUsesLisp
35df1d1864 vk_staging_buffer_pool: Add stream buffer for small uploads
This uses a ring buffer similar to OpenGL's stream buffer for small
uploads. This stops us from allocating several small buffers, reducing
memory fragmentation and cache locality.

It uses dedicated allocations when possible.
2021-02-13 02:17:24 -03:00
ReinUsesLisp
8fd518ec40 vulkan_device: Enable robustBufferAccess
Fix regression on Pascal on Animal Crossing: New Horizons, fixing a
validation error.
2021-02-13 02:17:23 -03:00
ReinUsesLisp
82c2601555 video_core: Reimplement the buffer cache
Reimplement the buffer cache using cached bindings and page level
granularity for modification tracking. This also drops the usage of
shared pointers and virtual functions from the cache.

- Bindings are cached, allowing to skip work when the game changes few
  bits between draws.
- OpenGL Assembly shaders no longer copy when a region has been modified
  from the GPU to emulate constant buffers, instead GL_EXT_memory_object
  is used to alias sub-buffers within the same allocation.
- OpenGL Assembly shaders stream constant buffer data using
  glProgramBufferParametersIuivNV, from NV_parameter_buffer_object. In
  theory this should save one hash table resolve inside the driver
  compared to glBufferSubData.
- A new OpenGL stream buffer is implemented based on fences for drivers
  that are not Nvidia's proprietary, due to their low performance on
  partial glBufferSubData calls synchronized with 3D rendering (that
  some games use a lot).
- Most optimizations are shared between APIs now, allowing Vulkan to
  cache more bindings than before, skipping unnecesarry work.

This commit adds the necessary infrastructure to use Vulkan object from
OpenGL. Overall, it improves performance and fixes some bugs present on
the old cache. There are still some edge cases hit by some games that
harm performance on some vendors, this are planned to be fixed in later
commits.
2021-02-13 02:17:22 -03:00
ReinUsesLisp
a39d9c5194 vulkan_common: Expose interop and headless devices 2021-02-13 02:16:21 -03:00
ReinUsesLisp
47d5ec6cfc vulkan_common: Make interop extensions mandatory 2021-02-13 02:16:21 -03:00
ReinUsesLisp
40ed0cb920 vulkan_device: Enable robust buffers 2021-02-13 02:16:21 -03:00
ReinUsesLisp
1a987054c5 vulkan_device: Use designated initializers for features 2021-02-13 02:16:21 -03:00
ReinUsesLisp
79afdeaf08 vulkan_wrapper: Add memory barrier pipeline barrier helper 2021-02-13 02:16:21 -03:00
ReinUsesLisp
004a8d6a7a vulkan_device: Fix formatting of constants 2021-02-13 02:16:21 -03:00
ReinUsesLisp
16f97ded21 vulkan_wrapper: Add interop functions 2021-02-13 02:16:21 -03:00
ReinUsesLisp
9735c34f5d vulkan_instance: Initialize Vulkan instance in a separate thread
Workaround an issue on Nvidia where creating a Vulkan instance from an
active OpenGL thread disables threaded optimization on the driver.
This optimization is important to have good performance on Nvidia
OpenGL.
2021-02-13 02:16:21 -03:00
ReinUsesLisp
dde19e7d75 vulkan_wrapper: Pull Windows symbols 2021-02-13 02:16:21 -03:00
ReinUsesLisp
75ccd9959c gpu: Report renderer errors with exceptions
Instead of using a two step initialization to report errors, initialize
the GPU renderer and rasterizer on the constructor and report errors
through std::runtime_error.
2021-02-13 02:16:19 -03:00
ReinUsesLisp
19156292a3 tests/buffer_base: Add cached CPU writes tests
Ensure the behavior of the previous commit in tests.
2021-02-13 02:15:29 -03:00
ReinUsesLisp
9d8ca6cc4a buffer_base: Add support for cached CPU writes
Some games usually write memory pages currently used by the GPU, causing
rendering issues (e.g. flashing geometry and shadows on Link's
Awakening). To workaround this issue, Guest CPU writes are delayed until
the command buffer finishes processing, but the pages are updated
immediately.

The overall behavior is:
- CPU writes are cached until they are flushed, they update the page
  state, but don't change the modification state. Cached writes stop
  pages from being flushed, in case games have meaningful data in it.
- Command processing writes (e.g. push constants) update the page state
  and are marked to the command processor as dirty. They don't remove
  the state of cached writes.
2021-02-13 02:15:29 -03:00
ameerj
069afcc633 maxwell_to_gl: Remove unused code
Removes unused declarations in maxwell_to_gl.h
2021-02-12 23:01:09 -05:00
Chloe Marcec
7ad63ea542 revert to std::sin and std::cos 2021-02-12 18:48:10 -08:00
Chloe Marcec
d28b942458 address issues 2021-02-12 18:48:10 -08:00
Chloe Marcec
4a7fd91857 audren: Implement I3dl2Reverb
Most notable fix is the voices in Fire Emblem Three Houses
2021-02-12 18:48:10 -08:00
bunnei
c86d770af9 Merge pull request #5877 from ameerj/res-limit-usage
kernel: More accurately utilize resource_limit
2021-02-12 18:21:30 -08:00
ameerj
ec9b6641b1 kernel: More accurately reserve and release resources 2021-02-12 19:05:24 -05:00
ameerj
5fa6b15215 kernel: KScopedReservation implementation
This implements KScopedReservation, allowing resource limit reservations to be more HW accurate, and release upon failure without requiring too many conditionals.
2021-02-12 18:57:34 -05:00
Chloe
37939482fb kernel: Unify result codes (#5890)
* kernel: Unify result codes

Drop the usage of ERR_NAME convention in kernel for ResultName. Removed seperation between svc_results.h & errors.h as we mainly include both most of the time anyways.

* oops

* rename errors to svc_results
2021-02-12 15:43:01 -08:00
lat9nq
dcc0617cc2 yuzu: Create screenshot path before capture
Allows screenshots in cases where the screenshots path doesn't already
exist.
2021-02-12 17:26:01 -05:00
bunnei
a0379c2db5 Merge pull request #5902 from lioncash/core-warn
core: Silence various warnings on Clang 12
2021-02-11 18:57:23 -08:00
bunnei
e53b6ecc76 Merge pull request #5869 from german77/mousePanning
input_common: Add mouse panning
2021-02-11 09:58:23 -08:00
bunnei
f06c3f4907 Merge pull request #5908 from Morph1984/swkbd-finalize
software_keyboard: Implement Finalize request command
2021-02-10 21:49:53 -08:00
Morph
886043a6d2 software_keyboard: Implement Finalize request command 2021-02-10 21:42:49 -05:00
bunnei
3e6e0d8f13 Merge pull request #5893 from lioncash/input
configure_input_player_widget: Minor cleanup
2021-02-10 10:55:59 -08:00
LC
dee133ab3d Merge pull request #5904 from lat9nq/common-sized-dealloc
common: Add -fsized-deallocation as a Clang flag
2021-02-09 23:45:52 -05:00
LC
3c22ce035b Merge pull request #5905 from lat9nq/core-sized-dealloc
core: Add -fsized-dealloction as a Clang flag
2021-02-09 23:45:36 -05:00
LC
a5e184e948 Merge pull request #5903 from lat9nq/config-silence-warns
configure_input_player_widget: Silence unused variable warnings
2021-02-09 23:44:58 -05:00
lat9nq
c44ab0f8f6 cmake: Update FFmpeg to 4.3.1
Download FFmpeg package version 4.3.1. Uses a file defined within the
package to determine with DLLs to copy.

Also corrects a submodule name.
2021-02-09 22:17:22 -05:00
lat9nq
0e004269a9 configure_input_player_widget: Silence unused variable warnings
Prevents clang 11 from throwing an error since these variables are
unused.
2021-02-09 22:09:23 -05:00
lat9nq
a58086ae0d common: Add -fsized-deallocation as a Clang flag
Prevents an operator delete error when compiling with Clang 11.
2021-02-09 21:28:33 -05:00
lat9nq
68f718943e core: Add -fsized-dealloction as a Clang flag
Prevents a operator delete error when compiling with Clang 11.
2021-02-09 21:27:12 -05:00
Ameer J
70db238f80 Merge pull request #5901 from lioncash/input-warn
udp: Silence warnings on Clang 12
2021-02-09 20:19:56 -05:00
bunnei
245d60bfff Merge pull request #5900 from lioncash/unused-func
video_core: Remove unused functions and variables
2021-02-09 15:29:10 -08:00
Lioncash
0cd40fb523 bsd: Remove usage of optional emplace() with no arguments
Clang 12 currently falls over in the face of this.
2021-02-09 17:50:29 -05:00
Lioncash
1dab8acf5f am/controller: Remove [[fallthrough]] from unreachable path
Prevents warnings on clang 12. This path is reachable on other
variations of the build that disable the unreachable macro.
2021-02-09 17:44:14 -05:00
Lioncash
d64ba58759 nfp: Correct uninitialized size being used within GetTagInfo()
We were previously the name of the object being initialized within its
own initializer, which results in uninitialized data being read.
2021-02-09 17:42:02 -05:00
Lioncash
a352f34462 udp: Silence unused member variable warnings
Simply mark them as unused for now.
2021-02-09 17:38:45 -05:00
Lioncash
cda24b8eb1 udp/client: Define ClientData constructor/destructor in cpp file
Prevents compilation errors on clang 12 due to incomplete types within a
unique_ptr member.
2021-02-09 17:36:32 -05:00
Lioncash
10636d2494 gl_rasterizer: Remove unused variables
Resolves warnings on clang 12
2021-02-09 17:31:37 -05:00
Lioncash
783dc9e112 texture_cache/util: Remove unused functions
Silences a few warnings on clang 12.
2021-02-09 17:30:20 -05:00
Lioncash
864762cac9 configure_input_player_widget: Reduce duplication of array accessors where applicable
Reduces the amount of code to read in expressions a little bit by
separating constituents out a little.
2021-02-09 13:15:05 -05:00
Lioncash
5c7c212f61 configure_input_player_widget: Avoid nontrivial copies where applicable
Previously a function was copying an array of 20 std::string instances
by value.
2021-02-09 13:15:03 -05:00
german
bcd4e4f650 Use GC image 2021-02-09 08:12:21 -06:00
Jatoxo
2e32ab4e0b Settings: Add depth to Joysticks on Pro Controller preview (#5894)
* Add some depth to ProJoysticks

* address comments

* clang

* address nits

* fix wrong inner_offset when offset.x was 0
2021-02-08 21:06:37 -08:00
Morph
b6736db324 Merge pull request #5899 from ameerj/ffmpeg-revert
cmake: Revert FFmpeg 4.3.1 update for Windows builds
2021-02-09 12:14:19 +08:00
ameerj
d6ebb5c171 cmake: Revert FFmpeg 4.3.1 update for Windows builds
The new 4.3.1 externals build seems to not be compatible with yuzu. This also fixes an oversight when renaming CMake variables.
2021-02-08 23:11:59 -05:00
Ameer J
26669d9e13 Merge pull request #5880 from lat9nq/ffmpeg-external
cmake: FFmpeg linking rework
2021-02-08 21:13:10 -05:00
bunnei
1b730827dd Merge pull request #5892 from german77/backup
olsc: Stub GetSaveDataBackupSetting
2021-02-08 17:48:52 -08:00
bunnei
7666c0994c Merge pull request #5868 from german77/HandheldFix
Prevent over scheduling audio events and add motion update unschedule event
2021-02-08 11:33:53 -08:00
Schplee
d1ac25b632 README Edit for EA 2021-02-08 07:46:09 -08:00
LC
903311729a Merge pull request #5895 from Morph1984/utf16-cvt
string_util: Remove MSVC workaround for converting between UTF8/UTF16
2021-02-08 03:27:13 -05:00
Morph
ff58ad2050 string_util: Remove MSVC workaround for converting between UTF8/UTF16
This has been fixed as of Visual Studio 2019 Version 16.2
2021-02-08 02:56:07 -05:00
german
a994a40467 hid: Implement GC controller 2021-02-07 22:59:46 -06:00
bunnei
0896089092 Merge pull request #5339 from german77/interactive
Settings: Make settings controller image change with controller input
2021-02-07 20:53:46 -08:00
german
3f9eb56972 olsc: Stub GetSaveDataBackupSetting 2021-02-07 22:32:13 -06:00
german
52b79ac009 Add mouse panning 2021-02-07 20:31:58 -06:00
Chloe
d0a760a34a Merge pull request #5872 from lioncash/svc-error
svc: Provide more detailed error logs for svc functions
2021-02-08 12:27:36 +11:00
Rodrigo Locatti
4c82c08897 Merge pull request #5888 from Morph1984/ogl-4.6
renderer_opengl: Update OpenGL backend version requirement to 4.6
2021-02-07 21:44:49 -03:00
LC
148fb12bf3 Merge pull request #5889 from ogniK5377/morton-remove
video_core: Delete morton
2021-02-07 18:48:28 -05:00
Chloe Marcec
c5f109bc50 video_core: Delete morton
moron.h & morton.cpp are not used anywhere and are just empty files
2021-02-08 10:20:21 +11:00
Morph
6e5cc977ad renderer_opengl: Update OpenGL backend version requirement to 4.6 2021-02-07 16:32:35 -05:00
bunnei
230e71b255 Merge pull request #5887 from ogniK5377/lm-fix
lm: Fix ReadLeb128
2021-02-07 10:25:56 -08:00
Morph
458be11f93 Merge pull request #5878 from aleasto/master
pl_u: Fix read out of bounds
2021-02-07 22:20:47 +08:00
Chloe Marcec
9d5a56a40b lm: Fix ReadLeb128
Fixes assertion on Bloodstained Ritual of the Night.

We would over read sometimes, this is fixed by checking if the top bit is set in the first iteration. We also lock the loop off to be only the max size of the type we can fit. Finally we changed an incorrect print of "DEBUG" to "TRACE" to reflect the proper log severity
2021-02-07 23:52:56 +11:00
german
8893b766c3 Add GC controller animation 2021-02-07 00:15:24 -06:00
bunnei
4a01812ebe Merge pull request #5885 from MerryMage/ring_buffer-granularity
ring_buffer: Remove granularity template argument
2021-02-06 13:18:41 -08:00
bunnei
9078f4a9c7 Merge pull request #5871 from lioncash/address-arb
k_address_arbiter: Minor cleanup
2021-02-06 13:05:19 -08:00
MerryMage
8d00265998 ring_buffer: Remove granularity template argument
Non-obvious bug in RingBuffer::Push(std::vector<T>&) when granularity != 1

Just remove it altogether because we do not have a use for granularity != 1
2021-02-06 19:16:00 +00:00
Alessandro Astone
32d9a83f8e pl_u: Fix read out of bounds 2021-02-06 18:44:01 +01:00
german
160341fcf8 Refresh debug controller settings 2021-02-06 09:43:42 -06:00
german
d6a0975e5d Refresh controller only when necessary 2021-02-06 09:43:42 -06:00
german
c9597af39d Add SL SR vectors, change dual joycon view, add missing raw data from keyboard/mouse 2021-02-06 09:43:42 -06:00
german
a7f9983563 Add controller window and single joycon top view 2021-02-06 09:43:42 -06:00
german
ea1f656d7e Replace text with vectors 2021-02-06 09:43:42 -06:00
german
481cd86722 Make settings controller image change with controller input 2021-02-06 09:43:41 -06:00
bunnei
61bf850f3d Merge pull request #5326 from german77/hidUpdate1
HID: Update the HID service to match more closely to switchbrew part 1
2021-02-06 02:40:11 -08:00
Lioncash
40ab2b9348 k_address_arbiter: Unfold R_UNLESS macros
Allows for more descriptive error messages and also doesn't hide
control-path exit returns from the reader.
2021-02-06 04:08:27 -05:00
Lioncash
b8fc74d74d k_address_arbiter: Remove unnecessary usages of std::addressof
This is a useful function in a generic context or with types that
overload unary operator&. However, primitives and pointers will never do
this, so we can opt for a more straightforward syntax.
2021-02-06 04:06:33 -05:00
Lioncash
7b9c58880f k_address_arbiter: Remove dead code
This code is never used, so we can remove it. It's in version control,
so it can always be brought back when needed.
2021-02-06 04:06:33 -05:00
lat9nq
1a2e7c4dbd ffmpeg: Checkout tag n4.3.1
Target a specific release version rather than some random development
commit.
2021-02-06 03:19:07 -05:00
lat9nq
527188391c CMakeLists: Use bundled FFmpeg as a fallback
Sets YUZU_USE_BUNDLED_FFMPEG as a CMake dependent option that is OFF on
Linux and ON for WIN32 targets. If FFmpeg is not found when
YUZU_USE_BUNDLED_FFMPEG is OFF, the bundled module/binaries are used
instead.

Reverts earlier changes to FindFFmpeg a bit, mostly to keep parity with
it's Citra version a bit. Now _FFmpeg_ALL_COMPONENTS lists all
components. We overwrite FFmpeg_LIBRARIES and FFmpeg_INCLUDE_DIR after
using the module.
2021-02-06 03:17:36 -05:00
Lioncash
75a60a6e22 svc: Provide more detailed error logs for svc functions
Allows SVC calls to have much more informative information during error
cases. This also doesn't hide control flow returns from the reader.
2021-02-06 02:03:40 -05:00
bunnei
1498a7c9a8 Merge pull request #5862 from bunnei/kevent
Kernel Rework: Refactor KEvent/KReadableEvent/KWritableEvent
2021-02-05 23:00:43 -08:00
lat9nq
8b54e219c9 CMakeLists: Update to FFmpeg 4.3.1 for WIN32
Minimal binaries go brrrrrrr
2021-02-05 22:27:37 -05:00
bunnei
3a804752cb Merge pull request #5875 from lioncash/identifier
k_priority_queue: Minor cleanup
2021-02-05 17:02:13 -08:00
lat9nq
830612ef9e CMakeLists: Fixes for linux-fresh
Tells CMake to look for either nasm or yasm as it is required to build
FFmpeg. Avoids a compile-time error by checking for it during
configuration.

Adds a workaround for Ubuntu Bionic's old version of make not
communicating jobserver details properly.
2021-02-05 18:06:57 -05:00
bunnei
ea4f62615e hle: kernel: Drop R_UNLESS_NOLOG in favor of expanded if-statement. 2021-02-05 14:03:36 -08:00
bunnei
546af64340 hle: kernel: KAddressArbiter: Remove noisy error log. 2021-02-05 14:03:36 -08:00
bunnei
eba3c59a61 hle: kernel: svc: Cleanup KEvent/KReadableEvent/KWritableEvent SVCs. 2021-02-05 14:03:36 -08:00
bunnei
18175c71ed common: scope_exit: Add a cancellable ScopeExit macro. 2021-02-05 14:03:36 -08:00
bunnei
ff3c7c068b hle: kernel: Reimplement KReadableEvent and KWritableEvent. 2021-02-05 14:03:32 -08:00
bunnei
6bf80dfee0 hle: kernel: Implement KEvent. 2021-02-05 14:00:36 -08:00
bunnei
e9446d232f hle: kernel: KAddressArbiter: Use R_UNLESS_NOLOG where applicable. 2021-02-05 14:00:36 -08:00
bunnei
4577dcd5f9 common: common_funcs: Add R_UNLESS_NOLOG for scenarios that should not log. 2021-02-05 14:00:36 -08:00
bunnei
3f942c01f0 hle: kernel: Rename WritableEvent to KWritableEvent. 2021-02-05 14:00:36 -08:00
bunnei
e86a7e3691 hle: kernel: Rename ReadableEvent to KReadableEvent. 2021-02-05 14:00:36 -08:00
bunnei
b0727c90c5 Merge pull request #5867 from Morph1984/am-GetHealthWarningDisappearedSystemEvent
IApplicationFunctions: Implement GetHealthWarningDisappearedSystemEvent
2021-02-05 13:49:49 -08:00
lat9nq
b7e6eca8b2 Address reviewer comments 2021-02-05 16:46:03 -05:00
lat9nq
1d19eac415 CMake: Port citra-emu/citra FindFFmpeg.cmake
Also renames related CMake variables to match both the Find*FFmpeg* and
variables defined within the file. Fixes odd errors produced by the old
FindFFmpeg.

Citra's FindFFmpeg is slightly modified here: adds Citra's copyright at
the beginning, renames FFmpeg_INCLUDES to FFmpeg_INCLUDE_DIR, disables a
few components in _FFmpeg_ALL_COMPONENTS, and adds the missing avutil
component to the comment above.
2021-02-05 15:39:19 -05:00
lat9nq
0913aaa42a ci/windows: Copy downloaded FFmpeg libraries
Copies FFmpeg libraries that were downloaded during the CMake
configuration. Fixes dynamic linking issues with the MinGW builds.
2021-02-05 14:49:57 -05:00
lat9nq
47401016bf CMake: Implement YUZU_USE_BUNDLED_FFMPEG
For Linux, instructs CMake to use the FFmpeg submodule in externals.
This is HEAVILY based on our usage of the late Unicorn.  Minimal change
to MSVC as it uses the yuzu-emu/ext-windows-bin. MinGW now targets the
same ext-windows-bin libraries as MSVC for FFmpeg. Adds FFMPEG_LIBRARIES
to WIN32 and simplifies video_core/CMakeLists.txt a bit.
2021-02-05 14:49:51 -05:00
lat9nq
82dd376ba2 externals: Add submodule ffmpeg 2021-02-05 13:41:45 -05:00
bunnei
741dc13c5a Merge pull request #5865 from lat9nq/conditionally-quiet
video_core: host_shaders: Don't pass --quiet to glslangValidator if unavailable
2021-02-04 17:07:17 -08:00
bunnei
00cb631b2f Merge pull request #5876 from lioncash/truncation
k_affinity_mask: Avoid implicit truncation to bool
2021-02-04 14:44:11 -08:00
Lioncash
756365386a k_affinity_mask: Avoid implicit truncation to bool
This can cause compiler warnings. Instead, we can explicitly add a
boolean expression around it to naturally turn the result into a bool.
2021-02-04 15:35:46 -05:00
Lioncash
b944edc85d k_priority_queue: Unfold several declval usages
Given these are only used as function existence checks, we can simplify
some usages of declval, given they aren't particularly useful here.

Reduces a few template instantiations, which at most reduces compile
times a tiny bit.
2021-02-04 15:18:58 -05:00
Lioncash
31e6e58101 k_priority_queue: Simplify affinity mask type alias
We can make use of the _t variants of the templates to cut down on a
little bit of verbosity.
2021-02-04 14:57:41 -05:00
Lioncash
53aec1fe2d k_priority_queue: Resolved reserved identifier
An identifier containing a starting underscore followed by a capital
letter is reserved by the standard. It's trivial to avoid this by moving
the underscore to the end of the identifier.

While the likelihood of clashing here being minimal, we can turn a
"should not break" scenario into a definitive "will not break" one, so
why not?.
2021-02-04 14:55:08 -05:00
bunnei
eb3afd30b1 Merge pull request #5874 from Morph1984/create-keys-dir
key_manager: Create the keys directory if it does not exist
2021-02-04 11:47:14 -08:00
Morph
806e2d7900 key_manager: Create the keys directory if it does not exist 2021-02-04 06:05:50 -05:00
bunnei
b331bb5210 Merge pull request #5870 from german77/hanheldfix2
config: Always update handheld config
2021-02-03 19:02:59 -08:00
german
8019b2b9b5 Add footer types and address comments 2021-02-03 20:17:08 -06:00
german
9a9e81f2e9 Fix npad struct to match switchbrew 2021-02-03 20:17:08 -06:00
german
f30ef98761 Adds missing controller types and properties 2021-02-03 20:17:08 -06:00
bunnei
cde532cc52 Merge pull request #5863 from ogniK5377/disable-reverb
audren: Disable reverb for the time being
2021-02-03 18:05:54 -08:00
german
c1b81f776c Always update handheld config 2021-02-03 17:48:04 -06:00
bunnei
b0c9752663 Merge pull request #5848 from ogniK5377/k-resourcelimit
kernel: Rewrite resource limit to be more accurate
2021-02-03 14:53:25 -08:00
Chloe Marcec
2c6e940493 Simplify limitableresource names 2021-02-03 12:55:16 +11:00
bunnei
48d040fded Merge pull request #5842 from german77/userfix
acc: Fix error when second user is selected
2021-02-02 15:43:51 -08:00
bunnei
e5a76d728f Merge pull request #5841 from german77/username
Avoid overwriting username
2021-02-02 15:04:09 -08:00
german
7784b1da6d Prevent over scheduling audio events and terminate properly the motion update event 2021-02-02 10:17:10 -06:00
LC
82d232db46 Merge pull request #5866 from Morph1984/log-all-paths
settings: Log the cache, config and mod load directories
2021-02-02 11:07:42 -05:00
Morph
13b08376b7 IApplicationFunctions: Implement GetHealthWarningDisappearedSystemEvent 2021-02-02 10:47:38 -05:00
Morph
9137f3ec68 settings: Log the cache, config, and mod load directories 2021-02-02 04:01:05 -05:00
lat9nq
fc43eac82a video_core: host_shaders: Don't pass --quiet to glslangValidator if unavailable
Prevents CMake from calling `glslangValidator` with `--quiet` when it is
not available, i.e. on older downstream versions from Ubuntu.
2021-02-01 23:39:54 -05:00
bunnei
d4ebc9a120 Merge pull request #5861 from german77/HandheldFix
hid: Only update motion for npad and prevent over scheduling events
2021-02-01 18:46:26 -08:00
Chloe Marcec
64c3582705 Compile error 2021-02-02 13:23:34 +11:00
Chloe Marcec
9e4b2d60bc Address issues 2021-02-02 13:23:00 +11:00
LC
5e49b81d4d Merge pull request #5864 from MerryMage/is-thumb
arm_dynarmic_32: Print out CPSR.T on exception
2021-02-01 13:36:55 -05:00
MerryMage
821fc4a7b6 arm_dynarmic_32: Print out CPSR.T on exception 2021-02-01 18:35:33 +00:00
bunnei
f317b0d354 Merge pull request #5859 from Morph1984/nifm
nifm: Stub GetCurrentNetworkProfile and GetCurrentIpConfigInfo
2021-01-31 21:31:14 -08:00
Ameer J
f614d7d887 Merge pull request #5856 from Morph1984/nifm-fix-getappletinfo-stub
nifm: Fix GetAppletInfo stub
2021-01-31 23:33:11 -05:00
Chloe Marcec
9fc7f60b94 audren: Disable reverb for the time being
As this is causing issues in a few games, it's best to have it disabled until it's completely implemented
2021-02-01 14:41:58 +11:00
bunnei
67d08f14af Merge pull request #5858 from Morph1984/IsGamePlayRecordingSupported-stub
am/IApplicationFunctions: Stub IsGamePlayRecordingSupported
2021-01-31 18:04:04 -08:00
german
2489547dc5 Only update motion for npad and prevent over scheduling events 2021-01-31 18:52:38 -06:00
bunnei
1498ece290 Merge pull request #5860 from Morph1984/prepo-transmission-stub
prepo: Stub RequestImmediateTransmission and GetTransmissionStatus
2021-01-31 12:26:00 -08:00
Morph
f7dc77e03a Merge pull request #5846 from ameerj/analog-join
analog_from_button: Fix update_thread.join exception
2021-01-31 23:06:06 +08:00
Morph
8c7d89e6c7 nifm: Stub GetCurrentIpConfigInfo
- Used by Lets Sing 12
2021-01-31 07:36:37 -05:00
Morph
7d9465d47a prepo: Stub GetTransmissionStatus 2021-01-31 07:07:11 -05:00
Morph
2394807b42 prepo: Stub RequestImmediateTransmission
- Used by Animal Crossing: New Horizons
2021-01-31 07:04:35 -05:00
Morph
4bf1cf1f81 nifm: Stub GetCurrentNetworkProfile
- Used by Minecraft Bedrock Edition
- Used by Bloons TD 5
2021-01-31 06:56:29 -05:00
Morph
70a2065828 nifm: Add several structs 2021-01-31 06:56:29 -05:00
bunnei
ec51f8de82 Merge pull request #5857 from Morph1984/bsd-fix-eventfd-stub
bsd: Fix EventFd stub
2021-01-31 01:41:06 -08:00
Morph
9f6b35e61f am/IApplicationFunctions: Stub IsGamePlayRecordingSupported
Used by RetroArch
2021-01-31 03:11:03 -05:00
Morph
ded094a340 bsd: Fix EventFd stub 2021-01-31 02:57:56 -05:00
bunnei
1cc009a996 Merge pull request #5855 from Morph1984/bsd-fix-getsockopt-stub
bsd: Fix GetSockOpt stub
2021-01-30 23:21:21 -08:00
Morph
9914db8daa nifm: Fix GetAppletInfo stub 2021-01-31 02:19:36 -05:00
Morph
94f660d1cb Merge pull request #5851 from ameerj/pop-inv-stub
am: Stub TryPopFromFriendInvitationStorageChannel
2021-01-31 14:18:40 +08:00
Morph
6cc769065d bsd: Fix GetSockOpt stub 2021-01-31 01:08:56 -05:00
bunnei
360ea64738 Merge pull request #5852 from ameerj/event-fd-stub
bsd: Stub EventFd
2021-01-30 21:38:08 -08:00
ameerj
ad146eca60 bsd: Stub EventFd
Used by Family Feud
2021-01-30 21:47:32 -05:00
ameerj
99dcf7da21 am: Stub TryPopFromFriendInvitationStorageChannel
Used by Family Feud
2021-01-30 21:43:55 -05:00
Chloe Marcec
ee333e063d fix compile error 2021-01-30 21:51:22 +11:00
Chloe Marcec
56742c6222 cleanup commenting 2021-01-30 21:20:35 +11:00
Chloe Marcec
7791cfd960 Drop m_ from lock 2021-01-30 21:19:49 +11:00
Chloe Marcec
3bf62c7a8a Move to GetGlobalTimeNs, fix GetTotalPhysicalMemoryAvailable 2021-01-30 21:03:10 +11:00
Chloe Marcec
3be1a565f8 kernel: Rewrite resource limit to be more accurate
Matches closer to hardware
2021-01-30 20:40:49 +11:00
bunnei
a4526c4e1a Merge pull request #5779 from bunnei/kthread-rewrite
Rewrite KThread to be more accurate
2021-01-29 23:06:40 -08:00
bunnei
5861bacafd Merge pull request #5795 from ReinUsesLisp/bytes-to-map-end
video_core/memory_manager: Add BytesToMapEnd
2021-01-29 22:56:29 -08:00
Morph
f67cfebada Merge pull request #5838 from german77/prepostub
prepo: Stub GetSystemSessionId
2021-01-30 14:19:59 +08:00
bunnei
aaf834ffa6 Merge pull request #5847 from bunnei/update-dynarmic
externals: Dynarmic: Update to latest to include A32 ISB hook.
2021-01-29 21:52:25 -08:00
german
9150b8972e Stub GetSystemSessionId 2021-01-29 18:41:28 -06:00
bunnei
650734cc3e Merge pull request #5805 from german77/HandheldFix
Fix connect and disconnect controller events
2021-01-29 16:39:01 -08:00
bunnei
15d3376399 externals: Dynarmic: Update to latest to include A32 ISB hook.
- Fixes perf. issues with Megadimension Neptunia VII.
2021-01-29 16:36:45 -08:00
ameerj
ef8b3623f5 analog_from_button: Fix update_thread.join exception
This commit aims to address an exception that occurs when trying to join the Analog object's update_thread.

By using an atomic bool for the status of the update thread, we ensure its value is consistent across the threads accessing it.
2021-01-29 18:41:22 -05:00
bunnei
b786568c5a Merge pull request #5809 from ogniK5377/FlushAudioOutBuffers
audout: FlushAudioOutBuffers
2021-01-28 21:54:46 -08:00
bunnei
543e212554 hle: kernel: KLightLock: Fix several bugs. 2021-01-28 21:53:21 -08:00
bunnei
8d1afcb90f common: common_funcs: Change R_UNLESS to LOG_ERROR. 2021-01-28 21:51:16 -08:00
bunnei
c8fe8247ee arm: dynarmic: Reintroduce JIT checks on SaveContext/LoadContext. 2021-01-28 21:50:39 -08:00
bunnei
e24c6dab93 hle: kernel: KThread: Release thread resource on thread exit. 2021-01-28 21:49:47 -08:00
bunnei
10738839ad yuzu: debugger: Ignore HLE threads. 2021-01-28 21:42:27 -08:00
bunnei
3856564727 hle: kernel: process: Add state lock. 2021-01-28 21:42:26 -08:00
bunnei
ff46ef7ea3 hle: kernel: threading: Fix bug with host thread naming. 2021-01-28 21:42:26 -08:00
bunnei
6ee8340a6b hle: kernel: k_scheduler_lock: Cleanup. 2021-01-28 21:42:26 -08:00
bunnei
055194d2ab core: arm: Remove unnecessary JIT checks. 2021-01-28 21:42:26 -08:00
bunnei
091e9e8c41 common: common_funcs: Log error on R_UNLESS. 2021-01-28 21:42:26 -08:00
bunnei
6e953f7f02 hle: kernel: Allocate a dummy KThread for each host thread, and use it for scheduling. 2021-01-28 21:42:26 -08:00
bunnei
37f74d8741 hle: kernel: k_scheduler: Use atomics for current_thread, etc. 2021-01-28 21:42:26 -08:00
bunnei
f6b10fad63 hle: kernel: k_scheduler: Fix for single core mode. 2021-01-28 21:42:26 -08:00
bunnei
0a1449e04b kernel: Fix build errors. 2021-01-28 21:42:26 -08:00
bunnei
89a5ae92bd core: cpu_manager: Remove unused variable. 2021-01-28 21:42:26 -08:00
bunnei
ca78f77827 hle: kernel: KScheduler: Introduce thread context_guard. 2021-01-28 21:42:26 -08:00
bunnei
cdd14b03e5 hle: kernel: Recode implementation of KThread to be more accurate. 2021-01-28 21:42:26 -08:00
bunnei
1470338458 kernel: svc_types: Add ThreadActivity. 2021-01-28 21:42:26 -08:00
bunnei
1772ebeb1e kernel: KSchedulerPriorityQueue: Lowest priority should be LowestThreadPriority. 2021-01-28 21:42:26 -08:00
bunnei
1f99f5473c kernel: k_light_lock: Simplify EmuThreadHandle implementation. 2021-01-28 21:42:26 -08:00
bunnei
c0f5830323 hle: kernel: TimeManager: Simplify to not rely on previous EmuThreadHandle implementation. 2021-01-28 21:42:26 -08:00
bunnei
bb966d3e33 common: common_funcs: Add useful kernel macro R_SUCCEED_IF. 2021-01-28 21:42:26 -08:00
bunnei
ff186b2498 core: hle: kernel: object: Implement Finalize() virtual method. 2021-01-28 21:42:26 -08:00
bunnei
33b4930280 core: hle: kernel: svc_results: Populate with several missing error codes. 2021-01-28 21:42:26 -08:00
bunnei
5a4fc4a529 core: hle: kernel: Implement KLightLock. 2021-01-28 21:42:26 -08:00
bunnei
97129bc742 core: hle: kernel: Implement KThreadQueue. 2021-01-28 21:42:25 -08:00
bunnei
2fb77adb9f common: common_funcs: Add a few more useful macros for kernel code. 2021-01-28 21:42:25 -08:00
bunnei
4dbf3f4880 hle: kernel: KThread: Clean up thread priorities. 2021-01-28 21:42:25 -08:00
bunnei
1e55498110 hle: kernel: KThread: Reorganize thread priority defaults. 2021-01-28 21:42:25 -08:00
bunnei
0530292b97 hle: kernel: KThread: Fix ThreadType definition. 2021-01-28 21:42:25 -08:00
bunnei
4782985013 hle: kernel: Move single core "phantom mode" out of KThread.
- This is a workaround that does not belong in a kernel primitive.
2021-01-28 21:42:25 -08:00
bunnei
eea346ba8e hle: kernel: KThread: Remove thread types that do not exist. 2021-01-28 21:42:25 -08:00
bunnei
9a4e148f9e arm: arm_dynarmic: Skip calls when JIT is invalid.
- This can happen if called from an idle or suspension thread.
2021-01-28 21:42:25 -08:00
bunnei
c0d3aef28c core: hle: kernel: Rename Thread to KThread. 2021-01-28 21:42:25 -08:00
german
8ba0cac71c Fix user changing to 0 if valid 2021-01-28 21:02:25 -06:00
bunnei
df41e78205 Merge pull request #5837 from german77/socketstub
sockets: Stub GetSockOpt
2021-01-28 16:28:11 -08:00
german
7b8fa78c65 Avoid overwritting username 2021-01-28 16:58:53 -06:00
LC
c21ce728c2 Merge pull request #5831 from MerryMage/isb
dynarmic: Do not flush cache when executing an ISB instruction
2021-01-28 10:54:48 -05:00
LC
16818e952c Merge pull request #5836 from ReinUsesLisp/unaligned-constr-sched
vk_scheduler: Fix unaligned placement new expressions
2021-01-28 10:53:15 -05:00
LC
9f6290d207 Merge pull request #5840 from Morph1984/prepo-fix
prepo: Fix BufferDescriptorX invalid buffer index errors and add New variants of SaveReport
2021-01-28 10:52:44 -05:00
LC
0e125dfd43 Merge pull request #5835 from Morph1984/cleanup-sixaxis-fusion
hid: Cleanup SixAxisFusionParameters
2021-01-28 10:51:04 -05:00
Morph
4921ba05db hid: Add static_assert for Parameter size 2021-01-28 09:41:43 -05:00
Morph
ae6b3bdfbf prepo: Fix BufferDescriptorX invalid buffer errors and add "New" variants of SaveReport
The second input buffer could be optional when prepo/srepo is called, test for the availability of the second buffer prior to reading from it.
2021-01-28 01:32:24 -05:00
Morph
008afa5d59 hle_ipc: Add Can(Read, Write)Buffer
Allows us to test whether a buffer can be read from or written to memory
2021-01-28 01:32:24 -05:00
german
659b5f8088 Stub GetSockOpt 2021-01-27 23:18:20 -06:00
ReinUsesLisp
9e88ad8da9 vk_scheduler: Fix unaligned placement new expressions
We were accidentaly creating an object in an unaligned memory address.
Fix this by manually aligning the offset.
2021-01-27 22:28:22 -03:00
bunnei
45b13c3037 Merge pull request #5786 from ReinUsesLisp/glsl-cbuf
gl_shader_decompiler: Fix constant buffer size calculation
2021-01-27 15:27:53 -08:00
Rodrigo Locatti
ef6cc3aa1d vulkan_device: Blacklist Intel from float16 math (#5798)
Astral Chain crashes Intel's SPIR-V compiler when using fp16.
Disable this while the vendor works on a fix.
2021-01-27 13:31:32 -08:00
bunnei
28b822fe38 Merge pull request #5778 from ReinUsesLisp/shader-dir
renderer_opengl: Avoid precompiled cache and force NV GL cache directory
2021-01-27 11:34:21 -08:00
Morph
d4d39aa4c7 npad: Remove unused device handle parameter 2021-01-27 13:05:31 -05:00
bunnei
fb0fe3b8c3 Merge pull request #5812 from german77/StubSixaxisFusion
HID: Stub Set/Get/Reset SixaxisSensorFusionParameters
2021-01-26 15:58:04 -08:00
MerryMage
2350b76a91 externals: Update dynarmic to 0f27368f 2021-01-26 23:46:49 +00:00
bunnei
09b6f03592 Merge pull request #5810 from ogniK5377/stereo-vision
hle: Implement remaining services for Stereo Vision
2021-01-26 15:01:01 -08:00
bunnei
72c1cb85f1 Merge pull request #5824 from ogniK5377/IPsmSession
psm: IPsmSession
2021-01-26 11:11:29 -08:00
bunnei
64a5548454 Merge pull request #5774 from ogniK5377/mii-raw-random
mii: Fix BuildRandomStoreData & Cleanup raw_data
2021-01-25 16:41:20 -08:00
bunnei
81a037df9d Merge pull request #5771 from ogniK5377/lm-rework
lm: Recode LM service
2021-01-25 10:18:09 -08:00
Chloe Marcec
2c57f0fbd5 Omit system reference 2021-01-25 23:13:37 +11:00
Chloe Marcec
04e9486651 psm: IPsmSession
Used by homebrew menu
2021-01-25 21:37:51 +11:00
bunnei
2a2ee62cfd Merge pull request #5799 from ogniK5377/event-register-unregister
nvdrv: Unregister already registered events
2021-01-24 23:19:10 -08:00
bunnei
62766b1326 Merge pull request #5785 from ReinUsesLisp/buffer-dma
video_core/memory_manager: Flush destination buffer on CopyBlock
2021-01-24 22:57:00 -08:00
Rodrigo Locatti
5dc021d15b Merge pull request #5823 from ReinUsesLisp/revert-flags
Revert "Start of Integer flags implementation"
2021-01-25 03:35:48 -03:00
ReinUsesLisp
34c3ec2f8c Revert "Start of Integer flags implementation"
This reverts #4713. The implementation in that PR is not accurate.
It does not reflect the behavior seen in hardware.
2021-01-25 02:48:03 -03:00
bunnei
45e117b043 Merge pull request #5819 from ReinUsesLisp/cull-mode-cast
vk_graphics_pipeline: Fix narrowing conversion on MSVC
2021-01-24 16:58:38 -08:00
ReinUsesLisp
9dc4a80b17 vk_graphics_pipeline: Fix narrowing conversion on MSVC 2021-01-24 21:41:29 -03:00
LC
df0d8c45d2 Merge pull request #5807 from ReinUsesLisp/vc-warnings
video_core: Silence the remaining gcc warnings and enforce them
2021-01-24 17:36:43 -05:00
Rodrigo Locatti
b769b1be26 Merge pull request #5363 from ReinUsesLisp/vk-image-usage
vk_texture_cache: Support image store on sRGB images with VkImageViewUsageCreateInfo
2021-01-24 18:44:51 -03:00
bunnei
44c5ea3639 Merge pull request #5151 from comex/xx-vfs
vfs_real: When moving files or directories, don't assume file opening will succeed
2021-01-24 13:42:51 -08:00
ReinUsesLisp
6b00443bc1 vk_texture_cache: Support image store on sRGB images with VkImageViewUsageCreateInfo
Vulkan 1.0 didn't support creating sRGB image views on an ABGR8 VkImage
with storage usage bits. VK_KHR_maintenance2 addressed this allowing to
reduce the usage bits on a VkImageView.

To allow image store on non-sRGB image views when the VkImage is created
with sRGB, always create VkImages without sRGB and add the sRGB format
on the view.
2021-01-24 18:16:43 -03:00
LC
8959f3521f Merge pull request #5814 from ReinUsesLisp/remove-rdna-dynstate
vulkan_device: Lift VK_EXT_extended_dynamic_state blacklist on RDNA
2021-01-24 15:54:30 -05:00
ReinUsesLisp
6a0143400f vulkan_device: Lift VK_EXT_extended_dynamic_state blacklist on RDNA
It seems to be safe to use this on new drivers.
2021-01-24 20:21:11 -03:00
ReinUsesLisp
748551dafb cmake: Enforce -Warray-bounds and -Wmissing-field-initializers globally 2021-01-24 17:31:29 -03:00
bunnei
19c14589d3 Merge pull request #5796 from ReinUsesLisp/vertex-a-bypass-vk
vk_pipeline_cache: Properly bypass VertexA shaders
2021-01-24 11:22:58 -08:00
german
a8245cf2f1 Stub Set/Get/Reset SixaxisSensorFusionParameters 2021-01-24 11:28:52 -06:00
Chloe Marcec
2afc1060ef Print Process ID and Thread ID as hex 2021-01-25 02:47:40 +11:00
Chloe Marcec
5882cc0502 hle: Implement remaining services for Stereo Vision
Used by Zelda Breath of the Wild, Super Mario Odyssey and Nintendo Labo
2021-01-25 00:34:01 +11:00
LC
04dcada85f Merge pull request #5808 from ReinUsesLisp/glslang-quiet
host_shaders/cmake: Pass --quiet to glslang to keep it quiet
2021-01-24 05:01:10 -05:00
Chloe Marcec
b2b95e96c1 audout: FlushAudioOutBuffers
Fixes Devil May Cry
2021-01-24 19:13:34 +11:00
ReinUsesLisp
f81c783b5b host_shaders/cmake: Pass --quiet to glslang to keep it quiet
Silences noisy builds on toolchains.
2021-01-24 04:55:23 -03:00
ReinUsesLisp
cc4335a9c6 video_core/cmake: Enforce -Warray-bounds and -Wmissing-field-initializers 2021-01-24 04:42:41 -03:00
bunnei
f7ac4e1eb4 Merge pull request #5806 from bunnei/am-stub
hle: service: am: Stub ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero.
2021-01-23 23:37:05 -08:00
ReinUsesLisp
1b76e7e890 video_core: Silence -Wmissing-field-initializers warnings 2021-01-24 04:32:19 -03:00
ReinUsesLisp
80a673a27f maxwell_3d: Silence array bounds warnings 2021-01-24 04:31:41 -03:00
ReinUsesLisp
ad48259d7e maxwell_to_vk: Silence -Wextra warnings about using different enum types 2021-01-24 04:03:36 -03:00
german
3b4da2d7fa Fix connect and disconnect controller events 2021-01-23 22:59:44 -06:00
comex
e9bb95ae16 vfs_real: When moving files or directories, don't assume file opening will succeed
Found this via a warning, but it's a substantive fix.

Since this is only for a cache, it should be safe to silently drop the
entry if opening fails.  I think.
2021-01-23 16:19:29 -05:00
Levi Behunin
9477d23d70 shader_ir: Fix comment typo 2021-01-23 13:16:37 -05:00
LC
bfd2bcb068 Merge pull request #5800 from Morph1984/max-vibration-duration
sdl_impl: Set the maximum vibration duration to 1 second
2021-01-23 10:46:18 -05:00
Morph
5942d206c2 sdl_impl: Set the maximum vibration duration to 1 second 2021-01-23 08:06:07 -05:00
Chloe Marcec
822edff5bd Simplify condition 2021-01-23 22:12:05 +11:00
Chloe Marcec
3b0458a7a5 nvdrv: Unregister already registered events 2021-01-23 22:02:14 +11:00
LC
65f821850e Merge pull request #5797 from ReinUsesLisp/nsight-aftermath-build
nsight_aftermath_tracker: Fix build issues when enabled
2021-01-23 05:40:50 -05:00
Chloe Marcec
df42100320 Clamp string reads to buffer size 2021-01-23 18:24:57 +11:00
ReinUsesLisp
966896daad video_core/cmake: Properly generate fatal errors on Aftermath
Fix "message(ERROR ..." to "message(FATAL_ERROR ..." to properly stop
cmake when Nsight Aftermath can't be configured.
2021-01-23 04:15:30 -03:00
ReinUsesLisp
625a011888 nsight_aftermath_tracker: Fix build issues when enabled
Fixes a bunch of build errors when Nsight Aftermath is properly enabled.
2021-01-23 04:13:39 -03:00
bunnei
12355cbf02 Merge pull request #5776 from ogniK5377/lbl
lbl: Implement most of lbl
2021-01-22 23:13:23 -08:00
ReinUsesLisp
37ef2ee595 vk_pipeline_cache: Properly bypass VertexA shaders
The VertexA stage is not yet implemented, but Vulkan is adding its
descriptors, causing a discrepancy in the pushed descriptors and the
template. This generally ends up in a driver side crash.

Bypass the VertexA stage for now.
2021-01-23 03:59:59 -03:00
bunnei
302a5f00e8 Merge pull request #4713 from behunin/int-flags
Start of Integer flags implementation
2021-01-22 21:57:14 -08:00
bunnei
981d8e82d2 Merge pull request #5765 from ogniK5377/StoreSaveDataThumbnail-stub
acc: Stub StoreSaveDataThumbnail
2021-01-22 21:51:54 -08:00
ReinUsesLisp
bda177ef40 video_core/memory_manager: Add BytesToMapEnd
Track map address sizes in a flat ordered map and add a method to query
the number of bytes until the end of a map in a given address.
2021-01-22 18:31:12 -03:00
bunnei
a175ba1089 Merge pull request #5784 from v1993/patch-1
Bump conan SDL2 version to 2.0.14
2021-01-21 21:39:44 -08:00
bunnei
1e9b1d439f common: Add missing include to bit_util.h 2021-01-21 15:30:28 -08:00
ReinUsesLisp
436457b6e7 gl_shader_decompiler: Fix constant buffer size calculation
The divide logic was wrong and can cause an uniform buffer size
overflow.
2021-01-21 19:47:41 -03:00
bunnei
2c4c7aea8a Merge pull request #5781 from lioncash/bits
bit_util: Unify implementations of MostSignificantBit32/MostSignificantBit64
2021-01-21 14:45:40 -08:00
ReinUsesLisp
b7febb5625 video_core/memory_manager: Remove unused CopyBlockUnsafe
This function was not being used.
2021-01-21 19:16:06 -03:00
ReinUsesLisp
0e9a6759f9 video_core/memory_manager: Flush destination buffer on CopyBlock
When we copy into a buffer, it might contain data modified from the GPU
on the same pages. Because of this, we have to flush the contents before
writing new data.

An alternative approach would be to write the data in place, but games
can also write data in other ways, invalidating our contents.

Fixes geometry in Zombie Panic in Wonderland DX.
2021-01-21 19:16:06 -03:00
ReinUsesLisp
dd790abab0 video_core/memory_manager: Add GPU address based flush method
Allow flushing rasterizer contents based on a GPU address.
2021-01-21 19:16:05 -03:00
Valeri
46dda01151 Bump conan SDL2 version to 2.0.14
Update conan package version used for building.

A couple of new joystick-related functions might pose interest to yuzu's input system. Some sort of LED management have been added, but it doesn't seem to support leds used for player number indication JoyCons/ProCons use.
2021-01-21 21:47:35 +03:00
Lioncash
6ff2db181f bit_util: Unify implementations of MostSignificantBit32/MostSignificantBit64
We can use the standardized CLZ facilities to perform this. This also
allows us to make utilizing functions constexpr and eliminate the
inclusion of an intrinsics header.
2021-01-21 04:07:58 -05:00
bunnei
a1335d3d51 Merge pull request #5270 from german77/multiTouch
HID: Add multitouch support
2021-01-20 22:39:01 -08:00
bunnei
ffbde909c8 Merge pull request #5361 from ReinUsesLisp/vk-shader-comment
vk_shader_decompiler: Show comments as OpUndef with a type
2021-01-20 21:33:42 -08:00
bunnei
f83ef80ebd hle: service: am: Stub ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero.
- Used by Monster Hunter Rise demo.
2021-01-20 20:35:12 -08:00
ReinUsesLisp
51512d01d8 renderer_opengl: Avoid precompiled cache and force NV GL cache directory
Setting __GL_SHADER_DISK_CACHE_PATH we can force the cache directory to
be in yuzu's user directory to stop commonly distributed malware from
deleting our driver shader cache. And by setting
__GL_SHADER_DISK_CACHE_SKIP_CLEANUP we can have an unbounded shader
cache size.

This has only been implemented on Windows, mostly because previous tests
didn't seem to work on Linux.

Disable the precompiled cache on Nvidia's driver. There's no need to
hide information the driver already has in its own cache.
2021-01-21 00:41:03 -03:00
bunnei
d98b0f8f48 Merge pull request #5743 from german77/HandheldFix
Fix player 1 turning on handheld and not updating handheld settings
2021-01-20 17:05:44 -08:00
Chloe Marcec
c795207fb2 lbl: Implement most of lbl
Pretty basic service, only thing left to do is handle setting applying once set:sys is implemented
2021-01-21 00:46:03 +11:00
Chloe Marcec
5b8bc56e65 mii: Fix BuildRandomStoreData & Cleanup raw_data
Cleaned up mii raw data to reflect the underlying values instead of just a chunk of bytes.
Fixed BuildRandomStoreData not actually generating random miis properly. "values" should be a u32, not a u8.
2021-01-20 21:53:57 +11:00
Chloe Marcec
dc18a1261c Mark DestinationToString as static 2021-01-20 18:42:39 +11:00
Chloe Marcec
dca2e2c8f1 Mark LogPacketHeaderEntry hash as noexcept 2021-01-20 18:35:58 +11:00
Chloe Marcec
83f8c1a25e lm: Recode LM service
Rework the service to spit out to logs instead of a seperate file as well as fix any crashes caused by lm.
2021-01-20 18:25:15 +11:00
bunnei
4cd8b2f1f7 Merge pull request #5755 from FearlessTobi/port-5344
Port citra-emu/citra#5344: "game_list: Fix folder reordering"
2021-01-19 10:53:18 -08:00
Chloe Marcec
2d33b2c55a acc: Stub StoreSaveDataThumbnail
Fixes ACA NEOGEO METAL SLUG hanging on boot.
2021-01-19 20:56:18 +11:00
Rodrigo Locatti
2ef4591e58 Merge pull request #5746 from lioncash/sign-compare
texture_cache/util: Resolve -Wsign-compare warning
2021-01-18 03:49:58 -03:00
LC
f1b58f0cd9 Merge pull request #5754 from lat9nq/fix-disable-boxcat
configure_service: Only compile FormatEventStatusString when YUZU_ENABLE_BOXCAT is enabled
2021-01-17 23:52:47 -05:00
LC
dd0679d710 Merge pull request #5757 from Morph1984/npad-handheld
npad: Add check for HANDHELD_INDEX in UpdateControllerAt()
2021-01-17 23:51:30 -05:00
Morph
4a67a5b917 npad: Add check for HANDHELD_INDEX in UpdateControllerAt() 2021-01-17 22:36:17 -05:00
german
e7c1d7bf77 Always update configuration for handheld 2021-01-17 18:40:27 -06:00
FearlessTobi
bf9f737c60 game_list: Fix folder reordering
The bug(s) happened because we swapped the contents on values.game_dirs, but the pointer each item had to their respective game_dir wasn't updated. This made it so that the item had the wrong game_dir associated with it after a "move up" or "move down" operation. It can be observed by choosing "open directory location" after such operation.

Changed from raw pointer to an index because it's equivalent but a bit clearer, but the change is not essential.

Co-Authored-By: Vitor K <29167336+vitor-k@users.noreply.github.com>
2021-01-18 01:22:54 +01:00
lat9nq
fb796843df configure_service: Only compile FormatEventStatusString when YUZU_ENABLE_BOXCAT is enabled
The function is unused if YUZU_ENABLE_BOXCAT is disabled, causing a
-Wunused-funciton error when compiled.

Wrapping it with `#ifdef YUZU_ENABLE_BOXCAT` to prevent compiling the
function when the variable is disabled. Opting to not use [[maybe
unused]] in case the function is totally unused in the future.
2021-01-17 17:54:29 -05:00
german
0bd8cecc94 Fix player 1 default connected value 2021-01-17 12:55:28 -06:00
bunnei
e8401964b4 Merge pull request #5360 from ReinUsesLisp/enforce-memclass-access
core: Silence Wclass-memaccess warnings and enforce it
2021-01-17 00:55:10 -08:00
Rodrigo Locatti
132f2006af Merge pull request #5745 from lioncash/documentation
video_core: Resolve -Wdocumentation warnings
2021-01-17 05:37:17 -03:00
bunnei
e1ecf64701 Merge pull request #5744 from lioncash/header-guard
vulkan_debug_callback: Add missing header guard
2021-01-17 00:16:12 -08:00
Lioncash
5f4e7c77bd texture_cache/util: Resolve -Wsign-compare warning
Resolves a -Wsign-compare warning on Clang.
2021-01-17 02:47:48 -05:00
Lioncash
40acc2c079 video_core: Resolve -Wdocumentation warnings
Silences some -Wdocumentation warnings on Clang.
2021-01-17 02:44:21 -05:00
Lioncash
c61b973968 vulkan_debug_callback: Add missing header guard
Prevents inclusion issues from occurring.
2021-01-17 02:39:24 -05:00
Rodrigo Locatti
0e0fc07135 Merge pull request #5740 from lioncash/const-fn
input_interpreter: Mark two member functions as const
2021-01-16 20:02:02 -03:00
Rodrigo Locatti
fd873fd369 Merge pull request #5262 from ReinUsesLisp/buffer-base
buffer_cache/buffer_base: Add a range tracking buffer container and tests
2021-01-16 19:48:26 -03:00
Lioncash
ca9afa3293 input_interpreter: Mark two member functions as const
These aren't stateful functions, so we can make use of const.

While we're at, we can resolve some -Wdocumentation warnings.
2021-01-16 16:08:35 -05:00
bunnei
ff2b7cc0d3 Merge pull request #5366 from Morph1984/button-press
input_interpreter: Add method to check for a button press state
2021-01-16 13:00:54 -08:00
Morph
3c8f936b31 input_interpreter: Add method to check for a button press state
This allows to check for continuous input for the duration of a button press/hold
2021-01-16 10:34:39 -05:00
bunnei
a7fd61fcce Merge pull request #5275 from FernandoS27/fast-native-clock
X86/NativeClock: Improve performance of clock calculations on hot path.
2021-01-15 23:01:42 -08:00
bunnei
8def504d73 Merge pull request #5336 from lioncash/tree
common/tree: Convert defines over to templates
2021-01-15 21:46:25 -08:00
Rodrigo Locatti
c17ee0da5d Merge pull request #5297 from ReinUsesLisp/vulkan-allocator-common
vulkan_memory_allocator: Improvements to the memory allocator
2021-01-15 21:50:05 -03:00
ReinUsesLisp
c3c7603076 vk_shader_decompiler: Show comments as OpUndef with a type
Silence the new validation layer error about SPIR-V not allowing OpUndef
on a OpTypeVoid, even when the SPIR-V spec doesn't say anything against
it.

They will be inserted as an undefined int to avoid SPIRV-Cross and
validation errors, but only when a debugging tool is attached.
2021-01-15 21:12:57 -03:00
LC
8be9e5b48b Merge pull request #5358 from ReinUsesLisp/rename-insert-padding
common/common_funcs: Rename INSERT_UNION_PADDING_{BYTES,WORDS} to _NOINIT
2021-01-15 16:19:46 -05:00
ReinUsesLisp
5f517e3e16 core/cmake: Enforce Wclass-memaccess
Treat -Wclass-memaccess as an error.
2021-01-15 16:31:19 -03:00
ReinUsesLisp
f8650a9580 core: Silence Wclass-memaccess warnings
This requires making several types trivial and properly initialize
them whenever they are called.
2021-01-15 16:31:19 -03:00
ReinUsesLisp
3ff978aa4f common/common_funcs: Rename INSERT_UNION_PADDING_{BYTES,WORDS} to _NOINIT
INSERT_PADDING_BYTES_NOINIT is more descriptive of the underlying behavior.
2021-01-15 16:27:28 -03:00
ReinUsesLisp
301e2b5b7a vulkan_memory_allocator: Remove unnecesary 'device' memory from commits 2021-01-15 16:19:40 -03:00
ReinUsesLisp
432f045dba vk_texture_cache: Use Download memory types for texture flushes
Use the Download memory type where it matters.
2021-01-15 16:19:40 -03:00
ReinUsesLisp
8f22f5470c vulkan_memory_allocator: Add allocation support for download types
Implements the allocator logic to handle download memory types. This
will try to use HOST_CACHED_BIT when available.
2021-01-15 16:19:39 -03:00
ReinUsesLisp
72541af3bc vulkan_memory_allocator: Add "download" memory usage hint
Allow users of the allocator to hint memory usage for downloads. This
removes the non-descriptive boolean passed for "host visible" or not
host visible memory commits, and uses an enum to hint device local,
upload and download usages.
2021-01-15 16:19:39 -03:00
ReinUsesLisp
fade63b58e vulkan_common: Move allocator to the common directory
Allow using the abstraction from the OpenGL backend.
2021-01-15 16:19:39 -03:00
ReinUsesLisp
c2b550987b renderer_vulkan: Rename Vulkan memory manager to memory allocator
"Memory manager" collides with the guest GPU memory manager, and a
memory allocator sounds closer to what the abstraction aims to be.
2021-01-15 16:19:39 -03:00
ReinUsesLisp
e996f1ad09 vk_memory_manager: Improve memory manager and its API
Fix a bug where the memory allocator could leave gaps between commits.
To fix this the allocation algorithm was reworked, although it's still
short in number of lines of code.

Rework the allocation API to self-contained movable objects instead of
naively using an unique_ptr to do the job for us. Remove the VK prefix.
2021-01-15 16:19:36 -03:00
bunnei
f728a504aa Merge pull request #5355 from lioncash/timer
common/timer: Remove
2021-01-15 09:42:33 -08:00
german
b483f2d010 Always initialize keyboard input 2021-01-15 09:05:17 -06:00
german
8495e1bd83 Add mutitouch support for touch screens 2021-01-15 09:05:17 -06:00
german
d8df9a16bd Allow to return up to 16 touch inputs per engine 2021-01-15 09:05:17 -06:00
german
390ee10eef Allow all touch inputs at the same time and remove config options that are not longer necesary 2021-01-15 09:05:17 -06:00
german
d583e01f54 Add multitouch support 2021-01-15 09:03:39 -06:00
LC
9754a8145c Merge pull request #5357 from ReinUsesLisp/alignment-log2
common/alignment: Rename AlignBits to AlignUpLog2 and use constraints
2021-01-15 03:12:36 -05:00
Rodrigo Locatti
5b9aedfc21 Merge pull request #5356 from lioncash/clz
common/bit_util: Replace CLZ/CTZ operations with standardized ones
2021-01-15 04:48:58 -03:00
Lioncash
8620de6b20 common/bit_util: Replace CLZ/CTZ operations with standardized ones
Makes for less code that we need to maintain.
2021-01-15 02:15:32 -05:00
ReinUsesLisp
89c15dd115 common/alignment: Upgrade to use constraints instead of static asserts 2021-01-15 04:13:39 -03:00
ReinUsesLisp
fe494a0ccd common/alignment: Rename AlignBits to AlignUpLog2
AlignUpLog2 describes what the function does better than AlignBits.
2021-01-15 04:13:33 -03:00
Lioncash
91084d9396 common/timer: Remove
This is a leftover from citra and dolphin that isn't used at all,
particularly given the <chrono> header exists.
2021-01-15 01:55:33 -05:00
LC
c8bf0caca0 Merge pull request #5354 from ReinUsesLisp/remove-common-color
common/color: Remove
2021-01-15 01:54:22 -05:00
LC
6676687694 Merge pull request #5352 from ReinUsesLisp/remove-tester
cmake: Remove yuzu_tester
2021-01-15 01:48:02 -05:00
ReinUsesLisp
95fa57f007 common/color: Remove
This is a leftover from Citra we no longer use.
2021-01-15 03:47:43 -03:00
LC
7f37822c74 Merge pull request #5353 from ReinUsesLisp/deduplicate-warning-flags
{video_,}core/cmake: Remove Werror flags already defined code-base wide
2021-01-15 01:45:01 -05:00
ReinUsesLisp
fb99446f24 core/cmake: Remove Werror flags already defined code-base wide 2021-01-15 03:39:24 -03:00
ReinUsesLisp
cc2c3e447f video_core/cmake: Remove Werror flags already defined code-base wide
These flags are already defined in src/cmake.
2021-01-15 03:37:34 -03:00
LC
28e78d81b2 Merge pull request #5351 from ReinUsesLisp/vc-unused-functions
cmake: Enforce -Wunused-function code-base wise
2021-01-15 01:36:51 -05:00
Rodrigo Locatti
185388f341 Merge pull request #5350 from ReinUsesLisp/vk-init-warns
vulkan_common: Silence missing initializer warnings
2021-01-15 03:32:01 -03:00
LC
76b465f3ef Merge pull request #5349 from ReinUsesLisp/anv-fix
vulkan_device: Enable shaderStorageImageMultisample conditionally
2021-01-15 01:17:00 -05:00
ReinUsesLisp
af540b0057 cmake: Remove yuzu_tester
We never ended up using yuzu_tester.
Removing it saves code duplication with yuzu_cmd, and distribution size on
prebuilt packages.

For unit testing, we can use catch2 from guest code and dump the results
to a file. Then execute yuzu from a script on ci if we want this to be
automated.
2021-01-15 03:14:44 -03:00
ReinUsesLisp
06e0506cb3 cmake: Enforce -Wunused-function code-base wide 2021-01-15 03:09:48 -03:00
ReinUsesLisp
71264ce9a7 video_core: Enforce -Wunused-function
Stops us from merging code with unused functions in the future.

If something is invoked behind conditionally evaluated code in
a way that the language can't see it (e.g. preprocessor macros), the
potentially unused function should use [[maybe_unused]].
2021-01-15 02:59:25 -03:00
LC
6dc1d48fd1 Merge pull request #5348 from ReinUsesLisp/astc-robustness
astc: Make the decoder more robust to invalid data
2021-01-15 00:59:10 -05:00
ReinUsesLisp
3e03391a49 vk_buffer_cache: Remove unused function 2021-01-15 02:58:55 -03:00
ReinUsesLisp
be8fd5490e vulkan_common: Silence missing initializer warnings
Silence warnings explicitly initializing all members on construction.
2021-01-15 02:55:11 -03:00
ReinUsesLisp
ba2ea7eeac vulkan_device: Enable shaderStorageImageMultisample conditionally
Fix Vulkan initialization on ANV.
2021-01-15 02:47:05 -03:00
ReinUsesLisp
22be115eb2 astc: Increase integer encoded vector size
Invalid ASTC textures seem to write more bytes here, increase
the size to something that can't make us push out of bounds.
2021-01-15 02:24:36 -03:00
ReinUsesLisp
0ec71b78fb astc: Return zero on out of bound bits
Avoid out of bound reads on invalid ASTC textures.
Games can bind invalid textures that make us read or write out of bounds.
2021-01-15 02:24:36 -03:00
LC
93f7719eed Merge pull request #5302 from lat9nq/appimage-update
ci/linux: Make Mainline AppImages updateable
2021-01-14 18:46:27 -05:00
bunnei
4038ca2e5d Merge pull request #5345 from lioncash/unused-var
yuzu: Remove unused variables in Qt code
2021-01-14 01:23:50 -08:00
Lioncash
e11e1dcf2d yuzu: Remove unused variables in Qt code
Removes two unused variables in out Qt code. In this case the removal of
these two results in less allocations, given std::map allocates on the
heap.
2021-01-14 03:05:41 -05:00
Morph
f1e278c30f Merge pull request #5343 from lioncash/qt6
configure_motion_touch: Migrate off QRegExp to QRegularExpression
2021-01-14 15:30:26 +08:00
Morph
980973d83e Merge pull request #5344 from lioncash/move
configure_motion_touch: Prevent use after move in ApplyConfiguration()
2021-01-14 15:24:03 +08:00
Lioncash
45aee996c1 configure_motion_touch: Prevent use after move in ApplyConfiguration()
touch_engine was being compared against after being moved into the
setter for the engine, so this comparison wouldn't behave properly.
2021-01-13 22:37:40 -05:00
Lioncash
a2952ac213 configure_motion_touch: Migrate off QRegExp to QRegularExpression
QRegularExpression was introduced in Qt 5 as a better replacement for
QRegExp. In Qt 6.0 QRegExp is removed entirely.

To remain forward compatible with Qt 6.0, we can transition over to
using QRegularExpression.
2021-01-13 22:25:52 -05:00
LC
5e35c69f35 Merge pull request #5330 from german77/regexerror
Fix IP validator error
2021-01-13 22:08:42 -05:00
bunnei
2c2ef9252f Merge pull request #5342 from lioncash/qt6
yuzu: Migrate off of setMargin() to setContentsMargins()
2021-01-13 10:44:21 -08:00
german
06cf705501 Fix IP validator error where the last octet produced an error if the value was higher than 199 2021-01-13 11:02:28 -06:00
Lioncash
0d7de7c2db yuzu: Migrate off of setMargin() to setContentsMargins()
setMargin() has been deprecated since Qt 5, and replaced with
setContentsMargins(). We can move over to setContentsMargins() to stay
forward-compatible with Qt 6.0.
2021-01-13 07:29:59 -05:00
Morph
baff865d7c Merge pull request #5341 from ReinUsesLisp/anv-storage
vulkan_device: Remove requirement on shaderStorageImageMultisample
2021-01-13 18:00:52 +08:00
ReinUsesLisp
d9a15a935b vulkan_device: Remove requirement on shaderStorageImageMultisample
yuzu doesn't currently emulate MS image stores. Requiring this makes no
sense for now. Fixes ANV not booting any games on Vulkan.
2021-01-13 06:21:33 -03:00
ReinUsesLisp
7bd603061c tests: Add unit tests for the GPU range tracking buffer container
Due to how error prone the container design is, this commit adds unit
tests for it.

Some tests taken from here are based on bugs from using this buffer
container in games, so if we ever break it in the future in a way that
might harm games, the tests should fail.
2021-01-13 04:31:40 -03:00
LC
c320da3f63 Merge pull request #5340 from Morph1984/gcc-warnings
cmake: Enforce -Werror=switch and -Werror=unused-variable
2021-01-13 02:30:31 -05:00
ReinUsesLisp
a4bfae1b55 buffer_cache/buffer_base: Add a range tracking buffer container
It keeps track of the modified CPU and GPU ranges on a CPU page
granularity, notifying the given rasterizer about state changes
in the tracking behavior of the buffer.

Use a small vector optimization to store buffers smaller than 256 KiB
locally instead of using free store memory allocations.
2021-01-13 04:14:58 -03:00
Morph
2b98da2ed4 cmake: Enforce -Werror=switch and -Werror=unused-variable 2021-01-13 01:57:18 -05:00
bunnei
0fb19e9bef Merge pull request #5280 from FearlessTobi/port-5666
Port citra-emu/citra#5666: "Rotate previous log file to "citra_log.txt.old""
2021-01-12 22:16:57 -08:00
bunnei
de1a316369 Merge pull request #5311 from ReinUsesLisp/fence-wait
vk_fence_manager: Use timeline semaphores instead of spin waits
2021-01-12 21:00:05 -08:00
Lioncash
b15e1a3501 common/tree: Convert defines over to templates
Reworks the tree header to operate off of templates as opposed to a
series of defines.

This allows all tree facilities to obey namespacing rules, and also
allows this code to be used within modules once compiler support is in
place.

This also gets rid to use a macro to define functions and structs for
necessary data types. With templates, these will be generated when
they're actually used, eliminating the need for the separate
declaration.
2021-01-12 16:46:36 -05:00
Lioncash
197b5d19bc common/tree: Remove unused splay tree defines
Makes for less code to take care of.
2021-01-12 02:32:41 -05:00
bunnei
99d2d77062 Merge pull request #5333 from lioncash/define
common/parent_of_member: Replace TYPED_STORAGE define with template alias
2021-01-11 20:47:30 -08:00
Lioncash
703c57a119 common/parent_of_member: Replace TYPED_STORAGE define with template alias
Provides the same construct, but makes it obey namespacing.
2021-01-11 18:26:04 -05:00
bunnei
eb3cb54aa5 Merge pull request #5266 from bunnei/kernel-synch
Rewrite KSynchronizationObject, KConditonVariable, and KAddressArbiter
2021-01-11 14:36:26 -08:00
bunnei
03dfc8d8e7 hle: kernel: thread: Preserve thread wait reason for debugging only.
- This is decoupled from core functionality and used for debugging only.
2021-01-11 14:23:17 -08:00
bunnei
81c1bfafea yuzu: debugger: wait_tree: Handle unknown ThreadState. 2021-01-11 14:23:16 -08:00
bunnei
6b2f653143 hle: kernel: k_scheduler_lock: Fix shadowing errors. 2021-01-11 14:23:16 -08:00
bunnei
354130cd84 core: arm: arm_interface: Fix shadowing errors. 2021-01-11 14:23:16 -08:00
bunnei
82f6037ec2 core: hle: Add missing calls to MicroProfileOnThreadExit. 2021-01-11 14:23:16 -08:00
bunnei
912dd50146 core: hle: Integrate new KConditionVariable and KAddressArbiter implementations. 2021-01-11 14:23:16 -08:00
bunnei
952d1ac487 core: hle: kernel: Update KAddressArbiter. 2021-01-11 14:23:16 -08:00
bunnei
b4e6d6c385 core: hle: kernel: Update KConditionVariable. 2021-01-11 14:23:16 -08:00
bunnei
1212fa60b6 core: hle: kernel: Begin moving common SVC defintions to its own header. 2021-01-11 14:23:16 -08:00
bunnei
8a155c4058 hle: kernel: Remove unnecessary AddressArbiter definition. 2021-01-11 14:23:16 -08:00
bunnei
92d5c63f01 common: common_funcs: Add R_UNLESS macro. 2021-01-11 14:23:16 -08:00
bunnei
f12701b303 hle: kernel: k_scheduler: Cleanup OnThreadPriorityChanged. 2021-01-11 14:23:16 -08:00
bunnei
d1309fb275 hle: kernel: Rename thread "status" to "state". 2021-01-11 14:23:16 -08:00
bunnei
c3c43e32fc hle: kernel: thread: Replace ThreadStatus/ThreadSchedStatus with a single ThreadState.
- This is how the real kernel works, and is more accurate and simpler.
2021-01-11 14:23:16 -08:00
bunnei
7420a717e6 core: hle: kernel: Add some useful functions for checking kernel addresses. 2021-01-11 14:23:16 -08:00
bunnei
4bbf173fc1 core: hle: kernel: svc_types: Add type definitions for KAddressArbiter. 2021-01-11 14:23:16 -08:00
bunnei
fb43b8efd2 common: Introduce useful tree structures. 2021-01-11 14:23:16 -08:00
bunnei
35c3c078e3 core: hle: kernel: Update KSynchronizationObject. 2021-01-11 14:23:16 -08:00
bunnei
1ae883435d core: hle: kernel: Begin moving common SVC results to its own header. 2021-01-11 14:23:16 -08:00
bunnei
8fc6e92ef1 hle: service: nfp: Remove incorrect signaling behavior in GetDeviceState. 2021-01-11 14:23:16 -08:00
Levi
7a3c884e39 Merge remote-tracking branch 'upstream/master' into int-flags 2021-01-10 22:09:56 -07:00
bunnei
46cd71d1c7 Merge pull request #5229 from Morph1984/fullscreen-opt
yuzu/main: Add basic command line arguments
2021-01-10 18:53:04 -08:00
LC
5e161b2531 Merge pull request #5324 from Morph1984/docked-default
config: Enable docked mode by default
2021-01-10 20:51:33 -05:00
bunnei
32df83e55d Merge pull request #5312 from german77/overclockenabled
apm: Stub IsCpuOverclockEnabled
2021-01-10 14:30:13 -08:00
Morph
05f58144c9 config: Enable docked mode by default 2021-01-10 09:37:38 -05:00
bunnei
fe9588f4a0 Merge pull request #5323 from Morph1984/enforce-c4101
cmake: Enforce C4101
2021-01-09 22:49:58 -08:00
Morph
25724898d0 cmake: Enforce C4101
This matches GCC's -Wunused-variable
2021-01-10 01:16:25 -05:00
Morph
e07540264d yuzu_cmd: Silence unreferenced local variable warning 2021-01-10 01:10:36 -05:00
LC
0f932d30f5 Merge pull request #5320 from ReinUsesLisp/div-ceil-type
common/div_ceil: Return numerator type
2021-01-09 16:45:29 -05:00
LC
64a24f3344 Merge pull request #5322 from Morph1984/resolve-c4062-msvc
general: Resolve C4062 warnings on MSVC
2021-01-09 16:43:47 -05:00
Morph
4aae21e1e4 general: Resolve C4062 warnings on MSVC 2021-01-09 14:46:35 -05:00
ReinUsesLisp
c190586597 common/div_ceil: Return numerator type
Fixes instances where DivCeil(u32, u64) would surprisingly return u64,
instead of the more natural u32.
2021-01-09 03:16:10 -03:00
Rodrigo Locatti
7bad1974a6 Merge pull request #5319 from ReinUsesLisp/msvc-warnings
cmake: Enforce C4062, C4265, C4388, and C5038
2021-01-09 03:13:25 -03:00
ReinUsesLisp
d7128845c9 cmake: Enforce C4062, C4265, C4388, and C5038
This should match some warnings we treat as errors on gcc and clang,
caching bugs early and reducing the number of instances where we have to
edit commits to make CI happy when developing from Windows.
2021-01-09 02:19:17 -03:00
ReinUsesLisp
c68d0dc851 file_sys/registered_cache: Silence virtual functions without override warnings 2021-01-09 00:04:12 -03:00
ReinUsesLisp
b4451c5e81 core: Silence unhandled enum in switch warnings 2021-01-08 23:21:07 -03:00
ReinUsesLisp
613b3671b7 tests/ring_buffer: Silence signed/unsigned mismatch warnings 2021-01-08 23:14:38 -03:00
bunnei
8eea7c1176 Merge pull request #5231 from ReinUsesLisp/dyn-bindings
renderer_vulkan/fixed_pipeline_state: Move enabled bindings to static state
2021-01-08 12:24:46 -08:00
german
385a4555d5 Stub IsCpuOverclockEnabled 2021-01-08 09:44:56 -06:00
bunnei
61f707d708 Merge pull request #5300 from JeremyStarTM/patch-1
Removed MacOS build link
2021-01-08 00:02:12 -08:00
ReinUsesLisp
154a7653f9 vk_fence_manager: Use timeline semaphores instead of spin waits
With timeline semaphores we can avoid creating objects. Instead of
creating an event, grab the current tick from the scheduler and flush
the current command buffer. When the fence has to be queried/waited, we
can do so against the master semaphore instead of spinning on an event.

If Vulkan supported NVN like events or fences, we could signal from the
command buffer and wait for that without splitting things in two
separate command buffers.
2021-01-08 02:47:28 -03:00
bunnei
c72571055b Merge pull request #5310 from lat9nq/fix-disable-web-service
CMakeLists: Disable YUZU_ENABLE_BOXCAT if ENABLE_WEB_SERVICE is disabled
2021-01-07 17:10:34 -08:00
lat9nq
78be397723 CMakeLists: Disable YUZU_ENABLE_BOXCAT if ENABLE_WEB_SERVICE is disabled
Boxcat is a web service but is still enabled if ENABLE_WEB_SERVICE is
disabled during the CMake stage, which causes compilation issues with
either missing headers or missing libraries.

This disables YUZU_ENABLE_BOXCAT regardless of the input if
ENABLE_WEB_SERVICE is disabled.
2021-01-07 17:28:15 -05:00
bunnei
aaf9e39f56 Merge pull request #5237 from ameerj/nvdec-syncpt
nvdec: Incorporate syncpoint manager
2021-01-07 12:42:28 -08:00
Ameer J
16392a23cc remove inaccurate reference
Co-authored-by: LC <mathew1800@gmail.com>
2021-01-07 14:33:45 -05:00
ameerj
06cef3355e fix for nvdec disabled, cleanup host1x 2021-01-07 14:33:45 -05:00
ameerj
2c27127d04 nvdec syncpt incorporation
laying the groundwork for async gpu, although this does not fully implement async nvdec operations
2021-01-07 14:33:45 -05:00
Morph
bcb702fa3e Merge pull request #5306 from MerryMage/ignore-library-Open
vulkan_library: Common::DynamicLibrary::Open is [[nodiscard]]
2021-01-08 01:44:18 +08:00
MerryMage
21199cb965 vulkan_library: Common::DynamicLibrary::Open is [[nodiscard]]
Ignore the return value on __APPLE__ systems as well
2021-01-07 17:37:47 +00:00
Morph
123568ef80 Merge pull request #5305 from MerryMage/page_shift
texture_cache: Replace PAGE_SHIFT with PAGE_BITS
2021-01-08 00:55:34 +08:00
MerryMage
aace20afc7 texture_cache: Replace PAGE_SHIFT with PAGE_BITS
PAGE_SHIFT is a #define in system headers that leaks into user code on some systems
2021-01-07 16:51:34 +00:00
lat9nq
0d24b1a31b ci/linux: Make Mainline AppImages updateable
Moves the final step for building the AppImage to the upload script.
Instructs appimagetool to embed update information into the AppImage if
the release target is Mainline. Also tells it to create a zsync file to
enable partial-downloads when updating the AppImage.

Also renames the AppImage from `yuzu-{version info}-x86_64.AppImage` to
`yuzu-{version info}.AppImage` to avoid a bug in the downloads page at
yuzu-emu.org/downloads.
2021-01-06 13:23:56 -05:00
JeremyStarTM
5b60899fbc Removed MacOS build link
The MacOS build link was removed in the README.md because it no longer exist.
2021-01-06 11:39:27 +01:00
Morph
e8d40559d5 Merge pull request #5288 from ReinUsesLisp/workaround-garbage
gl_texture_cache: Avoid format views on Intel and AMD
2021-01-06 15:39:51 +08:00
bunnei
e112d0a52f Merge pull request #5250 from lat9nq/appimage
ci/linux: Build an AppImage
2021-01-05 21:34:08 -08:00
bunnei
dc02b03c4a Merge pull request #5293 from ReinUsesLisp/return-values
core: Enforce C4715 (not all control paths return a value)
2021-01-05 19:04:15 -08:00
bunnei
275b96a0e2 Merge pull request #5289 from ReinUsesLisp/vulkan-device
vulkan_common: Move device abstraction to the common directory and allow surfaceless devices
2021-01-05 17:44:56 -08:00
ReinUsesLisp
43d9f417ae core: Enforce C4715 (not all control paths return a value) 2021-01-05 04:18:40 -03:00
ReinUsesLisp
4f13e270c8 core: Silence warnings when compiling without asserts 2021-01-05 04:18:16 -03:00
LC
2a6e6306d8 Merge pull request #5292 from ReinUsesLisp/empty-set
vk_rasterizer: Skip binding empty descriptor sets on compute
2021-01-04 21:32:57 -05:00
bunnei
4e6aa1cfdd Merge pull request #5261 from gal20/hide_mouse_patch
yuzu/main: Fix 'Hide mouse on inactivity' and port citra-emu/citra#5476
2021-01-04 17:19:04 -08:00
ReinUsesLisp
1ccf805367 vk_rasterizer: Skip binding empty descriptor sets on compute
Fixes unit tests where compute shaders had no descriptors in the set,
making Vulkan drivers crash when binding an empty set.
2021-01-04 17:56:39 -03:00
Morph
ace8a8e86e Merge pull request #5284 from ameerj/bufferq-oor-fix
buffer_queue: Fix data race by protecting queue_sequence access
2021-01-04 15:42:40 +08:00
ameerj
6b354ccaee buffer_queue: Protect queue_sequence list access with a mutex
fixes a data race as this is an unprotected variable manipulated by multiple threads
2021-01-04 01:36:41 -05:00
FearlessTobi
8e77d331be yuzu/configure_filesystem: Remove "Select Cache Directory" option
This tab of the settings is already extremely bloated and the setting itself is quite useless.
With a gamelist of almost 30 games, the cache directory is smaller than 1MB for me and therefore I don't see why it needs to be configurable.
2021-01-04 06:29:48 +01:00
ReinUsesLisp
ac1e4734c2 vulkan_device: Allow creating a device without surface 2021-01-04 02:22:22 -03:00
ReinUsesLisp
d235cf3933 renderer_vulkan/nsight_aftermath_tracker: Move to vulkan_common 2021-01-04 02:22:22 -03:00
ReinUsesLisp
3753553b6a renderer_vulkan: Move device abstraction to vulkan_common 2021-01-04 02:22:22 -03:00
Rodrigo Locatti
4801f4250d Merge pull request #5286 from ReinUsesLisp/rename-vk-device
renderer_vulkan: Rename VKDevice to Device
2021-01-04 02:22:02 -03:00
ReinUsesLisp
7d904fef2e gl_texture_cache: Avoid format views on Intel and AMD
Intel and AMD proprietary drivers are incapable of rendering to texture
views of different formats than the original texture. Avoid creating
these at a cache level. This will consume more memory, emulating them
with copies.
2021-01-04 02:06:40 -03:00
ReinUsesLisp
3a49c1a691 gl_texture_cache: Create base images with sRGB
This breaks accelerated decoders trying to imageStore into images with
sRGB. The decoders are currently disabled so this won't cause issues at
runtime.
2021-01-04 01:54:54 -03:00
Rodrigo Locatti
87a8925523 Merge pull request #5285 from lioncash/error-str
main: Resolve error string not displaying
2021-01-03 19:56:15 -03:00
ReinUsesLisp
974d731926 renderer_vulkan: Rename VKDevice to Device
The "VK" prefix predates the "Vulkan" namespace. It was carried around
the codebase for consistency. "VKDevice" currently is a bad alias with
"VkDevice" (only an upcase character of difference) that can cause
confusion. Rename all instances of it.
2021-01-03 17:51:48 -03:00
Rodrigo Locatti
7265e80c12 Merge pull request #5230 from ReinUsesLisp/vulkan-common
vulkan_common: Move reusable Vulkan abstractions to a separate directory
2021-01-03 17:38:29 -03:00
Lioncash
86592b274e main: Resolve error string not displaying
During the transition to make the error dialog translatable, I
accidentally got rid of the conversion to ResultStatus, which prevented
operator<< from being invoked during formatting.

This adds a function to directly retrieve the result status string
instead so that it displays again.
2021-01-03 13:18:04 -05:00
bunnei
71e18dddbe Merge pull request #5278 from MerryMage/cpuopt_unsafe_inaccurate_nan
dynarmic: Add Unsafe_InaccurateNaN optimization
2021-01-03 03:27:29 -08:00
bunnei
f64456c7e2 Merge pull request #5279 from bunnei/buffer-queue-connect
hle: service: nvflinger: buffer_queue: Do not reset id/layer_id on Connect.
2021-01-03 01:01:38 -08:00
Morph
ec58aabb26 Merge pull request #5281 from FearlessTobi/port-5668
Port citra-emu/citra#5668: "Update zstd to v1.4.8"
2021-01-03 12:25:21 +08:00
FearlessTobi
c90268127b Update zstd to v1.4.8
Co-Authored-By: Vitor K <29167336+vitor-k@users.noreply.github.com>
2021-01-03 01:58:14 +01:00
bunnei
beaa25d777 hle: service: nvflinger: buffer_queue: Do not reset id/layer_id on Connect.
- This behavior is a mistake, fixes Katana Zero.
2021-01-02 15:42:16 -08:00
MerryMage
8a5356357f externals: Update dynarmic to 3806284cb 2021-01-02 20:42:11 +00:00
MerryMage
57c9da1b39 dynarmic: Add Unsafe_InaccurateNaN optimization 2021-01-02 20:13:21 +00:00
Fernando Sahmkow
53d92318b8 X86/NativeClock: Reimplement RTDSC access to be lock free. 2021-01-02 04:00:27 +01:00
Fernando Sahmkow
d4f871cb6a X86/NativeClock: Improve performance of clock calculations on hot path. 2021-01-02 00:43:47 +01:00
gal20
5dfb8743cb yuzu/main: fix mouse not showing on move and port citra-emu/citra#5476 2020-12-31 21:16:09 +02:00
ReinUsesLisp
cdbee27692 vulkan_instance: Allow different Vulkan versions and enforce 1.1
For listing the available physical devices we can use Vulkan 1.0.
Now that MoltenVK supports 1.1 we can require it for running games.

Add missing documentation.
2020-12-31 02:07:34 -03:00
ReinUsesLisp
7344a7c447 vk_device: Use an array to report lacking device limits
This makes easier to add and tune the required device limits.
2020-12-31 02:07:34 -03:00
ReinUsesLisp
f687392e6f vk_device: Stop initialization when device is not suitable
VKDevice::IsSuitable was not being called. To address this issue, check
suitability before initialization and throw an exception if it fails.

By doing this, we can deduplicate some code on queue searches.
Previosuly we would first search if a present and graphics queue
existed, then on initialization we would search again to find the index.
2020-12-31 02:07:33 -03:00
ReinUsesLisp
53ea06dc17 renderer_vulkan: Remove two step initialization on VKDevice
The Vulkan device abstraction either initializes successfully on the
constructor or throws a Vulkan exception.
2020-12-31 02:07:33 -03:00
ReinUsesLisp
085adfea00 renderer_vulkan: Throw when enumerating devices fails
Report device enumeration errors with exceptions to be consistent with
other initialization related function calls. Reduces the amount of code
to maintain.
2020-12-31 02:07:33 -03:00
ReinUsesLisp
11f0f7598d renderer_vulkan: Initialize surface in separate file
Move surface initialization code to a separate file. It's unlikely to
use this code outside of Vulkan, but keeping platform-specific code
(Win32, Xlib, Wayland) in its own translation unit keeps things cleaner.
2020-12-31 02:07:33 -03:00
ReinUsesLisp
dce8720780 renderer_vulkan: Catch and report exceptions
Move more Vulkan code to report errors with exceptions and report them
through a log before notifying it with an error boolean for backwards
compatibility. In the future we can replace the rasterizer two-step
initialization to always use exceptions.
2020-12-31 02:07:33 -03:00
ReinUsesLisp
47843b4f09 renderer_vulkan: Create debug callback on separate file and throw
Initialize debug callbacks (messenger) from a separate file. This allows
sharing code with different backends.

Change our Vulkan error handling to use exceptions instead of error
codes, simplifying the initialization process.
2020-12-31 02:07:33 -03:00
ReinUsesLisp
25f88d99ce renderer_vulkan: Move instance initialization to a separate file
Simplify Vulkan's backend initialization code by moving it to a separate
file, allowing us to initialize a Vulkan instance from different
backends.
2020-12-31 02:07:33 -03:00
ReinUsesLisp
d1435009ed vulkan_common: Rename renderer_vulkan/wrapper.h to vulkan_common/vulkan_wrapper.h
Allows sharing Vulkan wrapper code between different rendering backends.
2020-12-31 02:07:14 -03:00
ReinUsesLisp
d937421422 vulkan_common: Move dynamic library load to a separate file
Allows us to initialize a Vulkan dynamic library from different backends
without duplicating code.
2020-12-31 02:02:48 -03:00
lat9nq
43cad754d5 ci: Build an AppImage
This builds yuzu in an AppImage alongside the other archives during
release. Required to allow distributing yuzu in the future with upgraded
dependencies, such as Qt.
2020-12-30 16:05:15 -05:00
ReinUsesLisp
661483f313 renderer_vulkan/fixed_pipeline_state: Move enabled bindings to static state
Without using VK_EXT_robustness2, we can't consider the 'enabled' (not
null) vertex buffers as dynamic state, as this leads to invalid Vulkan
state. Move this to static state that is always hashed and compared in
the pipeline key.

The bits for enabled vertex buffers are moved into the attribute state
bitfield. This is not 'correct' as it's not an attribute state, but that
struct has bits to spare, and it's used in an array of 32 elements (the
exact same number of vertex buffer bindings).
2020-12-25 23:34:38 -03:00
Morph
ff3aa5d380 yuzu/main: Add basic command line arguments
The following command line arguments are supported:

yuzu.exe "path_to_game" - Launches a game at "path_to_game"
yuzu.exe -f - Launches the next game in fullscreen
yuzu.exe -g "path_to_game" - Launches a game at "path_to_game"
yuzu.exe -f -g "path_to_game" - Launches a game at "path_to_game" in fullscreen
2020-12-25 15:41:00 -05:00
Levi Behunin
bc69cc1511 More forgetting... duh 2020-09-24 22:12:13 -06:00
Levi Behunin
24c1bb3842 Forgot to apply suggestion here as well 2020-09-24 21:58:51 -06:00
Levi Behunin
a19dc3bf00 Address Comments 2020-09-24 21:52:23 -06:00
Levi Behunin
d53b79ff5c Start of Integer flags implementation 2020-09-24 16:40:06 -06:00
Vitor Kiguchi
e6f9fe1f60 sdl_joystick: disable the use of the hidapi drivers due to many problems caused by them.
The main problem is the loss of compatibility with some controllers, but there are also
unwanted changes to the behaviour of PS4 controllers (hardcoded lightbar color).
2020-08-30 05:06:49 +02:00
540 changed files with 25252 additions and 16949 deletions

View File

@@ -15,5 +15,5 @@ mv "${REV_NAME}-source.tar.xz" $RELEASE_NAME
7z a "$REV_NAME.7z" $RELEASE_NAME
# move the compiled archive into the artifacts directory to be uploaded by travis releases
mv "$ARCHIVE_NAME" artifacts/
mv "$REV_NAME.7z" artifacts/
mv "$ARCHIVE_NAME" "${ARTIFACTS_DIR}/"
mv "$REV_NAME.7z" "${ARTIFACTS_DIR}/"

View File

@@ -2,5 +2,6 @@
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
GITREV="`git show -s --format='%h'`"
ARTIFACTS_DIR="artifacts"
mkdir -p artifacts
mkdir -p "${ARTIFACTS_DIR}/"

View File

@@ -1,14 +1,49 @@
#!/bin/bash -ex
# Exit on error, rather than continuing with the rest of the script.
set -e
cd /yuzu
ccache -s
mkdir build || true && cd build
cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON
cmake .. -DDISPLAY_VERSION=$1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_INSTALL_PREFIX="/usr"
ninja
make -j$(nproc)
ccache -s
ctest -VV -C Release
make install DESTDIR=AppDir
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
# Download tools needed to build an AppImage
wget -nc https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget -nc https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/AppRun-patched-x86_64
wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/exec-x86_64.so
# Set executable bit
chmod 755 \
AppRun-patched-x86_64 \
exec-x86_64.so \
linuxdeploy-x86_64.AppImage \
linuxdeploy-plugin-qt-x86_64.AppImage
# Workaround for https://github.com/AppImage/AppImageKit/issues/828
export APPIMAGE_EXTRACT_AND_RUN=1
mkdir -p AppDir/usr/optional
mkdir -p AppDir/usr/optional/libstdc++
mkdir -p AppDir/usr/optional/libgcc_s
# Deploy yuzu's needed dependencies
./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt
# Workaround for building yuzu with GCC 10 but also trying to distribute it to Ubuntu 18.04 et al.
# See https://github.com/darealshinji/AppImageKit-checkrt
cp exec-x86_64.so AppDir/usr/optional/exec.so
cp AppRun-patched-x86_64 AppDir/AppRun
cp --dereference /usr/lib/x86_64-linux-gnu/libstdc++.so.6 AppDir/usr/optional/libstdc++/libstdc++.so.6
cp --dereference /lib/x86_64-linux-gnu/libgcc_s.so.1 AppDir/usr/optional/libgcc_s/libgcc_s.so.1

View File

@@ -2,6 +2,7 @@
. .ci/scripts/common/pre-upload.sh
APPIMAGE_NAME="yuzu-${GITDATE}-${GITREV}.AppImage"
REV_NAME="yuzu-linux-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.xz"
COMPRESSION_FLAGS="-cJvf"
@@ -17,4 +18,24 @@ mkdir "$DIR_NAME"
cp build/bin/yuzu-cmd "$DIR_NAME"
cp build/bin/yuzu "$DIR_NAME"
# Build an AppImage
cd build
wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod 755 appimagetool-x86_64.AppImage
if [ "${RELEASE_NAME}" = "mainline" ]; then
# Generate update information if releasing to mainline
./appimagetool-x86_64.AppImage -u "gh-releases-zsync|yuzu-emu|yuzu-${RELEASE_NAME}|latest|yuzu-*.AppImage.zsync" AppDir "${APPIMAGE_NAME}"
else
./appimagetool-x86_64.AppImage AppDir "${APPIMAGE_NAME}"
fi
cd ..
# Copy the AppImage and update info to the artifacts directory and avoid compressing it
cp "build/${APPIMAGE_NAME}" "${ARTIFACTS_DIR}/"
if [ -f "build/${APPIMAGE_NAME}.zsync" ]; then
cp "build/${APPIMAGE_NAME}.zsync" "${ARTIFACTS_DIR}/"
fi
. .ci/scripts/common/post-upload.sh

View File

@@ -42,3 +42,8 @@ done
pip3 install pefile
python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/"
python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/"
# copy FFmpeg libraries
EXTERNALS_PATH="$(pwd)/build/externals"
FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin"
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';'

3
.gitmodules vendored
View File

@@ -37,3 +37,6 @@
[submodule "opus"]
path = externals/opus/opus
url = https://github.com/xiph/opus.git
[submodule "ffmpeg"]
path = externals/ffmpeg
url = https://git.ffmpeg.org/ffmpeg.git

View File

@@ -18,6 +18,8 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "EN
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled yuzu" ON "WIN32" OFF)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON)
@@ -26,6 +28,10 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
if (NOT ENABLE_WEB_SERVICE)
set(YUZU_ENABLE_BOXCAT OFF)
endif()
# Default to a Release build
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
@@ -165,7 +171,7 @@ macro(yuzu_find_packages)
"lz4 1.8 lz4/1.9.2"
"nlohmann_json 3.8 nlohmann_json/3.8.0"
"ZLIB 1.2 zlib/1.2.11"
"zstd 1.4 zstd/1.4.5"
"zstd 1.4 zstd/1.4.8"
)
foreach(PACKAGE ${REQUIRED_LIBS})
@@ -239,7 +245,7 @@ if(ENABLE_QT)
if (YUZU_USE_QT_WEB_ENGINE)
find_package(Qt5 COMPONENTS WebEngineCore WebEngineWidgets)
endif()
if (ENABLE_QT_TRANSLATION)
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
endif()
@@ -257,7 +263,7 @@ if(ENABLE_SDL2)
find_package(SDL2)
if (NOT SDL2_FOUND)
# otherwise add this to the list of libraries to install
list(APPEND CONAN_REQUIRED_LIBS "sdl2/2.0.12@bincrafters/stable")
list(APPEND CONAN_REQUIRED_LIBS "sdl2/2.0.14@bincrafters/stable")
endif()
endif()
@@ -322,7 +328,7 @@ if (CONAN_REQUIRED_LIBS)
list(APPEND Boost_LIBRARIES Boost::context)
endif()
endif()
# Due to issues with variable scopes in functions, we need to also find_package(qt5) outside of the function
if(ENABLE_QT)
list(APPEND CMAKE_MODULE_PATH "${CONAN_QT_ROOT_RELEASE}")
@@ -380,19 +386,141 @@ if (NOT LIBUSB_FOUND)
set(LIBUSB_LIBRARIES usb)
endif()
# Use system installed ffmpeg.
if (NOT MSVC)
find_package(FFmpeg REQUIRED)
else()
set(FFMPEG_EXT_NAME "ffmpeg-4.2.1")
set(FFMPEG_PATH "${CMAKE_BINARY_DIR}/externals/${FFMPEG_EXT_NAME}")
download_bundled_external("ffmpeg/" ${FFMPEG_EXT_NAME} "")
set(FFMPEG_FOUND YES)
set(FFMPEG_INCLUDE_DIR "${FFMPEG_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
set(FFMPEG_LIBRARY_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg library" FORCE)
set(FFMPEG_DLL_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
# List of all FFmpeg components required
set(FFmpeg_COMPONENTS
avcodec
avutil
swscale)
if (NOT YUZU_USE_BUNDLED_FFMPEG)
# Use system installed FFmpeg
find_package(FFmpeg REQUIRED COMPONENTS ${FFmpeg_COMPONENTS})
if (FFmpeg_FOUND)
# Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries.
# Prevents shipping too many libraries with the AppImage.
set(FFmpeg_LIBRARIES "")
set(FFmpeg_INCLUDE_DIR "")
foreach(COMPONENT ${FFmpeg_COMPONENTS})
set(FFmpeg_LIBRARIES ${FFmpeg_LIBRARIES} ${FFmpeg_LIBRARY_${COMPONENT}} CACHE PATH "Paths to FFmpeg libraries" FORCE)
set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE)
endforeach()
else()
message(WARNING "FFmpeg not found, falling back to externals")
set(YUZU_USE_BUNDLED_FFMPEG ON)
endif()
endif()
if (YUZU_USE_BUNDLED_FFMPEG)
if (NOT WIN32)
# Build FFmpeg from externals
message(STATUS "Using FFmpeg from externals")
# FFmpeg has source that requires one of nasm or yasm to assemble it.
# REQUIRED throws an error if not found here during configuration rather than during compilation.
find_program(ASSEMBLER NAMES nasm yasm REQUIRED)
set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg)
set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg)
set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile)
make_directory(${FFmpeg_BUILD_DIR})
# Read version string from external
file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION)
set(FFmpeg_FOUND NO)
if (NOT FFmpeg_VERSION STREQUAL "")
set(FFmpeg_FOUND YES)
endif()
foreach(COMPONENT ${FFmpeg_COMPONENTS})
set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}")
set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a")
set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}")
set(FFmpeg_LIBRARIES
${FFmpeg_LIBRARIES}
${FFmpeg_${COMPONENT}_LIBRARY}
CACHE PATH "Paths to FFmpeg libraries" FORCE)
endforeach()
set(FFmpeg_INCLUDE_DIR
${FFmpeg_PREFIX}
CACHE PATH "Path to FFmpeg headers" FORCE)
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
# `--disable-{vaapi,vdpau}` is needed to avoid linking issues
add_custom_command(
OUTPUT
${FFmpeg_MAKEFILE}
COMMAND
/bin/bash ${FFmpeg_PREFIX}/configure
--disable-avdevice
--disable-avfilter
--disable-avformat
--disable-doc
--disable-everything
--disable-ffmpeg
--disable-ffprobe
--disable-network
--disable-postproc
--disable-swresample
--disable-vaapi
--disable-vdpau
--enable-decoder=h264
--enable-decoder=vp9
WORKING_DIRECTORY
${FFmpeg_BUILD_DIR}
)
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
# with context of the jobserver. Also helps ninja users.
execute_process(
COMMAND
nproc
OUTPUT_VARIABLE
SYSTEM_THREADS)
add_custom_command(
OUTPUT
${FFmpeg_LIBRARIES}
COMMAND
make -j${SYSTEM_THREADS}
WORKING_DIRECTORY
${FFmpeg_BUILD_DIR}
)
# ALL makes this custom target build every time
# but it won't actually build if the DEPENDS parameter is up to date
add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_LIBRARIES})
add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE})
if (FFmpeg_FOUND)
message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
add_dependencies(ffmpeg-build ffmpeg-configure)
else()
message(FATAL_ERROR "FFmpeg not found")
endif()
else() # WIN32
# Use yuzu FFmpeg binaries
set(FFmpeg_EXT_NAME "ffmpeg-4.3.1")
set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
set(FFmpeg_FOUND YES)
set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE)
set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
set(FFmpeg_LIBRARIES
${FFmpeg_LIBRARY_DIR}/swscale.lib
${FFmpeg_LIBRARY_DIR}/avcodec.lib
${FFmpeg_LIBRARY_DIR}/avutil.lib
CACHE PATH "Paths to FFmpeg libraries" FORCE)
endif()
endif()
unset(FFmpeg_COMPONENTS)
# Prefer the -pthread flag on Linux.
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

View File

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

View File

@@ -30,11 +30,10 @@ If you want to contribute to the user interface translation, please check out th
* __Windows__: [Windows Build](https://github.com/yuzu-emu/yuzu/wiki/Building-For-Windows)
* __Linux__: [Linux Build](https://github.com/yuzu-emu/yuzu/wiki/Building-For-Linux)
* __macOS__: [macOS Build](https://github.com/yuzu-emu/yuzu/wiki/Building-for-macOS)
### Support
We happily accept monetary donations or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like:
We happily accept monetary donations, or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like:
* Switch consoles to explore and reverse-engineer the hardware
* Switch games for testing, reverse-engineering, and implementing new features
* Web hosting and infrastructure setup

View File

@@ -1,26 +1,5 @@
<RCC>
<qresource prefix="controller">
<file alias="dual_joycon">dual_joycon.png</file>
<file alias="dual_joycon_dark">dual_joycon_dark.png</file>
<file alias="dual_joycon_midnight">dual_joycon_midnight.png</file>
<file alias="handheld">handheld.png</file>
<file alias="handheld_dark">handheld_dark.png</file>
<file alias="handheld_midnight">handheld_midnight.png</file>
<file alias="pro_controller">pro_controller.png</file>
<file alias="pro_controller_dark">pro_controller_dark.png</file>
<file alias="pro_controller_midnight">pro_controller_midnight.png</file>
<file alias="single_joycon_left">single_joycon_left.png</file>
<file alias="single_joycon_left_dark">single_joycon_left_dark.png</file>
<file alias="single_joycon_left_midnight">single_joycon_left_midnight.png</file>
<file alias="single_joycon_right">single_joycon_right.png</file>
<file alias="single_joycon_right_dark">single_joycon_right_dark.png</file>
<file alias="single_joycon_right_midnight">single_joycon_right_midnight.png</file>
<file alias="single_joycon_left_vertical">single_joycon_left_vertical.png</file>
<file alias="single_joycon_left_vertical_dark">single_joycon_left_vertical_dark.png</file>
<file alias="single_joycon_left_vertical_midnight">single_joycon_left_vertical_midnight.png</file>
<file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
<file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
<file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
<file alias="applet_dual_joycon">applet_dual_joycon.png</file>
<file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file>
<file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -1,7 +1,7 @@
[Icon Theme]
Name=colorful_dark
Comment=Colorful theme (Dark style)
Inherits=default
Inherits=colorful
Directories=16x16
[16x16]

View File

@@ -1,7 +1,7 @@
[Icon Theme]
Name=colorful_midnight_blue
Comment=Colorful theme (Midnight Blue style)
Inherits=default
Inherits=colorful
Directories=16x16
[16x16]

View File

@@ -1257,10 +1257,6 @@ QComboBox::item:alternate {
background: #19232D;
}
QComboBox::item:checked {
font-weight: bold;
}
QComboBox::item:selected {
border: 0px solid transparent;
}

BIN
dist/yuzu.bmp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

1
externals/ffmpeg vendored Submodule

Submodule externals/ffmpeg added at 6b6b9e593d

View File

@@ -1,100 +1,187 @@
# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil)
# Once done this will define
# FindFFmpeg
# ----------
#
# FFMPEG_FOUND - system has ffmpeg or libav
# FFMPEG_INCLUDE_DIR - the ffmpeg include directory
# FFMPEG_LIBRARIES - Link these to use ffmpeg
# FFMPEG_LIBAVCODEC
# FFMPEG_LIBAVFORMAT
# FFMPEG_LIBAVUTIL
# Copyright 2019 Citra Emulator Project
# Licensed under GPLv2 or any later version
#
# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org>
# Modified for other libraries by Lasse Kärkkäinen <tronic>
# Modified for Hedgewars by Stepik777
# Modified for FFmpeg-example Tuukka Pasanen 2018
# Modified for yuzu toastUnlimted 2020
# Find the native FFmpeg includes and libraries
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# This module defines the following variables:
#
# FFmpeg_INCLUDE_<component>: where to find <component>.h
# FFmpeg_LIBRARY_<component>: where to find the <component> library
# FFmpeg_INCLUDE_DIR: aggregate all the include paths
# FFmpeg_LIBRARIES: aggregate all the paths to the libraries
# FFmpeg_FOUND: True if all components have been found
#
# This module defines the following targets, which are prefered over variables:
#
# FFmpeg::<component>: Target to use <component> directly, with include path,
# library and dependencies set up. If you are using a static build, you are
# responsible for adding any external dependencies (such as zlib, bzlib...).
#
# <component> can be one of:
# avcodec
# avdevice
# avfilter
# avformat
# avutil
# postproc
# swresample
# swscale
#
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FFMPEG
FOUND_VAR FFMPEG_FOUND
REQUIRED_VARS
FFMPEG_LIBRARY
FFMPEG_INCLUDE_DIR
VERSION_VAR FFMPEG_VERSION
set(_FFmpeg_ALL_COMPONENTS
avcodec
avdevice
avfilter
avformat
avutil
postproc
swresample
swscale
)
if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
# in cache already
set(FFMPEG_FOUND TRUE)
else()
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
pkg_check_modules(_FFMPEG_AVUTIL libavutil)
pkg_check_modules(_FFMPEG_SWSCALE libswscale)
set(_FFmpeg_DEPS_avcodec avutil)
set(_FFmpeg_DEPS_avdevice avcodec avformat avutil)
set(_FFmpeg_DEPS_avfilter avutil)
set(_FFmpeg_DEPS_avformat avcodec avutil)
set(_FFmpeg_DEPS_postproc avutil)
set(_FFmpeg_DEPS_swresample avutil)
set(_FFmpeg_DEPS_swscale avutil)
function(find_ffmpeg LIBNAME)
if(DEFINED ENV{FFMPEG_DIR})
set(FFMPEG_DIR $ENV{FFMPEG_DIR})
endif()
find_path(FFMPEG_AVCODEC_INCLUDE_DIR
NAMES libavcodec/avcodec.h
PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS}
/usr/include
/usr/local/include
/opt/local/include
/sw/include
PATH_SUFFIXES ffmpeg libav)
find_library(FFMPEG_LIBAVCODEC
NAMES avcodec
PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib)
find_library(FFMPEG_LIBAVUTIL
NAMES avutil
PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib)
find_library(FFMPEG_LIBSWSCALE
NAMES swscale
PATHS ${_FFMPEG_SWSCALE_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib)
if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVUTIL AND FFMPEG_LIBSWSCALE)
set(FFMPEG_FOUND TRUE)
endif()
if(FFMPEG_FOUND)
set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR})
set(FFMPEG_LIBRARIES
${FFMPEG_LIBAVCODEC}
${FFMPEG_LIBAVUTIL}
${FFMPEG_LIBSWSCALE})
endif()
if(FFMPEG_FOUND)
if(NOT FFMPEG_FIND_QUIETLY)
message(STATUS
"Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}")
endif()
if(FFMPEG_DIR)
list(APPEND INCLUDE_PATHS
${FFMPEG_DIR}
${FFMPEG_DIR}/ffmpeg
${FFMPEG_DIR}/lib${LIBNAME}
${FFMPEG_DIR}/include/lib${LIBNAME}
${FFMPEG_DIR}/include/ffmpeg
${FFMPEG_DIR}/include
NO_DEFAULT_PATH
NO_CMAKE_FIND_ROOT_PATH
)
list(APPEND LIB_PATHS
${FFMPEG_DIR}
${FFMPEG_DIR}/lib
${FFMPEG_DIR}/lib${LIBNAME}
NO_DEFAULT_PATH
NO_CMAKE_FIND_ROOT_PATH
)
else()
if(FFMPEG_FIND_REQUIRED)
message(FATAL_ERROR
"Could not find libavcodec or libavutil or libswscale")
list(APPEND INCLUDE_PATHS
/usr/local/include/ffmpeg
/usr/local/include/lib${LIBNAME}
/usr/include/ffmpeg
/usr/include/lib${LIBNAME}
/usr/include/ffmpeg/lib${LIBNAME}
)
list(APPEND LIB_PATHS
/usr/local/lib
/usr/lib
)
endif()
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
HINTS ${INCLUDE_PATHS}
)
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
HINTS ${LIB_PATHS}
)
if(NOT FFMPEG_DIR AND (NOT FFmpeg_LIBRARY_${LIBNAME} OR NOT FFmpeg_INCLUDE_${LIBNAME}))
# Didn't find it in the usual paths, try pkg-config
find_package(PkgConfig QUIET)
pkg_check_modules(FFmpeg_PKGCONFIG_${LIBNAME} QUIET lib${LIBNAME})
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
${FFmpeg_PKGCONFIG_${LIBNAME}_INCLUDE_DIRS}
)
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
${FFmpeg_PKGCONFIG_${LIBNAME}_LIBRARY_DIRS}
)
endif()
if(FFmpeg_INCLUDE_${LIBNAME} AND FFmpeg_LIBRARY_${LIBNAME})
set(FFmpeg_INCLUDE_${LIBNAME} "${FFmpeg_INCLUDE_${LIBNAME}}" PARENT_SCOPE)
set(FFmpeg_LIBRARY_${LIBNAME} "${FFmpeg_LIBRARY_${LIBNAME}}" PARENT_SCOPE)
# Extract FFmpeg version from version.h
foreach(v MAJOR MINOR MICRO)
set(FFmpeg_${LIBNAME}_VERSION_${v} 0)
endforeach()
string(TOUPPER ${LIBNAME} LIBNAME_UPPER)
file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version.h" _FFmpeg_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_(MAJOR|MINOR|MICRO) ")
set(_FFmpeg_VERSION_REGEX "([0-9]+)")
foreach(v MAJOR MINOR MICRO)
if("${_FFmpeg_VERSION_H_CONTENTS}" MATCHES "#define LIB${LIBNAME_UPPER}_VERSION_${v}[\\t ]+${_FFmpeg_VERSION_REGEX}")
set(FFmpeg_${LIBNAME}_VERSION_${v} "${CMAKE_MATCH_1}")
endif()
endforeach()
set(FFmpeg_${LIBNAME}_VERSION "${FFmpeg_${LIBNAME}_VERSION_MAJOR}.${FFmpeg_${LIBNAME}_VERSION_MINOR}.${FFmpeg_${LIBNAME}_VERSION_MICRO}")
set(FFmpeg_${c}_VERSION "${FFmpeg_${LIBNAME}_VERSION}" PARENT_SCOPE)
unset(_FFmpeg_VERSION_REGEX)
unset(_FFmpeg_VERSION_H_CONTENTS)
set(FFmpeg_${c}_FOUND TRUE PARENT_SCOPE)
if(NOT FFmpeg_FIND_QUIETLY)
message("-- Found ${LIBNAME}: ${FFmpeg_INCLUDE_${LIBNAME}} ${FFmpeg_LIBRARY_${LIBNAME}} (version: ${FFmpeg_${LIBNAME}_VERSION})")
endif()
endif()
endfunction()
foreach(c ${_FFmpeg_ALL_COMPONENTS})
find_ffmpeg(${c})
endforeach()
foreach(c ${_FFmpeg_ALL_COMPONENTS})
if(FFmpeg_${c}_FOUND)
list(APPEND FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_${c}})
list(APPEND FFmpeg_LIBRARIES ${FFmpeg_LIBRARY_${c}})
add_library(FFmpeg::${c} IMPORTED UNKNOWN)
set_target_properties(FFmpeg::${c} PROPERTIES
IMPORTED_LOCATION ${FFmpeg_LIBRARY_${c}}
INTERFACE_INCLUDE_DIRECTORIES ${FFmpeg_INCLUDE_${c}}
)
if(_FFmpeg_DEPS_${c})
set(deps)
foreach(dep ${_FFmpeg_DEPS_${c}})
list(APPEND deps FFmpeg::${dep})
endforeach()
set_target_properties(FFmpeg::${c} PROPERTIES
INTERFACE_LINK_LIBRARIES "${deps}"
)
unset(deps)
endif()
endif()
endforeach()
if(FFmpeg_INCLUDE_DIR)
list(REMOVE_DUPLICATES FFmpeg_INCLUDE_DIR)
endif()
foreach(c ${FFmpeg_FIND_COMPONENTS})
list(APPEND _FFmpeg_REQUIRED_VARS FFmpeg_INCLUDE_${c} FFmpeg_LIBRARY_${c})
endforeach()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FFmpeg
REQUIRED_VARS ${_FFmpeg_REQUIRED_VARS}
HANDLE_COMPONENTS
)
foreach(c ${_FFmpeg_ALL_COMPONENTS})
unset(_FFmpeg_DEPS_${c})
endforeach()
unset(_FFmpeg_ALL_COMPONENTS)
unset(_FFmpeg_REQUIRED_VARS)

View File

@@ -45,10 +45,15 @@ if (MSVC)
# Warnings
/W3
/we4062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled
/we4101 # 'identifier': unreferenced local variable
/we4265 # 'class': class has virtual functions, but destructor is not virtual
/we4388 # signed/unsigned mismatch
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
/we4555 # Expression has no effect; expected expression with side-effect
/we4834 # Discarding return value of function with 'nodiscard' attribute
/we5038 # data member 'member1' will be initialized after data member 'member2'
)
# /GS- - No stack buffer overflow checks
@@ -59,11 +64,16 @@ if (MSVC)
else()
add_compile_options(
-Wall
-Werror=array-bounds
-Werror=implicit-fallthrough
-Werror=missing-declarations
-Werror=missing-field-initializers
-Werror=reorder
-Werror=switch
-Werror=uninitialized
-Werror=unused-function
-Werror=unused-result
-Werror=unused-variable
-Wextra
-Wmissing-declarations
-Wno-attributes
@@ -122,7 +132,6 @@ add_subdirectory(tests)
if (ENABLE_SDL2)
add_subdirectory(yuzu_cmd)
add_subdirectory(yuzu_tester)
endif()
if (ENABLE_QT)

View File

@@ -15,6 +15,8 @@ add_library(audio_core STATIC
command_generator.cpp
command_generator.h
common.h
delay_line.cpp
delay_line.h
effect_context.cpp
effect_context.h
info_updater.cpp

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cmath>
#include <numbers>
#include "audio_core/algorithm/interpolate.h"
#include "audio_core/command_generator.h"
#include "audio_core/effect_context.h"
@@ -13,6 +15,20 @@ namespace AudioCore {
namespace {
constexpr std::size_t MIX_BUFFER_SIZE = 0x3f00;
constexpr std::size_t SCALED_MIX_BUFFER_SIZE = MIX_BUFFER_SIZE << 15ULL;
using DelayLineTimes = std::array<f32, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT>;
constexpr DelayLineTimes FDN_MIN_DELAY_LINE_TIMES{5.0f, 6.0f, 13.0f, 14.0f};
constexpr DelayLineTimes FDN_MAX_DELAY_LINE_TIMES{45.704f, 82.782f, 149.94f, 271.58f};
constexpr DelayLineTimes DECAY0_MAX_DELAY_LINE_TIMES{17.0f, 13.0f, 9.0f, 7.0f};
constexpr DelayLineTimes DECAY1_MAX_DELAY_LINE_TIMES{19.0f, 11.0f, 10.0f, 6.0f};
constexpr std::array<f32, AudioCommon::I3DL2REVERB_TAPS> EARLY_TAP_TIMES{
0.017136f, 0.059154f, 0.161733f, 0.390186f, 0.425262f, 0.455411f, 0.689737f,
0.745910f, 0.833844f, 0.859502f, 0.000000f, 0.075024f, 0.168788f, 0.299901f,
0.337443f, 0.371903f, 0.599011f, 0.716741f, 0.817859f, 0.851664f};
constexpr std::array<f32, AudioCommon::I3DL2REVERB_TAPS> EARLY_GAIN{
0.67096f, 0.61027f, 1.0f, 0.35680f, 0.68361f, 0.65978f, 0.51939f,
0.24712f, 0.45945f, 0.45021f, 0.64196f, 0.54879f, 0.92925f, 0.38270f,
0.72867f, 0.69794f, 0.5464f, 0.24563f, 0.45214f, 0.44042f};
template <std::size_t N>
void ApplyMix(s32* output, const s32* input, s32 gain, s32 sample_count) {
@@ -65,6 +81,154 @@ s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) {
}
}
float Pow10(float x) {
if (x >= 0.0f) {
return 1.0f;
} else if (x <= -5.3f) {
return 0.0f;
}
return std::pow(10.0f, x);
}
float SinD(float degrees) {
return std::sin(degrees * std::numbers::pi_v<float> / 180.0f);
}
float CosD(float degrees) {
return std::cos(degrees * std::numbers::pi_v<float> / 180.0f);
}
float ToFloat(s32 sample) {
return static_cast<float>(sample) / 65536.f;
}
s32 ToS32(float sample) {
constexpr auto min = -8388608.0f;
constexpr auto max = 8388607.f;
float rescaled_sample = sample * 65536.0f;
if (rescaled_sample < min) {
rescaled_sample = min;
}
if (rescaled_sample > max) {
rescaled_sample = max;
}
return static_cast<s32>(rescaled_sample);
}
constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_1CH{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_2CH{0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
1, 1, 1, 0, 0, 0, 0, 1, 1, 1};
constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_4CH{0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_6CH{4, 0, 0, 1, 1, 1, 1, 2, 2, 2,
1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
template <std::size_t CHANNEL_COUNT>
void ApplyReverbGeneric(I3dl2ReverbState& state,
const std::array<const s32*, AudioCommon::MAX_CHANNEL_COUNT>& input,
const std::array<s32*, AudioCommon::MAX_CHANNEL_COUNT>& output,
s32 sample_count) {
auto GetTapLookup = []() {
if constexpr (CHANNEL_COUNT == 1) {
return REVERB_TAP_INDEX_1CH;
} else if constexpr (CHANNEL_COUNT == 2) {
return REVERB_TAP_INDEX_2CH;
} else if constexpr (CHANNEL_COUNT == 4) {
return REVERB_TAP_INDEX_4CH;
} else if constexpr (CHANNEL_COUNT == 6) {
return REVERB_TAP_INDEX_6CH;
}
};
const auto& tap_index_lut = GetTapLookup();
for (s32 sample = 0; sample < sample_count; sample++) {
std::array<f32, CHANNEL_COUNT> out_samples{};
std::array<f32, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> fsamp{};
std::array<f32, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> mixed{};
std::array<f32, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> osamp{};
// Mix everything into a single sample
s32 temp_mixed_sample = 0;
for (std::size_t i = 0; i < CHANNEL_COUNT; i++) {
temp_mixed_sample += input[i][sample];
}
const auto current_sample = ToFloat(temp_mixed_sample);
const auto early_tap = state.early_delay_line.TapOut(state.early_to_late_taps);
for (std::size_t i = 0; i < AudioCommon::I3DL2REVERB_TAPS; i++) {
const auto tapped_samp =
state.early_delay_line.TapOut(state.early_tap_steps[i]) * EARLY_GAIN[i];
out_samples[tap_index_lut[i]] += tapped_samp;
if constexpr (CHANNEL_COUNT == 6) {
// handle lfe
out_samples[5] += tapped_samp;
}
}
state.lowpass_0 = current_sample * state.lowpass_2 + state.lowpass_0 * state.lowpass_1;
state.early_delay_line.Tick(state.lowpass_0);
for (std::size_t i = 0; i < CHANNEL_COUNT; i++) {
out_samples[i] *= state.early_gain;
}
// Two channel seems to apply a latet gain, we require to save this
f32 filter{};
for (std::size_t i = 0; i < AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT; i++) {
filter = state.fdn_delay_line[i].GetOutputSample();
const auto computed = filter * state.lpf_coefficients[0][i] + state.shelf_filter[i];
state.shelf_filter[i] =
filter * state.lpf_coefficients[1][i] + computed * state.lpf_coefficients[2][i];
fsamp[i] = computed;
}
// Mixing matrix
mixed[0] = fsamp[1] + fsamp[2];
mixed[1] = -fsamp[0] - fsamp[3];
mixed[2] = fsamp[0] - fsamp[3];
mixed[3] = fsamp[1] - fsamp[2];
if constexpr (CHANNEL_COUNT == 2) {
for (auto& mix : mixed) {
mix *= (filter * state.late_gain);
}
}
for (std::size_t i = 0; i < AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT; i++) {
const auto late = early_tap * state.late_gain;
osamp[i] = state.decay_delay_line0[i].Tick(late + mixed[i]);
osamp[i] = state.decay_delay_line1[i].Tick(osamp[i]);
state.fdn_delay_line[i].Tick(osamp[i]);
}
if constexpr (CHANNEL_COUNT == 1) {
output[0][sample] = ToS32(state.dry_gain * ToFloat(input[0][sample]) +
(out_samples[0] + osamp[0] + osamp[1]));
} else if constexpr (CHANNEL_COUNT == 2 || CHANNEL_COUNT == 4) {
for (std::size_t i = 0; i < CHANNEL_COUNT; i++) {
output[i][sample] =
ToS32(state.dry_gain * ToFloat(input[i][sample]) + (out_samples[i] + osamp[i]));
}
} else if constexpr (CHANNEL_COUNT == 6) {
const auto temp_center = state.center_delay_line.Tick(0.5f * (osamp[2] - osamp[3]));
for (std::size_t i = 0; i < 4; i++) {
output[i][sample] =
ToS32(state.dry_gain * ToFloat(input[i][sample]) + (out_samples[i] + osamp[i]));
}
output[4][sample] =
ToS32(state.dry_gain * ToFloat(input[4][sample]) + (out_samples[4] + temp_center));
output[5][sample] =
ToS32(state.dry_gain * ToFloat(input[5][sample]) + (out_samples[5] + osamp[3]));
}
}
}
} // namespace
CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params_,
@@ -271,11 +435,10 @@ void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voic
}
// Generate biquad filter
// GenerateBiquadFilterCommand(mix_buffer_count, biquad_filter,
// dsp_state.biquad_filter_state,
// mix_buffer_count + channel, mix_buffer_count +
// channel, worker_params.sample_count,
// voice_info.GetInParams().node_id);
// GenerateBiquadFilterCommand(mix_buffer_count, biquad_filter,
// dsp_state.biquad_filter_state,
// mix_buffer_count + channel, mix_buffer_count + channel,
// worker_params.sample_count, voice_info.GetInParams().node_id);
}
}
@@ -376,17 +539,53 @@ void CommandGenerator::GenerateEffectCommand(ServerMixInfo& mix_info) {
void CommandGenerator::GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info,
bool enabled) {
if (!enabled) {
auto* reverb = dynamic_cast<EffectI3dl2Reverb*>(info);
const auto& params = reverb->GetParams();
auto& state = reverb->GetState();
const auto channel_count = params.channel_count;
if (channel_count != 1 && channel_count != 2 && channel_count != 4 && channel_count != 6) {
return;
}
const auto& params = dynamic_cast<EffectI3dl2Reverb*>(info)->GetParams();
const auto channel_count = params.channel_count;
std::array<const s32*, AudioCommon::MAX_CHANNEL_COUNT> input{};
std::array<s32*, AudioCommon::MAX_CHANNEL_COUNT> output{};
const auto status = params.status;
for (s32 i = 0; i < channel_count; i++) {
// TODO(ogniK): Actually implement reverb
if (params.input[i] != params.output[i]) {
const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]);
auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
ApplyMix<1>(output, input, 32768, worker_params.sample_count);
input[i] = GetMixBuffer(mix_buffer_offset + params.input[i]);
output[i] = GetMixBuffer(mix_buffer_offset + params.output[i]);
}
if (enabled) {
if (status == ParameterStatus::Initialized) {
InitializeI3dl2Reverb(reverb->GetParams(), state, info->GetWorkBuffer());
} else if (status == ParameterStatus::Updating) {
UpdateI3dl2Reverb(reverb->GetParams(), state, false);
}
}
if (enabled) {
switch (channel_count) {
case 1:
ApplyReverbGeneric<1>(state, input, output, worker_params.sample_count);
break;
case 2:
ApplyReverbGeneric<2>(state, input, output, worker_params.sample_count);
break;
case 4:
ApplyReverbGeneric<4>(state, input, output, worker_params.sample_count);
break;
case 6:
ApplyReverbGeneric<6>(state, input, output, worker_params.sample_count);
break;
}
} else {
for (s32 i = 0; i < channel_count; i++) {
// Only copy if the buffer input and output do not match!
if ((mix_buffer_offset + params.input[i]) != (mix_buffer_offset + params.output[i])) {
std::memcpy(output[i], input[i], worker_params.sample_count * sizeof(s32));
}
}
}
}
@@ -525,6 +724,133 @@ s32 CommandGenerator::ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u3
return sample_count;
}
void CommandGenerator::InitializeI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state,
std::vector<u8>& work_buffer) {
// Reset state
state.lowpass_0 = 0.0f;
state.lowpass_1 = 0.0f;
state.lowpass_2 = 0.0f;
state.early_delay_line.Reset();
state.early_tap_steps.fill(0);
state.early_gain = 0.0f;
state.late_gain = 0.0f;
state.early_to_late_taps = 0;
for (std::size_t i = 0; i < AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT; i++) {
state.fdn_delay_line[i].Reset();
state.decay_delay_line0[i].Reset();
state.decay_delay_line1[i].Reset();
}
state.last_reverb_echo = 0.0f;
state.center_delay_line.Reset();
for (auto& coef : state.lpf_coefficients) {
coef.fill(0.0f);
}
state.shelf_filter.fill(0.0f);
state.dry_gain = 0.0f;
const auto sample_rate = info.sample_rate / 1000;
f32* work_buffer_ptr = reinterpret_cast<f32*>(work_buffer.data());
s32 delay_samples{};
for (std::size_t i = 0; i < AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT; i++) {
delay_samples =
AudioCommon::CalculateDelaySamples(sample_rate, FDN_MAX_DELAY_LINE_TIMES[i]);
state.fdn_delay_line[i].Initialize(delay_samples, work_buffer_ptr);
work_buffer_ptr += delay_samples + 1;
delay_samples =
AudioCommon::CalculateDelaySamples(sample_rate, DECAY0_MAX_DELAY_LINE_TIMES[i]);
state.decay_delay_line0[i].Initialize(delay_samples, 0.0f, work_buffer_ptr);
work_buffer_ptr += delay_samples + 1;
delay_samples =
AudioCommon::CalculateDelaySamples(sample_rate, DECAY1_MAX_DELAY_LINE_TIMES[i]);
state.decay_delay_line1[i].Initialize(delay_samples, 0.0f, work_buffer_ptr);
work_buffer_ptr += delay_samples + 1;
}
delay_samples = AudioCommon::CalculateDelaySamples(sample_rate, 5.0f);
state.center_delay_line.Initialize(delay_samples, work_buffer_ptr);
work_buffer_ptr += delay_samples + 1;
delay_samples = AudioCommon::CalculateDelaySamples(sample_rate, 400.0f);
state.early_delay_line.Initialize(delay_samples, work_buffer_ptr);
UpdateI3dl2Reverb(info, state, true);
}
void CommandGenerator::UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state,
bool should_clear) {
state.dry_gain = info.dry_gain;
state.shelf_filter.fill(0.0f);
state.lowpass_0 = 0.0f;
state.early_gain = Pow10(std::min(info.room + info.reflection, 5000.0f) / 2000.0f);
state.late_gain = Pow10(std::min(info.room + info.reverb, 5000.0f) / 2000.0f);
const auto sample_rate = info.sample_rate / 1000;
const f32 hf_gain = Pow10(info.room_hf / 2000.0f);
if (hf_gain >= 1.0f) {
state.lowpass_2 = 1.0f;
state.lowpass_1 = 0.0f;
} else {
const auto a = 1.0f - hf_gain;
const auto b = 2.0f * (1.0f - hf_gain * CosD(256.0f * info.hf_reference /
static_cast<f32>(info.sample_rate)));
const auto c = std::sqrt(b * b - 4.0f * a * a);
state.lowpass_1 = (b - c) / (2.0f * a);
state.lowpass_2 = 1.0f - state.lowpass_1;
}
state.early_to_late_taps = AudioCommon::CalculateDelaySamples(
sample_rate, 1000.0f * (info.reflection_delay + info.reverb_delay));
state.last_reverb_echo = 0.6f * info.diffusion * 0.01f;
for (std::size_t i = 0; i < AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT; i++) {
const auto length =
FDN_MIN_DELAY_LINE_TIMES[i] +
(info.density / 100.0f) * (FDN_MAX_DELAY_LINE_TIMES[i] - FDN_MIN_DELAY_LINE_TIMES[i]);
state.fdn_delay_line[i].SetDelay(AudioCommon::CalculateDelaySamples(sample_rate, length));
const auto delay_sample_counts = state.fdn_delay_line[i].GetDelay() +
state.decay_delay_line0[i].GetDelay() +
state.decay_delay_line1[i].GetDelay();
float a = (-60.0f * static_cast<f32>(delay_sample_counts)) /
(info.decay_time * static_cast<f32>(info.sample_rate));
float b = a / info.hf_decay_ratio;
float c = CosD(128.0f * 0.5f * info.hf_reference / static_cast<f32>(info.sample_rate)) /
SinD(128.0f * 0.5f * info.hf_reference / static_cast<f32>(info.sample_rate));
float d = Pow10((b - a) / 40.0f);
float e = Pow10((b + a) / 40.0f) * 0.7071f;
state.lpf_coefficients[0][i] = e * ((d * c) + 1.0f) / (c + d);
state.lpf_coefficients[1][i] = e * (1.0f - (d * c)) / (c + d);
state.lpf_coefficients[2][i] = (c - d) / (c + d);
state.decay_delay_line0[i].SetCoefficient(state.last_reverb_echo);
state.decay_delay_line1[i].SetCoefficient(-0.9f * state.last_reverb_echo);
}
if (should_clear) {
for (std::size_t i = 0; i < AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT; i++) {
state.fdn_delay_line[i].Clear();
state.decay_delay_line0[i].Clear();
state.decay_delay_line1[i].Clear();
}
state.early_delay_line.Clear();
state.center_delay_line.Clear();
}
const auto max_early_delay = state.early_delay_line.GetMaxDelay();
const auto reflection_time = 1000.0f * (0.0098f * info.reverb_delay + 0.02f);
for (std::size_t tap = 0; tap < AudioCommon::I3DL2REVERB_TAPS; tap++) {
const auto length = AudioCommon::CalculateDelaySamples(
sample_rate, 1000.0f * info.reflection_delay + reflection_time * EARLY_TAP_TIMES[tap]);
state.early_tap_steps[tap] = std::min(length, max_early_delay);
}
}
void CommandGenerator::GenerateVolumeRampCommand(float last_volume, float current_volume,
s32 channel, s32 node_id) {
const auto last = static_cast<s32>(last_volume * 32768.0f);

View File

@@ -21,6 +21,8 @@ class ServerMixInfo;
class EffectContext;
class EffectBase;
struct AuxInfoDSP;
struct I3dl2ReverbParams;
struct I3dl2ReverbState;
using MixVolumeBuffer = std::array<float, AudioCommon::MAX_MIX_BUFFERS>;
class CommandGenerator {
@@ -80,6 +82,9 @@ private:
s32 ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples, s32* out_data,
u32 sample_count, u32 read_offset, u32 read_count);
void InitializeI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state,
std::vector<u8>& work_buffer);
void UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, bool should_clear);
// DSP Code
s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count,
s32 channel, std::size_t mix_offset);

View File

@@ -33,6 +33,29 @@ constexpr std::size_t TEMP_MIX_BASE_SIZE = 0x3f00; // TODO(ogniK): Work out this
// and our const ends up being 0x3f04, the 4 bytes are most
// likely the sample history
constexpr std::size_t TOTAL_TEMP_MIX_SIZE = TEMP_MIX_BASE_SIZE + AudioCommon::MAX_SAMPLE_HISTORY;
constexpr f32 I3DL2REVERB_MAX_LEVEL = 5000.0f;
constexpr f32 I3DL2REVERB_MIN_REFLECTION_DURATION = 0.02f;
constexpr std::size_t I3DL2REVERB_TAPS = 20;
constexpr std::size_t I3DL2REVERB_DELAY_LINE_COUNT = 4;
using Fractional = s32;
template <typename T>
constexpr Fractional ToFractional(T x) {
return static_cast<Fractional>(x * static_cast<T>(0x4000));
}
constexpr Fractional MultiplyFractional(Fractional lhs, Fractional rhs) {
return static_cast<Fractional>(static_cast<s64>(lhs) * rhs >> 14);
}
constexpr s32 FractionalToFixed(Fractional x) {
const auto s = x & (1 << 13);
return static_cast<s32>(x >> 14) + s;
}
constexpr s32 CalculateDelaySamples(s32 sample_rate_khz, float time) {
return FractionalToFixed(MultiplyFractional(ToFractional(sample_rate_khz), ToFractional(time)));
}
static constexpr u32 VersionFromRevision(u32_le rev) {
// "REV7" -> 7

View File

@@ -0,0 +1,104 @@
#include <cstring>
#include "audio_core/delay_line.h"
namespace AudioCore {
DelayLineBase::DelayLineBase() = default;
DelayLineBase::~DelayLineBase() = default;
void DelayLineBase::Initialize(s32 max_delay_, float* src_buffer) {
buffer = src_buffer;
buffer_end = buffer + max_delay_;
max_delay = max_delay_;
output = buffer;
SetDelay(max_delay_);
Clear();
}
void DelayLineBase::SetDelay(s32 new_delay) {
if (max_delay < new_delay) {
return;
}
delay = new_delay;
input = (buffer + ((output - buffer) + new_delay) % (max_delay + 1));
}
s32 DelayLineBase::GetDelay() const {
return delay;
}
s32 DelayLineBase::GetMaxDelay() const {
return max_delay;
}
f32 DelayLineBase::TapOut(s32 last_sample) {
const float* ptr = input - (last_sample + 1);
if (ptr < buffer) {
ptr += (max_delay + 1);
}
return *ptr;
}
f32 DelayLineBase::Tick(f32 sample) {
*(input++) = sample;
const auto out_sample = *(output++);
if (buffer_end < input) {
input = buffer;
}
if (buffer_end < output) {
output = buffer;
}
return out_sample;
}
float* DelayLineBase::GetInput() {
return input;
}
const float* DelayLineBase::GetInput() const {
return input;
}
f32 DelayLineBase::GetOutputSample() const {
return *output;
}
void DelayLineBase::Clear() {
std::memset(buffer, 0, sizeof(float) * max_delay);
}
void DelayLineBase::Reset() {
buffer = nullptr;
buffer_end = nullptr;
max_delay = 0;
input = nullptr;
output = nullptr;
delay = 0;
}
DelayLineAllPass::DelayLineAllPass() = default;
DelayLineAllPass::~DelayLineAllPass() = default;
void DelayLineAllPass::Initialize(u32 delay_, float coeffcient_, f32* src_buffer) {
DelayLineBase::Initialize(delay_, src_buffer);
SetCoefficient(coeffcient_);
}
void DelayLineAllPass::SetCoefficient(float coeffcient_) {
coefficient = coeffcient_;
}
f32 DelayLineAllPass::Tick(f32 sample) {
const auto temp = sample - coefficient * *output;
return coefficient * temp + DelayLineBase::Tick(temp);
}
void DelayLineAllPass::Reset() {
coefficient = 0.0f;
DelayLineBase::Reset();
}
} // namespace AudioCore

View File

@@ -0,0 +1,46 @@
#pragma once
#include "common/common_types.h"
namespace AudioCore {
class DelayLineBase {
public:
DelayLineBase();
~DelayLineBase();
void Initialize(s32 max_delay_, float* src_buffer);
void SetDelay(s32 new_delay);
s32 GetDelay() const;
s32 GetMaxDelay() const;
f32 TapOut(s32 last_sample);
f32 Tick(f32 sample);
float* GetInput();
const float* GetInput() const;
f32 GetOutputSample() const;
void Clear();
void Reset();
protected:
float* buffer{nullptr};
float* buffer_end{nullptr};
s32 max_delay{};
float* input{nullptr};
float* output{nullptr};
s32 delay{};
};
class DelayLineAllPass final : public DelayLineBase {
public:
DelayLineAllPass();
~DelayLineAllPass();
void Initialize(u32 delay, float coeffcient_, f32* src_buffer);
void SetCoefficient(float coeffcient_);
f32 Tick(f32 sample);
void Reset();
private:
float coefficient{};
};
} // namespace AudioCore

View File

@@ -90,6 +90,14 @@ s32 EffectBase::GetProcessingOrder() const {
return processing_order;
}
std::vector<u8>& EffectBase::GetWorkBuffer() {
return work_buffer;
}
const std::vector<u8>& EffectBase::GetWorkBuffer() const {
return work_buffer;
}
EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric(EffectType::I3dl2Reverb) {}
EffectI3dl2Reverb::~EffectI3dl2Reverb() = default;
@@ -117,6 +125,12 @@ void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) {
usage = UsageState::Initialized;
params.status = ParameterStatus::Initialized;
skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
if (!skipped) {
auto& cur_work_buffer = GetWorkBuffer();
// Has two buffers internally
cur_work_buffer.resize(in_params.buffer_size * 2);
std::fill(cur_work_buffer.begin(), cur_work_buffer.end(), 0);
}
}
}
@@ -129,6 +143,14 @@ void EffectI3dl2Reverb::UpdateForCommandGeneration() {
GetParams().status = ParameterStatus::Updated;
}
I3dl2ReverbState& EffectI3dl2Reverb::GetState() {
return state;
}
const I3dl2ReverbState& EffectI3dl2Reverb::GetState() const {
return state;
}
EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric(EffectType::BiquadFilter) {}
EffectBiquadFilter::~EffectBiquadFilter() = default;

View File

@@ -8,6 +8,7 @@
#include <memory>
#include <vector>
#include "audio_core/common.h"
#include "audio_core/delay_line.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
@@ -194,6 +195,8 @@ public:
[[nodiscard]] bool IsEnabled() const;
[[nodiscard]] s32 GetMixID() const;
[[nodiscard]] s32 GetProcessingOrder() const;
[[nodiscard]] std::vector<u8>& GetWorkBuffer();
[[nodiscard]] const std::vector<u8>& GetWorkBuffer() const;
protected:
UsageState usage{UsageState::Invalid};
@@ -201,6 +204,7 @@ protected:
s32 mix_id{};
s32 processing_order{};
bool enabled = false;
std::vector<u8> work_buffer{};
};
template <typename T>
@@ -212,7 +216,7 @@ public:
return internal_params;
}
const I3dl2ReverbParams& GetParams() const {
const T& GetParams() const {
return internal_params;
}
@@ -229,6 +233,27 @@ public:
void UpdateForCommandGeneration() override;
};
struct I3dl2ReverbState {
f32 lowpass_0{};
f32 lowpass_1{};
f32 lowpass_2{};
DelayLineBase early_delay_line{};
std::array<u32, AudioCommon::I3DL2REVERB_TAPS> early_tap_steps{};
f32 early_gain{};
f32 late_gain{};
u32 early_to_late_taps{};
std::array<DelayLineBase, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> fdn_delay_line{};
std::array<DelayLineAllPass, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> decay_delay_line0{};
std::array<DelayLineAllPass, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> decay_delay_line1{};
f32 last_reverb_echo{};
DelayLineBase center_delay_line{};
std::array<std::array<f32, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT>, 3> lpf_coefficients{};
std::array<f32, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> shelf_filter{};
f32 dry_gain{};
};
class EffectI3dl2Reverb : public EffectGeneric<I3dl2ReverbParams> {
public:
explicit EffectI3dl2Reverb();
@@ -237,8 +262,12 @@ public:
void Update(EffectInfo::InParams& in_params) override;
void UpdateForCommandGeneration() override;
I3dl2ReverbState& GetState();
const I3dl2ReverbState& GetState() const;
private:
bool skipped = false;
I3dl2ReverbState state{};
};
class EffectBiquadFilter : public EffectGeneric<BiquadFilterParams> {

View File

@@ -40,17 +40,17 @@ public:
SinkSampleFormat sample_format;
std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input;
bool in_use;
INSERT_UNION_PADDING_BYTES(5);
INSERT_PADDING_BYTES_NOINIT(5);
};
static_assert(sizeof(CircularBufferIn) == 0x28,
"SinkInfo::CircularBufferIn is in invalid size");
struct DeviceIn {
std::array<u8, 255> device_name;
INSERT_UNION_PADDING_BYTES(1);
INSERT_PADDING_BYTES_NOINIT(1);
s32_le input_count;
std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input;
INSERT_UNION_PADDING_BYTES(1);
INSERT_PADDING_BYTES_NOINIT(1);
bool down_matrix_enabled;
DownmixCoefficients down_matrix_coef;
};

View File

@@ -51,6 +51,14 @@ void Stream::Stop() {
UNIMPLEMENTED();
}
bool Stream::Flush() {
const bool had_buffers = !queued_buffers.empty();
while (!queued_buffers.empty()) {
queued_buffers.pop();
}
return had_buffers;
}
void Stream::SetVolume(float volume) {
game_volume = volume;
}
@@ -103,7 +111,14 @@ void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) {
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
core_timing.ScheduleEvent(GetBufferReleaseNS(*active_buffer) - ns_late, release_event, {});
const auto buffer_release_ns = GetBufferReleaseNS(*active_buffer);
// If ns_late is higher than the update rate ignore the delay
if (ns_late > buffer_release_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(buffer_release_ns - ns_late, release_event, {});
}
void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) {

View File

@@ -56,6 +56,9 @@ public:
/// Queues a buffer into the audio stream, returns true on success
bool QueueBuffer(BufferPtr&& buffer);
/// Flush audio buffers
bool Flush();
/// Returns true if the audio stream contains a buffer with the specified tag
[[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const;

View File

@@ -86,28 +86,28 @@ struct BehaviorFlags {
static_assert(sizeof(BehaviorFlags) == 0x4, "BehaviorFlags is an invalid size");
struct ADPCMContext {
u16 header{};
s16 yn1{};
s16 yn2{};
u16 header;
s16 yn1;
s16 yn2;
};
static_assert(sizeof(ADPCMContext) == 0x6, "ADPCMContext is an invalid size");
struct VoiceState {
s64 played_sample_count{};
s32 offset{};
s32 wave_buffer_index{};
std::array<bool, AudioCommon::MAX_WAVE_BUFFERS> is_wave_buffer_valid{};
s32 wave_buffer_consumed{};
std::array<s32, AudioCommon::MAX_SAMPLE_HISTORY> sample_history{};
s32 fraction{};
VAddr context_address{};
Codec::ADPCM_Coeff coeff{};
ADPCMContext context{};
std::array<s64, 2> biquad_filter_state{};
std::array<s32, AudioCommon::MAX_MIX_BUFFERS> previous_samples{};
u32 external_context_size{};
bool is_external_context_used{};
bool voice_dropped{};
s64 played_sample_count;
s32 offset;
s32 wave_buffer_index;
std::array<bool, AudioCommon::MAX_WAVE_BUFFERS> is_wave_buffer_valid;
s32 wave_buffer_consumed;
std::array<s32, AudioCommon::MAX_SAMPLE_HISTORY> sample_history;
s32 fraction;
VAddr context_address;
Codec::ADPCM_Coeff coeff;
ADPCMContext context;
std::array<s64, 2> biquad_filter_state;
std::array<s32, AudioCommon::MAX_MIX_BUFFERS> previous_samples;
u32 external_context_size;
bool is_external_context_used;
bool voice_dropped;
};
class VoiceChannelResource {

View File

@@ -98,7 +98,6 @@ add_library(common STATIC
algorithm.h
alignment.h
assert.h
atomic_ops.cpp
atomic_ops.h
detached_tasks.cpp
detached_tasks.h
@@ -108,7 +107,6 @@ add_library(common STATIC
bit_util.h
cityhash.cpp
cityhash.h
color.h
common_funcs.h
common_paths.h
common_types.h
@@ -123,6 +121,7 @@ add_library(common STATIC
hash.h
hex_util.cpp
hex_util.h
intrusive_red_black_tree.h
logging/backend.cpp
logging/backend.h
logging/filter.cpp
@@ -139,10 +138,13 @@ add_library(common STATIC
microprofile.h
microprofileui.h
misc.cpp
nvidia_flags.cpp
nvidia_flags.h
page_table.cpp
page_table.h
param_package.cpp
param_package.h
parent_of_member.h
quaternion.h
ring_buffer.h
scm_rev.cpp
@@ -165,9 +167,8 @@ add_library(common STATIC
threadsafe_queue.h
time_zone.cpp
time_zone.h
timer.cpp
timer.h
uint128.cpp
tiny_mt.h
tree.h
uint128.h
uuid.cpp
uuid.h
@@ -205,6 +206,8 @@ if (MSVC)
else()
target_compile_options(common PRIVATE
-Werror
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
)
endif()

View File

@@ -9,50 +9,50 @@
namespace Common {
template <typename T>
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUp(T value, size_t size) {
auto mod{static_cast<T>(value % size)};
value -= mod;
return static_cast<T>(mod == T{0} ? value : value + size);
}
template <typename T>
[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
}
template <typename T>
requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignDown(T value, size_t size) {
return static_cast<T>(value - value % size);
}
template <typename T>
[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
}
template <typename T>
[[nodiscard]] constexpr bool Is4KBAligned(T value) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool Is4KBAligned(T value) {
return (value & 0xFFF) == 0;
}
template <typename T>
[[nodiscard]] constexpr bool IsWordAligned(T value) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool IsWordAligned(T value) {
return (value & 0b11) == 0;
}
template <typename T>
[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
using U = typename std::make_unsigned<T>::type;
requires std::is_integral_v<T>[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
using U = typename std::make_unsigned_t<T>;
const U mask = static_cast<U>(alignment - 1);
return (value & mask) == 0;
}
template <typename T, std::size_t Align = 16>
template <typename T, typename U>
requires std::is_integral_v<T>[[nodiscard]] constexpr T DivideUp(T x, U y) {
return (x + (y - 1)) / y;
}
template <typename T, size_t Align = 16>
class AlignmentAllocator {
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using size_type = size_t;
using difference_type = ptrdiff_t;
using propagate_on_container_copy_assignment = std::true_type;
using propagate_on_container_move_assignment = std::true_type;

View File

@@ -1,75 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include "common/atomic_ops.h"
#if _MSC_VER
#include <intrin.h>
#endif
namespace Common {
#if _MSC_VER
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
const u8 result =
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
return result == expected;
}
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
const u16 result =
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
return result == expected;
}
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
const u32 result =
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
return result == expected;
}
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
value, expected);
return result == expected;
}
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
value[0],
reinterpret_cast<__int64*>(expected.data())) != 0;
}
#else
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
return __sync_bool_compare_and_swap(pointer, expected, value);
}
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
return __sync_bool_compare_and_swap(pointer, expected, value);
}
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
return __sync_bool_compare_and_swap(pointer, expected, value);
}
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
return __sync_bool_compare_and_swap(pointer, expected, value);
}
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
unsigned __int128 value_a;
unsigned __int128 expected_a;
std::memcpy(&value_a, value.data(), sizeof(u128));
std::memcpy(&expected_a, expected.data(), sizeof(u128));
return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
}
#endif
} // namespace Common

View File

@@ -4,14 +4,75 @@
#pragma once
#include <cstring>
#include <memory>
#include "common/common_types.h"
#if _MSC_VER
#include <intrin.h>
#endif
namespace Common {
[[nodiscard]] bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
[[nodiscard]] bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
[[nodiscard]] bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected);
#if _MSC_VER
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
const u8 result =
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
return result == expected;
}
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
const u16 result =
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
return result == expected;
}
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
const u32 result =
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
return result == expected;
}
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
value, expected);
return result == expected;
}
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
value[0],
reinterpret_cast<__int64*>(expected.data())) != 0;
}
#else
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
return __sync_bool_compare_and_swap(pointer, expected, value);
}
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
return __sync_bool_compare_and_swap(pointer, expected, value);
}
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
return __sync_bool_compare_and_swap(pointer, expected, value);
}
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
return __sync_bool_compare_and_swap(pointer, expected, value);
}
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
unsigned __int128 value_a;
unsigned __int128 expected_a;
std::memcpy(&value_a, value.data(), sizeof(u128));
std::memcpy(&expected_a, expected.data(), sizeof(u128));
return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
}
#endif
} // namespace Common

View File

@@ -4,13 +4,10 @@
#pragma once
#include <bit>
#include <climits>
#include <cstddef>
#ifdef _MSC_VER
#include <intrin.h>
#endif
#include "common/common_types.h"
namespace Common {
@@ -21,124 +18,30 @@ template <typename T>
return sizeof(T) * CHAR_BIT;
}
#ifdef _MSC_VER
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
unsigned long leading_zero = 0;
if (_BitScanReverse(&leading_zero, value) != 0) {
return 31 - leading_zero;
}
return 32;
[[nodiscard]] constexpr u32 MostSignificantBit32(const u32 value) {
return 31U - static_cast<u32>(std::countl_zero(value));
}
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
unsigned long leading_zero = 0;
if (_BitScanReverse64(&leading_zero, value) != 0) {
return 63 - leading_zero;
}
return 64;
}
#else
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
if (value == 0) {
return 32;
}
return static_cast<u32>(__builtin_clz(value));
[[nodiscard]] constexpr u32 MostSignificantBit64(const u64 value) {
return 63U - static_cast<u32>(std::countl_zero(value));
}
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
if (value == 0) {
return 64;
}
return static_cast<u32>(__builtin_clzll(value));
}
#endif
#ifdef _MSC_VER
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
unsigned long trailing_zero = 0;
if (_BitScanForward(&trailing_zero, value) != 0) {
return trailing_zero;
}
return 32;
}
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
unsigned long trailing_zero = 0;
if (_BitScanForward64(&trailing_zero, value) != 0) {
return trailing_zero;
}
return 64;
}
#else
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
if (value == 0) {
return 32;
}
return static_cast<u32>(__builtin_ctz(value));
}
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
if (value == 0) {
return 64;
}
return static_cast<u32>(__builtin_ctzll(value));
}
#endif
#ifdef _MSC_VER
[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
unsigned long result;
_BitScanReverse(&result, value);
return static_cast<u32>(result);
}
[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
unsigned long result;
_BitScanReverse64(&result, value);
return static_cast<u32>(result);
}
#else
[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
return 31U - static_cast<u32>(__builtin_clz(value));
}
[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
return 63U - static_cast<u32>(__builtin_clzll(value));
}
#endif
[[nodiscard]] inline u32 Log2Floor32(const u32 value) {
[[nodiscard]] constexpr u32 Log2Floor32(const u32 value) {
return MostSignificantBit32(value);
}
[[nodiscard]] inline u32 Log2Ceil32(const u32 value) {
const u32 log2_f = Log2Floor32(value);
return log2_f + ((value ^ (1U << log2_f)) != 0U);
}
[[nodiscard]] inline u32 Log2Floor64(const u64 value) {
[[nodiscard]] constexpr u32 Log2Floor64(const u64 value) {
return MostSignificantBit64(value);
}
[[nodiscard]] inline u32 Log2Ceil64(const u64 value) {
const u64 log2_f = static_cast<u64>(Log2Floor64(value));
return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL));
[[nodiscard]] constexpr u32 Log2Ceil32(const u32 value) {
const u32 log2_f = Log2Floor32(value);
return log2_f + static_cast<u32>((value ^ (1U << log2_f)) != 0U);
}
[[nodiscard]] constexpr u32 Log2Ceil64(const u64 value) {
const u64 log2_f = Log2Floor64(value);
return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL));
}
} // namespace Common

View File

@@ -28,8 +28,10 @@
// compromising on hash quality.
#include <algorithm>
#include <string.h> // for memcpy and memset
#include "cityhash.h"
#include <cstring>
#include <utility>
#include "common/cityhash.h"
#include "common/swap.h"
// #include "config.h"
@@ -42,21 +44,17 @@
using namespace std;
typedef uint8_t uint8;
typedef uint32_t uint32;
typedef uint64_t uint64;
namespace Common {
static uint64 UNALIGNED_LOAD64(const char* p) {
uint64 result;
memcpy(&result, p, sizeof(result));
static u64 unaligned_load64(const char* p) {
u64 result;
std::memcpy(&result, p, sizeof(result));
return result;
}
static uint32 UNALIGNED_LOAD32(const char* p) {
uint32 result;
memcpy(&result, p, sizeof(result));
static u32 unaligned_load32(const char* p) {
u32 result;
std::memcpy(&result, p, sizeof(result));
return result;
}
@@ -76,64 +74,64 @@ static uint32 UNALIGNED_LOAD32(const char* p) {
#endif
#endif
static uint64 Fetch64(const char* p) {
return uint64_in_expected_order(UNALIGNED_LOAD64(p));
static u64 Fetch64(const char* p) {
return uint64_in_expected_order(unaligned_load64(p));
}
static uint32 Fetch32(const char* p) {
return uint32_in_expected_order(UNALIGNED_LOAD32(p));
static u32 Fetch32(const char* p) {
return uint32_in_expected_order(unaligned_load32(p));
}
// Some primes between 2^63 and 2^64 for various uses.
static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
static const uint64 k1 = 0xb492b66fbe98f273ULL;
static const uint64 k2 = 0x9ae16a3b2f90404fULL;
static constexpr u64 k0 = 0xc3a5c85c97cb3127ULL;
static constexpr u64 k1 = 0xb492b66fbe98f273ULL;
static constexpr u64 k2 = 0x9ae16a3b2f90404fULL;
// Bitwise right rotate. Normally this will compile to a single
// instruction, especially if the shift is a manifest constant.
static uint64 Rotate(uint64 val, int shift) {
static u64 Rotate(u64 val, int shift) {
// Avoid shifting by 64: doing so yields an undefined result.
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
}
static uint64 ShiftMix(uint64 val) {
static u64 ShiftMix(u64 val) {
return val ^ (val >> 47);
}
static uint64 HashLen16(uint64 u, uint64 v) {
return Hash128to64(uint128(u, v));
static u64 HashLen16(u64 u, u64 v) {
return Hash128to64(u128{u, v});
}
static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
static u64 HashLen16(u64 u, u64 v, u64 mul) {
// Murmur-inspired hashing.
uint64 a = (u ^ v) * mul;
u64 a = (u ^ v) * mul;
a ^= (a >> 47);
uint64 b = (v ^ a) * mul;
u64 b = (v ^ a) * mul;
b ^= (b >> 47);
b *= mul;
return b;
}
static uint64 HashLen0to16(const char* s, std::size_t len) {
static u64 HashLen0to16(const char* s, size_t len) {
if (len >= 8) {
uint64 mul = k2 + len * 2;
uint64 a = Fetch64(s) + k2;
uint64 b = Fetch64(s + len - 8);
uint64 c = Rotate(b, 37) * mul + a;
uint64 d = (Rotate(a, 25) + b) * mul;
u64 mul = k2 + len * 2;
u64 a = Fetch64(s) + k2;
u64 b = Fetch64(s + len - 8);
u64 c = Rotate(b, 37) * mul + a;
u64 d = (Rotate(a, 25) + b) * mul;
return HashLen16(c, d, mul);
}
if (len >= 4) {
uint64 mul = k2 + len * 2;
uint64 a = Fetch32(s);
u64 mul = k2 + len * 2;
u64 a = Fetch32(s);
return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
}
if (len > 0) {
uint8 a = s[0];
uint8 b = s[len >> 1];
uint8 c = s[len - 1];
uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
uint32 z = static_cast<uint32>(len) + (static_cast<uint32>(c) << 2);
u8 a = s[0];
u8 b = s[len >> 1];
u8 c = s[len - 1];
u32 y = static_cast<u32>(a) + (static_cast<u32>(b) << 8);
u32 z = static_cast<u32>(len) + (static_cast<u32>(c) << 2);
return ShiftMix(y * k2 ^ z * k0) * k2;
}
return k2;
@@ -141,22 +139,21 @@ static uint64 HashLen0to16(const char* s, std::size_t len) {
// This probably works well for 16-byte strings as well, but it may be overkill
// in that case.
static uint64 HashLen17to32(const char* s, std::size_t len) {
uint64 mul = k2 + len * 2;
uint64 a = Fetch64(s) * k1;
uint64 b = Fetch64(s + 8);
uint64 c = Fetch64(s + len - 8) * mul;
uint64 d = Fetch64(s + len - 16) * k2;
static u64 HashLen17to32(const char* s, size_t len) {
u64 mul = k2 + len * 2;
u64 a = Fetch64(s) * k1;
u64 b = Fetch64(s + 8);
u64 c = Fetch64(s + len - 8) * mul;
u64 d = Fetch64(s + len - 16) * k2;
return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, a + Rotate(b + k2, 18) + c, mul);
}
// Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b.
static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z, uint64 a,
uint64 b) {
static pair<u64, u64> WeakHashLen32WithSeeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) {
a += w;
b = Rotate(b + a + z, 21);
uint64 c = a;
u64 c = a;
a += x;
a += y;
b += Rotate(a, 44);
@@ -164,34 +161,34 @@ static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y,
}
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
static pair<u64, u64> WeakHashLen32WithSeeds(const char* s, u64 a, u64 b) {
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
b);
}
// Return an 8-byte hash for 33 to 64 bytes.
static uint64 HashLen33to64(const char* s, std::size_t len) {
uint64 mul = k2 + len * 2;
uint64 a = Fetch64(s) * k2;
uint64 b = Fetch64(s + 8);
uint64 c = Fetch64(s + len - 24);
uint64 d = Fetch64(s + len - 32);
uint64 e = Fetch64(s + 16) * k2;
uint64 f = Fetch64(s + 24) * 9;
uint64 g = Fetch64(s + len - 8);
uint64 h = Fetch64(s + len - 16) * mul;
uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
uint64 v = ((a + g) ^ d) + f + 1;
uint64 w = swap64((u + v) * mul) + h;
uint64 x = Rotate(e + f, 42) + c;
uint64 y = (swap64((v + w) * mul) + g) * mul;
uint64 z = e + f + c;
static u64 HashLen33to64(const char* s, size_t len) {
u64 mul = k2 + len * 2;
u64 a = Fetch64(s) * k2;
u64 b = Fetch64(s + 8);
u64 c = Fetch64(s + len - 24);
u64 d = Fetch64(s + len - 32);
u64 e = Fetch64(s + 16) * k2;
u64 f = Fetch64(s + 24) * 9;
u64 g = Fetch64(s + len - 8);
u64 h = Fetch64(s + len - 16) * mul;
u64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
u64 v = ((a + g) ^ d) + f + 1;
u64 w = swap64((u + v) * mul) + h;
u64 x = Rotate(e + f, 42) + c;
u64 y = (swap64((v + w) * mul) + g) * mul;
u64 z = e + f + c;
a = swap64((x + z) * mul + y) + b;
b = ShiftMix((z + a) * mul + d + h) * mul;
return b + x;
}
uint64 CityHash64(const char* s, std::size_t len) {
u64 CityHash64(const char* s, size_t len) {
if (len <= 32) {
if (len <= 16) {
return HashLen0to16(s, len);
@@ -204,15 +201,15 @@ uint64 CityHash64(const char* s, std::size_t len) {
// For strings over 64 bytes we hash the end first, and then as we
// loop we keep 56 bytes of state: v, w, x, y, and z.
uint64 x = Fetch64(s + len - 40);
uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
u64 x = Fetch64(s + len - 40);
u64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
u64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
pair<u64, u64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
pair<u64, u64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
x = x * k1 + Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
len = (len - 1) & ~static_cast<std::size_t>(63);
len = (len - 1) & ~static_cast<size_t>(63);
do {
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
@@ -229,21 +226,21 @@ uint64 CityHash64(const char* s, std::size_t len) {
HashLen16(v.second, w.second) + x);
}
uint64 CityHash64WithSeed(const char* s, std::size_t len, uint64 seed) {
u64 CityHash64WithSeed(const char* s, size_t len, u64 seed) {
return CityHash64WithSeeds(s, len, k2, seed);
}
uint64 CityHash64WithSeeds(const char* s, std::size_t len, uint64 seed0, uint64 seed1) {
u64 CityHash64WithSeeds(const char* s, size_t len, u64 seed0, u64 seed1) {
return HashLen16(CityHash64(s, len) - seed0, seed1);
}
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
// of any length representable in signed long. Based on City and Murmur.
static uint128 CityMurmur(const char* s, std::size_t len, uint128 seed) {
uint64 a = Uint128Low64(seed);
uint64 b = Uint128High64(seed);
uint64 c = 0;
uint64 d = 0;
static u128 CityMurmur(const char* s, size_t len, u128 seed) {
u64 a = seed[0];
u64 b = seed[1];
u64 c = 0;
u64 d = 0;
signed long l = static_cast<long>(len) - 16;
if (l <= 0) { // len <= 16
a = ShiftMix(a * k1) * k1;
@@ -266,20 +263,20 @@ static uint128 CityMurmur(const char* s, std::size_t len, uint128 seed) {
}
a = HashLen16(a, c);
b = HashLen16(d, b);
return uint128(a ^ b, HashLen16(b, a));
return u128{a ^ b, HashLen16(b, a)};
}
uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
u128 CityHash128WithSeed(const char* s, size_t len, u128 seed) {
if (len < 128) {
return CityMurmur(s, len, seed);
}
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
// v, w, x, y, and z.
pair<uint64, uint64> v, w;
uint64 x = Uint128Low64(seed);
uint64 y = Uint128High64(seed);
uint64 z = len * k1;
pair<u64, u64> v, w;
u64 x = seed[0];
u64 y = seed[1];
u64 z = len * k1;
v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
w.first = Rotate(y + z, 35) * k1 + x;
@@ -313,7 +310,7 @@ uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
w.first *= 9;
v.first *= k0;
// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
for (std::size_t tail_done = 0; tail_done < len;) {
for (size_t tail_done = 0; tail_done < len;) {
tail_done += 32;
y = Rotate(x + y, 42) * k0 + v.second;
w.first += Fetch64(s + len - tail_done + 16);
@@ -328,13 +325,12 @@ uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
x = HashLen16(x, v.first);
y = HashLen16(y + z, w.first);
return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second));
return u128{HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second)};
}
uint128 CityHash128(const char* s, std::size_t len) {
return len >= 16
? CityHash128WithSeed(s + 16, len - 16, uint128(Fetch64(s), Fetch64(s + 8) + k0))
: CityHash128WithSeed(s, len, uint128(k0, k1));
u128 CityHash128(const char* s, size_t len) {
return len >= 16 ? CityHash128WithSeed(s + 16, len - 16, u128{Fetch64(s), Fetch64(s + 8) + k0})
: CityHash128WithSeed(s, len, u128{k0, k1});
}
} // namespace Common

View File

@@ -61,50 +61,38 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <utility>
#include "common/common_types.h"
namespace Common {
using uint128 = std::pair<uint64_t, uint64_t>;
[[nodiscard]] inline uint64_t Uint128Low64(const uint128& x) {
return x.first;
}
[[nodiscard]] inline uint64_t Uint128High64(const uint128& x) {
return x.second;
}
// Hash function for a byte array.
[[nodiscard]] uint64_t CityHash64(const char* buf, std::size_t len);
[[nodiscard]] u64 CityHash64(const char* buf, size_t len);
// Hash function for a byte array. For convenience, a 64-bit seed is also
// hashed into the result.
[[nodiscard]] uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
[[nodiscard]] u64 CityHash64WithSeed(const char* buf, size_t len, u64 seed);
// Hash function for a byte array. For convenience, two seeds are also
// hashed into the result.
[[nodiscard]] uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0,
uint64_t seed1);
[[nodiscard]] u64 CityHash64WithSeeds(const char* buf, size_t len, u64 seed0, u64 seed1);
// Hash function for a byte array.
[[nodiscard]] uint128 CityHash128(const char* s, std::size_t len);
[[nodiscard]] u128 CityHash128(const char* s, size_t len);
// Hash function for a byte array. For convenience, a 128-bit seed is also
// hashed into the result.
[[nodiscard]] uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
[[nodiscard]] u128 CityHash128WithSeed(const char* s, size_t len, u128 seed);
// Hash 128 input bits down to 64 bits of output.
// This is intended to be a reasonably good hash function.
[[nodiscard]] inline uint64_t Hash128to64(const uint128& x) {
[[nodiscard]] inline u64 Hash128to64(const u128& x) {
// Murmur-inspired hashing.
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
const u64 mul = 0x9ddfea08eb382d69ULL;
u64 a = (x[0] ^ x[1]) * mul;
a ^= (a >> 47);
uint64_t b = (Uint128High64(x) ^ a) * kMul;
u64 b = (x[1] ^ a) * mul;
b ^= (b >> 47);
b *= kMul;
b *= mul;
return b;
}

View File

@@ -1,271 +0,0 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <cstring>
#include "common/common_types.h"
#include "common/swap.h"
#include "common/vector_math.h"
namespace Common::Color {
/// Convert a 1-bit color component to 8 bit
[[nodiscard]] constexpr u8 Convert1To8(u8 value) {
return value * 255;
}
/// Convert a 4-bit color component to 8 bit
[[nodiscard]] constexpr u8 Convert4To8(u8 value) {
return (value << 4) | value;
}
/// Convert a 5-bit color component to 8 bit
[[nodiscard]] constexpr u8 Convert5To8(u8 value) {
return (value << 3) | (value >> 2);
}
/// Convert a 6-bit color component to 8 bit
[[nodiscard]] constexpr u8 Convert6To8(u8 value) {
return (value << 2) | (value >> 4);
}
/// Convert a 8-bit color component to 1 bit
[[nodiscard]] constexpr u8 Convert8To1(u8 value) {
return value >> 7;
}
/// Convert a 8-bit color component to 4 bit
[[nodiscard]] constexpr u8 Convert8To4(u8 value) {
return value >> 4;
}
/// Convert a 8-bit color component to 5 bit
[[nodiscard]] constexpr u8 Convert8To5(u8 value) {
return value >> 3;
}
/// Convert a 8-bit color component to 6 bit
[[nodiscard]] constexpr u8 Convert8To6(u8 value) {
return value >> 2;
}
/**
* Decode a color stored in RGBA8 format
* @param bytes Pointer to encoded source color
* @return Result color decoded as Common::Vec4<u8>
*/
[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
return {bytes[3], bytes[2], bytes[1], bytes[0]};
}
/**
* Decode a color stored in RGB8 format
* @param bytes Pointer to encoded source color
* @return Result color decoded as Common::Vec4<u8>
*/
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
return {bytes[2], bytes[1], bytes[0], 255};
}
/**
* Decode a color stored in RG8 (aka HILO8) format
* @param bytes Pointer to encoded source color
* @return Result color decoded as Common::Vec4<u8>
*/
[[nodiscard]] inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
return {bytes[1], bytes[0], 0, 255};
}
/**
* Decode a color stored in RGB565 format
* @param bytes Pointer to encoded source color
* @return Result color decoded as Common::Vec4<u8>
*/
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
u16_le pixel;
std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
Convert5To8(pixel & 0x1F), 255};
}
/**
* Decode a color stored in RGB5A1 format
* @param bytes Pointer to encoded source color
* @return Result color decoded as Common::Vec4<u8>
*/
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
u16_le pixel;
std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)};
}
/**
* Decode a color stored in RGBA4 format
* @param bytes Pointer to encoded source color
* @return Result color decoded as Common::Vec4<u8>
*/
[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
u16_le pixel;
std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)};
}
/**
* Decode a depth value stored in D16 format
* @param bytes Pointer to encoded source value
* @return Depth value as an u32
*/
[[nodiscard]] inline u32 DecodeD16(const u8* bytes) {
u16_le data;
std::memcpy(&data, bytes, sizeof(data));
return data;
}
/**
* Decode a depth value stored in D24 format
* @param bytes Pointer to encoded source value
* @return Depth value as an u32
*/
[[nodiscard]] inline u32 DecodeD24(const u8* bytes) {
return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
}
/**
* Decode a depth value and a stencil value stored in D24S8 format
* @param bytes Pointer to encoded source values
* @return Resulting values stored as a Common::Vec2
*/
[[nodiscard]] inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
}
/**
* Encode a color as RGBA8 format
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRGBA8(const Common::Vec4<u8>& color, u8* bytes) {
bytes[3] = color.r();
bytes[2] = color.g();
bytes[1] = color.b();
bytes[0] = color.a();
}
/**
* Encode a color as RGB8 format
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRGB8(const Common::Vec4<u8>& color, u8* bytes) {
bytes[2] = color.r();
bytes[1] = color.g();
bytes[0] = color.b();
}
/**
* Encode a color as RG8 (aka HILO8) format
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRG8(const Common::Vec4<u8>& color, u8* bytes) {
bytes[1] = color.r();
bytes[0] = color.g();
}
/**
* Encode a color as RGB565 format
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRGB565(const Common::Vec4<u8>& color, u8* bytes) {
const u16_le data =
(Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b());
std::memcpy(bytes, &data, sizeof(data));
}
/**
* Encode a color as RGB5A1 format
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRGB5A1(const Common::Vec4<u8>& color, u8* bytes) {
const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) |
(Convert8To5(color.b()) << 1) | Convert8To1(color.a());
std::memcpy(bytes, &data, sizeof(data));
}
/**
* Encode a color as RGBA4 format
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRGBA4(const Common::Vec4<u8>& color, u8* bytes) {
const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) |
(Convert8To4(color.b()) << 4) | Convert8To4(color.a());
std::memcpy(bytes, &data, sizeof(data));
}
/**
* Encode a 16 bit depth value as D16 format
* @param value 16 bit source depth value to encode
* @param bytes Pointer where to store the encoded value
*/
inline void EncodeD16(u32 value, u8* bytes) {
const u16_le data = static_cast<u16>(value);
std::memcpy(bytes, &data, sizeof(data));
}
/**
* Encode a 24 bit depth value as D24 format
* @param value 24 bit source depth value to encode
* @param bytes Pointer where to store the encoded value
*/
inline void EncodeD24(u32 value, u8* bytes) {
bytes[0] = value & 0xFF;
bytes[1] = (value >> 8) & 0xFF;
bytes[2] = (value >> 16) & 0xFF;
}
/**
* Encode a 24 bit depth and 8 bit stencil values as D24S8 format
* @param depth 24 bit source depth value to encode
* @param stencil 8 bit source stencil value to encode
* @param bytes Pointer where to store the encoded value
*/
inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) {
bytes[0] = depth & 0xFF;
bytes[1] = (depth >> 8) & 0xFF;
bytes[2] = (depth >> 16) & 0xFF;
bytes[3] = stencil;
}
/**
* Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused)
* @param depth 24 bit source depth value to encode
* @param bytes Pointer where to store the encoded value
* @note unused bits will not be modified
*/
inline void EncodeD24X8(u32 depth, u8* bytes) {
bytes[0] = depth & 0xFF;
bytes[1] = (depth >> 8) & 0xFF;
bytes[2] = (depth >> 16) & 0xFF;
}
/**
* Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused)
* @param stencil 8 bit source stencil value to encode
* @param bytes Pointer where to store the encoded value
* @note unused bits will not be modified
*/
inline void EncodeX24S8(u8 stencil, u8* bytes) {
bytes[3] = stencil;
}
} // namespace Common::Color

View File

@@ -24,10 +24,10 @@
#define INSERT_PADDING_WORDS(num_words) \
std::array<u32, num_words> CONCAT2(pad, __LINE__) {}
/// These are similar to the INSERT_PADDING_* macros, but are needed for padding unions. This is
/// because unions can only be initialized by one member.
#define INSERT_UNION_PADDING_BYTES(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
#define INSERT_UNION_PADDING_WORDS(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__)
/// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents.
/// This keeps the structure trivial to construct.
#define INSERT_PADDING_BYTES_NOINIT(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
#define INSERT_PADDING_WORDS_NOINIT(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__)
#ifndef _MSC_VER
@@ -93,6 +93,31 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
return static_cast<T>(key) == 0; \
}
/// Evaluates a boolean expression, and returns a result unless that expression is true.
#define R_UNLESS(expr, res) \
{ \
if (!(expr)) { \
if (res.IsError()) { \
LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \
} \
return res; \
} \
}
#define R_SUCCEEDED(res) (res.IsSuccess())
/// Evaluates an expression that returns a result, and returns the result if it would fail.
#define R_TRY(res_expr) \
{ \
const auto _tmp_r_try_rc = (res_expr); \
if (_tmp_r_try_rc.IsError()) { \
return _tmp_r_try_rc; \
} \
}
/// Evaluates a boolean expression, and succeeds if that expression is true.
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), RESULT_SUCCESS)
namespace Common {
[[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {

View File

@@ -11,16 +11,16 @@ namespace Common {
/// Ceiled integer division.
template <typename N, typename D>
requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr auto DivCeil(
N number, D divisor) {
return (static_cast<D>(number) + divisor - 1) / divisor;
requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeil(N number,
D divisor) {
return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
}
/// Ceiled integer division with logarithmic divisor in base 2
template <typename N, typename D>
requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr auto DivCeilLog2(
requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeilLog2(
N value, D alignment_log2) {
return (static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2;
return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
}
} // namespace Common

View File

@@ -0,0 +1,602 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/parent_of_member.h"
#include "common/tree.h"
namespace Common {
namespace impl {
class IntrusiveRedBlackTreeImpl;
}
struct IntrusiveRedBlackTreeNode {
public:
using EntryType = RBEntry<IntrusiveRedBlackTreeNode>;
constexpr IntrusiveRedBlackTreeNode() = default;
void SetEntry(const EntryType& new_entry) {
entry = new_entry;
}
[[nodiscard]] EntryType& GetEntry() {
return entry;
}
[[nodiscard]] const EntryType& GetEntry() const {
return entry;
}
private:
EntryType entry{};
friend class impl::IntrusiveRedBlackTreeImpl;
template <class, class, class>
friend class IntrusiveRedBlackTree;
};
template <class T, class Traits, class Comparator>
class IntrusiveRedBlackTree;
namespace impl {
class IntrusiveRedBlackTreeImpl {
private:
template <class, class, class>
friend class ::Common::IntrusiveRedBlackTree;
using RootType = RBHead<IntrusiveRedBlackTreeNode>;
RootType root;
public:
template <bool Const>
class Iterator;
using value_type = IntrusiveRedBlackTreeNode;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
template <bool Const>
class Iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveRedBlackTreeImpl::value_type;
using difference_type = typename IntrusiveRedBlackTreeImpl::difference_type;
using pointer = std::conditional_t<Const, IntrusiveRedBlackTreeImpl::const_pointer,
IntrusiveRedBlackTreeImpl::pointer>;
using reference = std::conditional_t<Const, IntrusiveRedBlackTreeImpl::const_reference,
IntrusiveRedBlackTreeImpl::reference>;
private:
pointer node;
public:
explicit Iterator(pointer n) : node(n) {}
bool operator==(const Iterator& rhs) const {
return this->node == rhs.node;
}
bool operator!=(const Iterator& rhs) const {
return !(*this == rhs);
}
pointer operator->() const {
return this->node;
}
reference operator*() const {
return *this->node;
}
Iterator& operator++() {
this->node = GetNext(this->node);
return *this;
}
Iterator& operator--() {
this->node = GetPrev(this->node);
return *this;
}
Iterator operator++(int) {
const Iterator it{*this};
++(*this);
return it;
}
Iterator operator--(int) {
const Iterator it{*this};
--(*this);
return it;
}
operator Iterator<true>() const {
return Iterator<true>(this->node);
}
};
private:
// Define accessors using RB_* functions.
bool EmptyImpl() const {
return root.IsEmpty();
}
IntrusiveRedBlackTreeNode* GetMinImpl() const {
return RB_MIN(const_cast<RootType*>(&root));
}
IntrusiveRedBlackTreeNode* GetMaxImpl() const {
return RB_MAX(const_cast<RootType*>(&root));
}
IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) {
return RB_REMOVE(&root, node);
}
public:
static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) {
return RB_NEXT(node);
}
static IntrusiveRedBlackTreeNode* GetPrev(IntrusiveRedBlackTreeNode* node) {
return RB_PREV(node);
}
static const IntrusiveRedBlackTreeNode* GetNext(const IntrusiveRedBlackTreeNode* node) {
return static_cast<const IntrusiveRedBlackTreeNode*>(
GetNext(const_cast<IntrusiveRedBlackTreeNode*>(node)));
}
static const IntrusiveRedBlackTreeNode* GetPrev(const IntrusiveRedBlackTreeNode* node) {
return static_cast<const IntrusiveRedBlackTreeNode*>(
GetPrev(const_cast<IntrusiveRedBlackTreeNode*>(node)));
}
public:
constexpr IntrusiveRedBlackTreeImpl() {}
// Iterator accessors.
iterator begin() {
return iterator(this->GetMinImpl());
}
const_iterator begin() const {
return const_iterator(this->GetMinImpl());
}
iterator end() {
return iterator(static_cast<IntrusiveRedBlackTreeNode*>(nullptr));
}
const_iterator end() const {
return const_iterator(static_cast<const IntrusiveRedBlackTreeNode*>(nullptr));
}
const_iterator cbegin() const {
return this->begin();
}
const_iterator cend() const {
return this->end();
}
iterator iterator_to(reference ref) {
return iterator(&ref);
}
const_iterator iterator_to(const_reference ref) const {
return const_iterator(&ref);
}
// Content management.
bool empty() const {
return this->EmptyImpl();
}
reference back() {
return *this->GetMaxImpl();
}
const_reference back() const {
return *this->GetMaxImpl();
}
reference front() {
return *this->GetMinImpl();
}
const_reference front() const {
return *this->GetMinImpl();
}
iterator erase(iterator it) {
auto cur = std::addressof(*it);
auto next = GetNext(cur);
this->RemoveImpl(cur);
return iterator(next);
}
};
} // namespace impl
template <typename T>
concept HasLightCompareType = requires {
{ std::is_same<typename T::LightCompareType, void>::value }
->std::convertible_to<bool>;
};
namespace impl {
template <typename T, typename Default>
consteval auto* GetLightCompareType() {
if constexpr (HasLightCompareType<T>) {
return static_cast<typename T::LightCompareType*>(nullptr);
} else {
return static_cast<Default*>(nullptr);
}
}
} // namespace impl
template <typename T, typename Default>
using LightCompareType = std::remove_pointer_t<decltype(impl::GetLightCompareType<T, Default>())>;
template <class T, class Traits, class Comparator>
class IntrusiveRedBlackTree {
public:
using ImplType = impl::IntrusiveRedBlackTreeImpl;
private:
ImplType impl{};
public:
template <bool Const>
class Iterator;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
using light_value_type = LightCompareType<Comparator, value_type>;
using const_light_pointer = const light_value_type*;
using const_light_reference = const light_value_type&;
template <bool Const>
class Iterator {
public:
friend class IntrusiveRedBlackTree<T, Traits, Comparator>;
using ImplIterator =
std::conditional_t<Const, ImplType::const_iterator, ImplType::iterator>;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveRedBlackTree::value_type;
using difference_type = typename IntrusiveRedBlackTree::difference_type;
using pointer = std::conditional_t<Const, IntrusiveRedBlackTree::const_pointer,
IntrusiveRedBlackTree::pointer>;
using reference = std::conditional_t<Const, IntrusiveRedBlackTree::const_reference,
IntrusiveRedBlackTree::reference>;
private:
ImplIterator iterator;
private:
explicit Iterator(ImplIterator it) : iterator(it) {}
explicit Iterator(typename std::conditional<Const, ImplType::const_iterator,
ImplType::iterator>::type::pointer ptr)
: iterator(ptr) {}
ImplIterator GetImplIterator() const {
return this->iterator;
}
public:
bool operator==(const Iterator& rhs) const {
return this->iterator == rhs.iterator;
}
bool operator!=(const Iterator& rhs) const {
return !(*this == rhs);
}
pointer operator->() const {
return Traits::GetParent(std::addressof(*this->iterator));
}
reference operator*() const {
return *Traits::GetParent(std::addressof(*this->iterator));
}
Iterator& operator++() {
++this->iterator;
return *this;
}
Iterator& operator--() {
--this->iterator;
return *this;
}
Iterator operator++(int) {
const Iterator it{*this};
++this->iterator;
return it;
}
Iterator operator--(int) {
const Iterator it{*this};
--this->iterator;
return it;
}
operator Iterator<true>() const {
return Iterator<true>(this->iterator);
}
};
private:
static int CompareImpl(const IntrusiveRedBlackTreeNode* lhs,
const IntrusiveRedBlackTreeNode* rhs) {
return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs));
}
static int LightCompareImpl(const void* elm, const IntrusiveRedBlackTreeNode* rhs) {
return Comparator::Compare(*static_cast<const_light_pointer>(elm), *Traits::GetParent(rhs));
}
// Define accessors using RB_* functions.
IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) {
return RB_INSERT(&impl.root, node, CompareImpl);
}
IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const {
return RB_FIND(const_cast<ImplType::RootType*>(&impl.root),
const_cast<IntrusiveRedBlackTreeNode*>(node), CompareImpl);
}
IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const {
return RB_NFIND(const_cast<ImplType::RootType*>(&impl.root),
const_cast<IntrusiveRedBlackTreeNode*>(node), CompareImpl);
}
IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const {
return RB_FIND_LIGHT(const_cast<ImplType::RootType*>(&impl.root),
static_cast<const void*>(lelm), LightCompareImpl);
}
IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const {
return RB_NFIND_LIGHT(const_cast<ImplType::RootType*>(&impl.root),
static_cast<const void*>(lelm), LightCompareImpl);
}
public:
constexpr IntrusiveRedBlackTree() = default;
// Iterator accessors.
iterator begin() {
return iterator(this->impl.begin());
}
const_iterator begin() const {
return const_iterator(this->impl.begin());
}
iterator end() {
return iterator(this->impl.end());
}
const_iterator end() const {
return const_iterator(this->impl.end());
}
const_iterator cbegin() const {
return this->begin();
}
const_iterator cend() const {
return this->end();
}
iterator iterator_to(reference ref) {
return iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref))));
}
const_iterator iterator_to(const_reference ref) const {
return const_iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref))));
}
// Content management.
bool empty() const {
return this->impl.empty();
}
reference back() {
return *Traits::GetParent(std::addressof(this->impl.back()));
}
const_reference back() const {
return *Traits::GetParent(std::addressof(this->impl.back()));
}
reference front() {
return *Traits::GetParent(std::addressof(this->impl.front()));
}
const_reference front() const {
return *Traits::GetParent(std::addressof(this->impl.front()));
}
iterator erase(iterator it) {
return iterator(this->impl.erase(it.GetImplIterator()));
}
iterator insert(reference ref) {
ImplType::pointer node = Traits::GetNode(std::addressof(ref));
this->InsertImpl(node);
return iterator(node);
}
iterator find(const_reference ref) const {
return iterator(this->FindImpl(Traits::GetNode(std::addressof(ref))));
}
iterator nfind(const_reference ref) const {
return iterator(this->NFindImpl(Traits::GetNode(std::addressof(ref))));
}
iterator find_light(const_light_reference ref) const {
return iterator(this->FindLightImpl(std::addressof(ref)));
}
iterator nfind_light(const_light_reference ref) const {
return iterator(this->NFindLightImpl(std::addressof(ref)));
}
};
template <auto T, class Derived = impl::GetParentType<T>>
class IntrusiveRedBlackTreeMemberTraits;
template <class Parent, IntrusiveRedBlackTreeNode Parent::*Member, class Derived>
class IntrusiveRedBlackTreeMemberTraits<Member, Derived> {
public:
template <class Comparator>
using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeMemberTraits, Comparator>;
using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
private:
template <class, class, class>
friend class IntrusiveRedBlackTree;
friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) {
return std::addressof(parent->*Member);
}
static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) {
return std::addressof(parent->*Member);
}
static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) {
return GetParentPointer<Member, Derived>(node);
}
static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) {
return GetParentPointer<Member, Derived>(node);
}
private:
static constexpr TypedStorage<Derived> DerivedStorage = {};
static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage));
};
template <auto T, class Derived = impl::GetParentType<T>>
class IntrusiveRedBlackTreeMemberTraitsDeferredAssert;
template <class Parent, IntrusiveRedBlackTreeNode Parent::*Member, class Derived>
class IntrusiveRedBlackTreeMemberTraitsDeferredAssert<Member, Derived> {
public:
template <class Comparator>
using TreeType =
IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeMemberTraitsDeferredAssert, Comparator>;
using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
static constexpr bool IsValid() {
TypedStorage<Derived> DerivedStorage = {};
return GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage);
}
private:
template <class, class, class>
friend class IntrusiveRedBlackTree;
friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) {
return std::addressof(parent->*Member);
}
static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) {
return std::addressof(parent->*Member);
}
static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) {
return GetParentPointer<Member, Derived>(node);
}
static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) {
return GetParentPointer<Member, Derived>(node);
}
};
template <class Derived>
class IntrusiveRedBlackTreeBaseNode : public IntrusiveRedBlackTreeNode {
public:
constexpr Derived* GetPrev() {
return static_cast<Derived*>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this));
}
constexpr const Derived* GetPrev() const {
return static_cast<const Derived*>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this));
}
constexpr Derived* GetNext() {
return static_cast<Derived*>(impl::IntrusiveRedBlackTreeImpl::GetNext(this));
}
constexpr const Derived* GetNext() const {
return static_cast<const Derived*>(impl::IntrusiveRedBlackTreeImpl::GetNext(this));
}
};
template <class Derived>
class IntrusiveRedBlackTreeBaseTraits {
public:
template <class Comparator>
using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeBaseTraits, Comparator>;
using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
private:
template <class, class, class>
friend class IntrusiveRedBlackTree;
friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) {
return static_cast<IntrusiveRedBlackTreeNode*>(parent);
}
static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) {
return static_cast<const IntrusiveRedBlackTreeNode*>(parent);
}
static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) {
return static_cast<Derived*>(node);
}
static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) {
return static_cast<const Derived*>(node);
}
};
} // namespace Common

View File

@@ -0,0 +1,27 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <filesystem>
#include <stdlib.h>
#include <fmt/format.h>
#include "common/file_util.h"
#include "common/nvidia_flags.h"
namespace Common {
void ConfigureNvidiaEnvironmentFlags() {
#ifdef _WIN32
const std::string shader_path = Common::FS::SanitizePath(
fmt::format("{}/nvidia/", Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir)));
const std::string windows_path =
Common::FS::SanitizePath(shader_path, Common::FS::DirectorySeparator::BackwardSlash);
void(Common::FS::CreateFullPath(shader_path + '/'));
void(_putenv(fmt::format("__GL_SHADER_DISK_CACHE_PATH={}", windows_path).c_str()));
void(_putenv("__GL_SHADER_DISK_CACHE_SKIP_CLEANUP=1"));
#endif
}
} // namespace Common

10
src/common/nvidia_flags.h Normal file
View File

@@ -0,0 +1,10 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
namespace Common {
/// Configure platform specific flags for Nvidia's driver
void ConfigureNvidiaEnvironmentFlags();
} // namespace Common

View File

@@ -0,0 +1,191 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <type_traits>
#include "common/assert.h"
#include "common/common_types.h"
namespace Common {
namespace detail {
template <typename T, size_t Size, size_t Align>
struct TypedStorageImpl {
std::aligned_storage_t<Size, Align> storage_;
};
} // namespace detail
template <typename T>
using TypedStorage = detail::TypedStorageImpl<T, sizeof(T), alignof(T)>;
template <typename T>
static constexpr T* GetPointer(TypedStorage<T>& ts) {
return static_cast<T*>(static_cast<void*>(std::addressof(ts.storage_)));
}
template <typename T>
static constexpr const T* GetPointer(const TypedStorage<T>& ts) {
return static_cast<const T*>(static_cast<const void*>(std::addressof(ts.storage_)));
}
namespace impl {
template <size_t MaxDepth>
struct OffsetOfUnionHolder {
template <typename ParentType, typename MemberType, size_t Offset>
union UnionImpl {
using PaddingMember = char;
static constexpr size_t GetOffset() {
return Offset;
}
#pragma pack(push, 1)
struct {
PaddingMember padding[Offset];
MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
} data;
#pragma pack(pop)
UnionImpl<ParentType, MemberType, Offset + 1> next_union;
};
template <typename ParentType, typename MemberType>
union UnionImpl<ParentType, MemberType, 0> {
static constexpr size_t GetOffset() {
return 0;
}
struct {
MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
} data;
UnionImpl<ParentType, MemberType, 1> next_union;
};
template <typename ParentType, typename MemberType>
union UnionImpl<ParentType, MemberType, MaxDepth> {};
};
template <typename ParentType, typename MemberType>
struct OffsetOfCalculator {
using UnionHolder =
typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType,
0>;
union Union {
char c{};
UnionHolder first_union;
TypedStorage<ParentType> parent;
constexpr Union() : c() {}
};
static constexpr Union U = {};
static constexpr const MemberType* GetNextAddress(const MemberType* start,
const MemberType* target) {
while (start < target) {
start++;
}
return start;
}
static constexpr std::ptrdiff_t GetDifference(const MemberType* start,
const MemberType* target) {
return (target - start) * sizeof(MemberType);
}
template <typename CurUnion>
static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member,
CurUnion& cur_union) {
constexpr size_t Offset = CurUnion::GetOffset();
const auto target = std::addressof(GetPointer(U.parent)->*member);
const auto start = std::addressof(cur_union.data.members[0]);
const auto next = GetNextAddress(start, target);
if (next != target) {
if constexpr (Offset < sizeof(MemberType) - 1) {
return OffsetOfImpl(member, cur_union.next_union);
} else {
UNREACHABLE();
}
}
return (next - start) * sizeof(MemberType) + Offset;
}
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
return OffsetOfImpl(member, U.first_union);
}
};
template <typename T>
struct GetMemberPointerTraits;
template <typename P, typename M>
struct GetMemberPointerTraits<M P::*> {
using Parent = P;
using Member = M;
};
template <auto MemberPtr>
using GetParentType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Parent;
template <auto MemberPtr>
using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
static inline std::ptrdiff_t OffsetOf = [] {
using DeducedParentType = GetParentType<MemberPtr>;
using MemberType = GetMemberType<MemberPtr>;
static_assert(std::is_base_of<DeducedParentType, RealParentType>::value ||
std::is_same<RealParentType, DeducedParentType>::value);
return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
}();
} // namespace impl
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) {
std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>;
return *static_cast<RealParentType*>(
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset));
}
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) {
std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>;
return *static_cast<const RealParentType*>(static_cast<const void*>(
static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset));
}
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>* member) {
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
}
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const* member) {
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
}
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>& member) {
return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
}
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const& member) {
return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
}
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>& member) {
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
}
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const& member) {
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
}
} // namespace Common

View File

@@ -19,15 +19,14 @@ namespace Common {
/// SPSC ring buffer
/// @tparam T Element type
/// @tparam capacity Number of slots in ring buffer
/// @tparam granularity Slot size in terms of number of elements
template <typename T, std::size_t capacity, std::size_t granularity = 1>
template <typename T, std::size_t capacity>
class RingBuffer {
/// A "slot" is made of `granularity` elements of `T`.
static constexpr std::size_t slot_size = granularity * sizeof(T);
/// A "slot" is made of a single `T`.
static constexpr std::size_t slot_size = sizeof(T);
// T must be safely memcpy-able and have a trivial default constructor.
static_assert(std::is_trivial_v<T>);
// Ensure capacity is sensible.
static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2 / granularity);
static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2);
static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two");
// Ensure lock-free.
static_assert(std::atomic_size_t::is_always_lock_free);
@@ -47,7 +46,7 @@ public:
const std::size_t second_copy = push_count - first_copy;
const char* in = static_cast<const char*>(new_slots);
std::memcpy(m_data.data() + pos * granularity, in, first_copy * slot_size);
std::memcpy(m_data.data() + pos, in, first_copy * slot_size);
in += first_copy * slot_size;
std::memcpy(m_data.data(), in, second_copy * slot_size);
@@ -74,7 +73,7 @@ public:
const std::size_t second_copy = pop_count - first_copy;
char* out = static_cast<char*>(output);
std::memcpy(out, m_data.data() + pos * granularity, first_copy * slot_size);
std::memcpy(out, m_data.data() + pos, first_copy * slot_size);
out += first_copy * slot_size;
std::memcpy(out, m_data.data(), second_copy * slot_size);
@@ -84,9 +83,9 @@ public:
}
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);
std::vector<T> out(std::min(max_slots, capacity));
const std::size_t count = Pop(out.data(), out.size());
out.resize(count);
return out;
}
@@ -113,7 +112,7 @@ private:
alignas(128) std::atomic_size_t m_write_index{0};
#endif
std::array<T, granularity * capacity> m_data;
std::array<T, capacity> m_data;
};
} // namespace Common

View File

@@ -49,3 +49,9 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
* \endcode
*/
#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body)
/**
* This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
* used when the caller might want to cancel the ScopeExit.
*/
#define SCOPE_GUARD(body) detail::ScopeExit([&]() body)

View File

@@ -141,27 +141,13 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
}
std::string UTF16ToUTF8(const std::u16string& input) {
#ifdef _MSC_VER
// Workaround for missing char16_t/char32_t instantiations in MSVC2017
std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
std::basic_string<__int16> tmp_buffer(input.cbegin(), input.cend());
return convert.to_bytes(tmp_buffer);
#else
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.to_bytes(input);
#endif
}
std::u16string UTF8ToUTF16(const std::string& input) {
#ifdef _MSC_VER
// Workaround for missing char16_t/char32_t instantiations in MSVC2017
std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
auto tmp_buffer = convert.from_bytes(input);
return std::u16string(tmp_buffer.cbegin(), tmp_buffer.cend());
#else
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.from_bytes(input);
#endif
}
#ifdef _WIN32

View File

@@ -1,159 +0,0 @@
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <ctime>
#include <fmt/format.h>
#include "common/common_types.h"
#include "common/string_util.h"
#include "common/timer.h"
namespace Common {
std::chrono::milliseconds Timer::GetTimeMs() {
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
}
// --------------------------------------------
// Initiate, Start, Stop, and Update the time
// --------------------------------------------
// Set initial values for the class
Timer::Timer() : m_LastTime(0), m_StartTime(0), m_Running(false) {
Update();
}
// Write the starting time
void Timer::Start() {
m_StartTime = GetTimeMs();
m_Running = true;
}
// Stop the timer
void Timer::Stop() {
// Write the final time
m_LastTime = GetTimeMs();
m_Running = false;
}
// Update the last time variable
void Timer::Update() {
m_LastTime = GetTimeMs();
// TODO(ector) - QPF
}
// -------------------------------------
// Get time difference and elapsed time
// -------------------------------------
// Get the number of milliseconds since the last Update()
std::chrono::milliseconds Timer::GetTimeDifference() {
return GetTimeMs() - m_LastTime;
}
// Add the time difference since the last Update() to the starting time.
// This is used to compensate for a paused game.
void Timer::AddTimeDifference() {
m_StartTime += GetTimeDifference();
}
// Get the time elapsed since the Start()
std::chrono::milliseconds Timer::GetTimeElapsed() {
// If we have not started yet, return 1 (because then I don't
// have to change the FPS calculation in CoreRerecording.cpp .
if (m_StartTime.count() == 0)
return std::chrono::milliseconds(1);
// Return the final timer time if the timer is stopped
if (!m_Running)
return (m_LastTime - m_StartTime);
return (GetTimeMs() - m_StartTime);
}
// Get the formatted time elapsed since the Start()
std::string Timer::GetTimeElapsedFormatted() const {
// If we have not started yet, return zero
if (m_StartTime.count() == 0)
return "00:00:00:000";
// The number of milliseconds since the start.
// Use a different value if the timer is stopped.
std::chrono::milliseconds Milliseconds;
if (m_Running)
Milliseconds = GetTimeMs() - m_StartTime;
else
Milliseconds = m_LastTime - m_StartTime;
// Seconds
std::chrono::seconds Seconds = std::chrono::duration_cast<std::chrono::seconds>(Milliseconds);
// Minutes
std::chrono::minutes Minutes = std::chrono::duration_cast<std::chrono::minutes>(Milliseconds);
// Hours
std::chrono::hours Hours = std::chrono::duration_cast<std::chrono::hours>(Milliseconds);
std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours.count(), Minutes.count() % 60,
Seconds.count() % 60, Milliseconds.count() % 1000);
return TmpStr;
}
// Get the number of seconds since January 1 1970
std::chrono::seconds Timer::GetTimeSinceJan1970() {
return std::chrono::duration_cast<std::chrono::seconds>(GetTimeMs());
}
std::chrono::seconds Timer::GetLocalTimeSinceJan1970() {
time_t sysTime, tzDiff, tzDST;
struct tm* gmTime;
time(&sysTime);
// Account for DST where needed
gmTime = localtime(&sysTime);
if (gmTime->tm_isdst == 1)
tzDST = 3600;
else
tzDST = 0;
// Lazy way to get local time in sec
gmTime = gmtime(&sysTime);
tzDiff = sysTime - mktime(gmTime);
return std::chrono::seconds(sysTime + tzDiff + tzDST);
}
// Return the current time formatted as Minutes:Seconds:Milliseconds
// in the form 00:00:000.
std::string Timer::GetTimeFormatted() {
time_t sysTime;
struct tm* gmTime;
char tmp[13];
time(&sysTime);
gmTime = localtime(&sysTime);
strftime(tmp, 6, "%M:%S", gmTime);
u64 milliseconds = static_cast<u64>(GetTimeMs().count()) % 1000;
return fmt::format("{}:{:03}", tmp, milliseconds);
}
// Returns a timestamp with decimals for precise time comparisons
// ----------------
double Timer::GetDoubleTime() {
// Get continuous timestamp
auto tmp_seconds = static_cast<u64>(GetTimeSinceJan1970().count());
const auto ms = static_cast<double>(static_cast<u64>(GetTimeMs().count()) % 1000);
// Remove a few years. We only really want enough seconds to make
// sure that we are detecting actual actions, perhaps 60 seconds is
// enough really, but I leave a year of seconds anyway, in case the
// user's clock is incorrect or something like that.
tmp_seconds = tmp_seconds - (38 * 365 * 24 * 60 * 60);
// Make a smaller integer that fits in the double
const auto seconds = static_cast<u32>(tmp_seconds);
return seconds + ms;
}
} // Namespace Common

View File

@@ -1,41 +0,0 @@
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <chrono>
#include <string>
#include "common/common_types.h"
namespace Common {
class Timer {
public:
Timer();
void Start();
void Stop();
void Update();
// The time difference is always returned in milliseconds, regardless of alternative internal
// representation
[[nodiscard]] std::chrono::milliseconds GetTimeDifference();
void AddTimeDifference();
[[nodiscard]] static std::chrono::seconds GetTimeSinceJan1970();
[[nodiscard]] static std::chrono::seconds GetLocalTimeSinceJan1970();
[[nodiscard]] static double GetDoubleTime();
[[nodiscard]] static std::string GetTimeFormatted();
[[nodiscard]] std::string GetTimeElapsedFormatted() const;
[[nodiscard]] std::chrono::milliseconds GetTimeElapsed();
[[nodiscard]] static std::chrono::milliseconds GetTimeMs();
private:
std::chrono::milliseconds m_LastTime;
std::chrono::milliseconds m_StartTime;
bool m_Running;
};
} // Namespace Common

250
src/common/tiny_mt.h Normal file
View File

@@ -0,0 +1,250 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include "common/alignment.h"
#include "common/common_types.h"
namespace Common {
// Implementation of TinyMT (mersenne twister RNG).
// Like Nintendo, we will use the sample parameters.
class TinyMT {
public:
static constexpr std::size_t NumStateWords = 4;
struct State {
std::array<u32, NumStateWords> data{};
};
private:
static constexpr u32 ParamMat1 = 0x8F7011EE;
static constexpr u32 ParamMat2 = 0xFC78FF1F;
static constexpr u32 ParamTmat = 0x3793FDFF;
static constexpr u32 ParamMult = 0x6C078965;
static constexpr u32 ParamPlus = 0x0019660D;
static constexpr u32 ParamXor = 0x5D588B65;
static constexpr u32 TopBitmask = 0x7FFFFFFF;
static constexpr int MinimumInitIterations = 8;
static constexpr int NumDiscardedInitOutputs = 8;
static constexpr u32 XorByShifted27(u32 value) {
return value ^ (value >> 27);
}
static constexpr u32 XorByShifted30(u32 value) {
return value ^ (value >> 30);
}
private:
State state{};
private:
// Internal API.
void FinalizeInitialization() {
const u32 state0 = this->state.data[0] & TopBitmask;
const u32 state1 = this->state.data[1];
const u32 state2 = this->state.data[2];
const u32 state3 = this->state.data[3];
if (state0 == 0 && state1 == 0 && state2 == 0 && state3 == 0) {
this->state.data[0] = 'T';
this->state.data[1] = 'I';
this->state.data[2] = 'N';
this->state.data[3] = 'Y';
}
for (int i = 0; i < NumDiscardedInitOutputs; i++) {
this->GenerateRandomU32();
}
}
u32 GenerateRandomU24() {
return (this->GenerateRandomU32() >> 8);
}
static void GenerateInitialValuePlus(TinyMT::State* state, int index, u32 value) {
u32& state0 = state->data[(index + 0) % NumStateWords];
u32& state1 = state->data[(index + 1) % NumStateWords];
u32& state2 = state->data[(index + 2) % NumStateWords];
u32& state3 = state->data[(index + 3) % NumStateWords];
const u32 x = XorByShifted27(state0 ^ state1 ^ state3) * ParamPlus;
const u32 y = x + index + value;
state0 = y;
state1 += x;
state2 += y;
}
static void GenerateInitialValueXor(TinyMT::State* state, int index) {
u32& state0 = state->data[(index + 0) % NumStateWords];
u32& state1 = state->data[(index + 1) % NumStateWords];
u32& state2 = state->data[(index + 2) % NumStateWords];
u32& state3 = state->data[(index + 3) % NumStateWords];
const u32 x = XorByShifted27(state0 + state1 + state3) * ParamXor;
const u32 y = x - index;
state0 = y;
state1 ^= x;
state2 ^= y;
}
public:
constexpr TinyMT() = default;
// Public API.
// Initialization.
void Initialize(u32 seed) {
this->state.data[0] = seed;
this->state.data[1] = ParamMat1;
this->state.data[2] = ParamMat2;
this->state.data[3] = ParamTmat;
for (int i = 1; i < MinimumInitIterations; i++) {
const u32 mixed = XorByShifted30(this->state.data[(i - 1) % NumStateWords]);
this->state.data[i % NumStateWords] ^= mixed * ParamMult + i;
}
this->FinalizeInitialization();
}
void Initialize(const u32* seed, int seed_count) {
this->state.data[0] = 0;
this->state.data[1] = ParamMat1;
this->state.data[2] = ParamMat2;
this->state.data[3] = ParamTmat;
{
const int num_init_iterations = std::max(seed_count + 1, MinimumInitIterations) - 1;
GenerateInitialValuePlus(&this->state, 0, seed_count);
for (int i = 0; i < num_init_iterations; i++) {
GenerateInitialValuePlus(&this->state, (i + 1) % NumStateWords,
(i < seed_count) ? seed[i] : 0);
}
for (int i = 0; i < static_cast<int>(NumStateWords); i++) {
GenerateInitialValueXor(&this->state,
(i + 1 + num_init_iterations) % NumStateWords);
}
}
this->FinalizeInitialization();
}
// State management.
void GetState(TinyMT::State& out) const {
out.data = this->state.data;
}
void SetState(const TinyMT::State& state_) {
this->state.data = state_.data;
}
// Random generation.
void GenerateRandomBytes(void* dst, std::size_t size) {
const uintptr_t start = reinterpret_cast<uintptr_t>(dst);
const uintptr_t end = start + size;
const uintptr_t aligned_start = Common::AlignUp(start, 4);
const uintptr_t aligned_end = Common::AlignDown(end, 4);
// Make sure we're aligned.
if (start < aligned_start) {
const u32 rnd = this->GenerateRandomU32();
std::memcpy(dst, &rnd, aligned_start - start);
}
// Write as many aligned u32s as we can.
{
u32* cur_dst = reinterpret_cast<u32*>(aligned_start);
u32* const end_dst = reinterpret_cast<u32*>(aligned_end);
while (cur_dst < end_dst) {
*(cur_dst++) = this->GenerateRandomU32();
}
}
// Handle any leftover unaligned data.
if (aligned_end < end) {
const u32 rnd = this->GenerateRandomU32();
std::memcpy(reinterpret_cast<void*>(aligned_end), &rnd, end - aligned_end);
}
}
u32 GenerateRandomU32() {
// Advance state.
const u32 x0 =
(this->state.data[0] & TopBitmask) ^ this->state.data[1] ^ this->state.data[2];
const u32 y0 = this->state.data[3];
const u32 x1 = x0 ^ (x0 << 1);
const u32 y1 = y0 ^ (y0 >> 1) ^ x1;
const u32 state0 = this->state.data[1];
u32 state1 = this->state.data[2];
u32 state2 = x1 ^ (y1 << 10);
const u32 state3 = y1;
if ((y1 & 1) != 0) {
state1 ^= ParamMat1;
state2 ^= ParamMat2;
}
this->state.data[0] = state0;
this->state.data[1] = state1;
this->state.data[2] = state2;
this->state.data[3] = state3;
// Temper.
const u32 t1 = state0 + (state2 >> 8);
u32 t0 = state3 ^ t1;
if ((t1 & 1) != 0) {
t0 ^= ParamTmat;
}
return t0;
}
u64 GenerateRandomU64() {
const u32 lo = this->GenerateRandomU32();
const u32 hi = this->GenerateRandomU32();
return (u64{hi} << 32) | u64{lo};
}
float GenerateRandomF32() {
// Floats have 24 bits of mantissa.
constexpr u32 MantissaBits = 24;
return static_cast<float>(GenerateRandomU24()) * (1.0f / (1U << MantissaBits));
}
double GenerateRandomF64() {
// Doubles have 53 bits of mantissa.
// The smart way to generate 53 bits of random would be to use 32 bits
// from the first rnd32() call, and then 21 from the second.
// Nintendo does not. They use (32 - 5) = 27 bits from the first rnd32()
// call, and (32 - 6) bits from the second. We'll do what they do, but
// There's not a clear reason why.
constexpr u32 MantissaBits = 53;
constexpr u32 Shift1st = (64 - MantissaBits) / 2;
constexpr u32 Shift2nd = (64 - MantissaBits) - Shift1st;
const u32 first = (this->GenerateRandomU32() >> Shift1st);
const u32 second = (this->GenerateRandomU32() >> Shift2nd);
return (1.0 * first * (u64{1} << (32 - Shift2nd)) + second) *
(1.0 / (u64{1} << MantissaBits));
}
};
} // namespace Common

674
src/common/tree.h Normal file
View File

@@ -0,0 +1,674 @@
/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/* $FreeBSD$ */
/*-
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
/*
* This file defines data structures for red-black trees.
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
namespace Common {
template <typename T>
class RBHead {
public:
[[nodiscard]] T* Root() {
return rbh_root;
}
[[nodiscard]] const T* Root() const {
return rbh_root;
}
void SetRoot(T* root) {
rbh_root = root;
}
[[nodiscard]] bool IsEmpty() const {
return Root() == nullptr;
}
private:
T* rbh_root = nullptr;
};
enum class EntryColor {
Black,
Red,
};
template <typename T>
class RBEntry {
public:
[[nodiscard]] T* Left() {
return rbe_left;
}
[[nodiscard]] const T* Left() const {
return rbe_left;
}
void SetLeft(T* left) {
rbe_left = left;
}
[[nodiscard]] T* Right() {
return rbe_right;
}
[[nodiscard]] const T* Right() const {
return rbe_right;
}
void SetRight(T* right) {
rbe_right = right;
}
[[nodiscard]] T* Parent() {
return rbe_parent;
}
[[nodiscard]] const T* Parent() const {
return rbe_parent;
}
void SetParent(T* parent) {
rbe_parent = parent;
}
[[nodiscard]] bool IsBlack() const {
return rbe_color == EntryColor::Black;
}
[[nodiscard]] bool IsRed() const {
return rbe_color == EntryColor::Red;
}
[[nodiscard]] EntryColor Color() const {
return rbe_color;
}
void SetColor(EntryColor color) {
rbe_color = color;
}
private:
T* rbe_left = nullptr;
T* rbe_right = nullptr;
T* rbe_parent = nullptr;
EntryColor rbe_color{};
};
template <typename Node>
[[nodiscard]] RBEntry<Node>& RB_ENTRY(Node* node) {
return node->GetEntry();
}
template <typename Node>
[[nodiscard]] const RBEntry<Node>& RB_ENTRY(const Node* node) {
return node->GetEntry();
}
template <typename Node>
[[nodiscard]] Node* RB_PARENT(Node* node) {
return RB_ENTRY(node).Parent();
}
template <typename Node>
[[nodiscard]] const Node* RB_PARENT(const Node* node) {
return RB_ENTRY(node).Parent();
}
template <typename Node>
void RB_SET_PARENT(Node* node, Node* parent) {
return RB_ENTRY(node).SetParent(parent);
}
template <typename Node>
[[nodiscard]] Node* RB_LEFT(Node* node) {
return RB_ENTRY(node).Left();
}
template <typename Node>
[[nodiscard]] const Node* RB_LEFT(const Node* node) {
return RB_ENTRY(node).Left();
}
template <typename Node>
void RB_SET_LEFT(Node* node, Node* left) {
return RB_ENTRY(node).SetLeft(left);
}
template <typename Node>
[[nodiscard]] Node* RB_RIGHT(Node* node) {
return RB_ENTRY(node).Right();
}
template <typename Node>
[[nodiscard]] const Node* RB_RIGHT(const Node* node) {
return RB_ENTRY(node).Right();
}
template <typename Node>
void RB_SET_RIGHT(Node* node, Node* right) {
return RB_ENTRY(node).SetRight(right);
}
template <typename Node>
[[nodiscard]] bool RB_IS_BLACK(const Node* node) {
return RB_ENTRY(node).IsBlack();
}
template <typename Node>
[[nodiscard]] bool RB_IS_RED(const Node* node) {
return RB_ENTRY(node).IsRed();
}
template <typename Node>
[[nodiscard]] EntryColor RB_COLOR(const Node* node) {
return RB_ENTRY(node).Color();
}
template <typename Node>
void RB_SET_COLOR(Node* node, EntryColor color) {
return RB_ENTRY(node).SetColor(color);
}
template <typename Node>
void RB_SET(Node* node, Node* parent) {
auto& entry = RB_ENTRY(node);
entry.SetParent(parent);
entry.SetLeft(nullptr);
entry.SetRight(nullptr);
entry.SetColor(EntryColor::Red);
}
template <typename Node>
void RB_SET_BLACKRED(Node* black, Node* red) {
RB_SET_COLOR(black, EntryColor::Black);
RB_SET_COLOR(red, EntryColor::Red);
}
template <typename Node>
void RB_ROTATE_LEFT(RBHead<Node>* head, Node* elm, Node*& tmp) {
tmp = RB_RIGHT(elm);
RB_SET_RIGHT(elm, RB_LEFT(tmp));
if (RB_RIGHT(elm) != nullptr) {
RB_SET_PARENT(RB_LEFT(tmp), elm);
}
RB_SET_PARENT(tmp, RB_PARENT(elm));
if (RB_PARENT(tmp) != nullptr) {
if (elm == RB_LEFT(RB_PARENT(elm))) {
RB_SET_LEFT(RB_PARENT(elm), tmp);
} else {
RB_SET_RIGHT(RB_PARENT(elm), tmp);
}
} else {
head->SetRoot(tmp);
}
RB_SET_LEFT(tmp, elm);
RB_SET_PARENT(elm, tmp);
}
template <typename Node>
void RB_ROTATE_RIGHT(RBHead<Node>* head, Node* elm, Node*& tmp) {
tmp = RB_LEFT(elm);
RB_SET_LEFT(elm, RB_RIGHT(tmp));
if (RB_LEFT(elm) != nullptr) {
RB_SET_PARENT(RB_RIGHT(tmp), elm);
}
RB_SET_PARENT(tmp, RB_PARENT(elm));
if (RB_PARENT(tmp) != nullptr) {
if (elm == RB_LEFT(RB_PARENT(elm))) {
RB_SET_LEFT(RB_PARENT(elm), tmp);
} else {
RB_SET_RIGHT(RB_PARENT(elm), tmp);
}
} else {
head->SetRoot(tmp);
}
RB_SET_RIGHT(tmp, elm);
RB_SET_PARENT(elm, tmp);
}
template <typename Node>
void RB_INSERT_COLOR(RBHead<Node>* head, Node* elm) {
Node* parent = nullptr;
Node* tmp = nullptr;
while ((parent = RB_PARENT(elm)) != nullptr && RB_IS_RED(parent)) {
Node* gparent = RB_PARENT(parent);
if (parent == RB_LEFT(gparent)) {
tmp = RB_RIGHT(gparent);
if (tmp && RB_IS_RED(tmp)) {
RB_SET_COLOR(tmp, EntryColor::Black);
RB_SET_BLACKRED(parent, gparent);
elm = gparent;
continue;
}
if (RB_RIGHT(parent) == elm) {
RB_ROTATE_LEFT(head, parent, tmp);
tmp = parent;
parent = elm;
elm = tmp;
}
RB_SET_BLACKRED(parent, gparent);
RB_ROTATE_RIGHT(head, gparent, tmp);
} else {
tmp = RB_LEFT(gparent);
if (tmp && RB_IS_RED(tmp)) {
RB_SET_COLOR(tmp, EntryColor::Black);
RB_SET_BLACKRED(parent, gparent);
elm = gparent;
continue;
}
if (RB_LEFT(parent) == elm) {
RB_ROTATE_RIGHT(head, parent, tmp);
tmp = parent;
parent = elm;
elm = tmp;
}
RB_SET_BLACKRED(parent, gparent);
RB_ROTATE_LEFT(head, gparent, tmp);
}
}
RB_SET_COLOR(head->Root(), EntryColor::Black);
}
template <typename Node>
void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) {
Node* tmp;
while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root()) {
if (RB_LEFT(parent) == elm) {
tmp = RB_RIGHT(parent);
if (RB_IS_RED(tmp)) {
RB_SET_BLACKRED(tmp, parent);
RB_ROTATE_LEFT(head, parent, tmp);
tmp = RB_RIGHT(parent);
}
if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) &&
(RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) {
RB_SET_COLOR(tmp, EntryColor::Red);
elm = parent;
parent = RB_PARENT(elm);
} else {
if (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp))) {
Node* oleft;
if ((oleft = RB_LEFT(tmp)) != nullptr) {
RB_SET_COLOR(oleft, EntryColor::Black);
}
RB_SET_COLOR(tmp, EntryColor::Red);
RB_ROTATE_RIGHT(head, tmp, oleft);
tmp = RB_RIGHT(parent);
}
RB_SET_COLOR(tmp, RB_COLOR(parent));
RB_SET_COLOR(parent, EntryColor::Black);
if (RB_RIGHT(tmp)) {
RB_SET_COLOR(RB_RIGHT(tmp), EntryColor::Black);
}
RB_ROTATE_LEFT(head, parent, tmp);
elm = head->Root();
break;
}
} else {
tmp = RB_LEFT(parent);
if (RB_IS_RED(tmp)) {
RB_SET_BLACKRED(tmp, parent);
RB_ROTATE_RIGHT(head, parent, tmp);
tmp = RB_LEFT(parent);
}
if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) &&
(RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) {
RB_SET_COLOR(tmp, EntryColor::Red);
elm = parent;
parent = RB_PARENT(elm);
} else {
if (RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) {
Node* oright;
if ((oright = RB_RIGHT(tmp)) != nullptr) {
RB_SET_COLOR(oright, EntryColor::Black);
}
RB_SET_COLOR(tmp, EntryColor::Red);
RB_ROTATE_LEFT(head, tmp, oright);
tmp = RB_LEFT(parent);
}
RB_SET_COLOR(tmp, RB_COLOR(parent));
RB_SET_COLOR(parent, EntryColor::Black);
if (RB_LEFT(tmp)) {
RB_SET_COLOR(RB_LEFT(tmp), EntryColor::Black);
}
RB_ROTATE_RIGHT(head, parent, tmp);
elm = head->Root();
break;
}
}
}
if (elm) {
RB_SET_COLOR(elm, EntryColor::Black);
}
}
template <typename Node>
Node* RB_REMOVE(RBHead<Node>* head, Node* elm) {
Node* child = nullptr;
Node* parent = nullptr;
Node* old = elm;
EntryColor color{};
const auto finalize = [&] {
if (color == EntryColor::Black) {
RB_REMOVE_COLOR(head, parent, child);
}
return old;
};
if (RB_LEFT(elm) == nullptr) {
child = RB_RIGHT(elm);
} else if (RB_RIGHT(elm) == nullptr) {
child = RB_LEFT(elm);
} else {
Node* left;
elm = RB_RIGHT(elm);
while ((left = RB_LEFT(elm)) != nullptr) {
elm = left;
}
child = RB_RIGHT(elm);
parent = RB_PARENT(elm);
color = RB_COLOR(elm);
if (child) {
RB_SET_PARENT(child, parent);
}
if (parent) {
if (RB_LEFT(parent) == elm) {
RB_SET_LEFT(parent, child);
} else {
RB_SET_RIGHT(parent, child);
}
} else {
head->SetRoot(child);
}
if (RB_PARENT(elm) == old) {
parent = elm;
}
elm->SetEntry(old->GetEntry());
if (RB_PARENT(old)) {
if (RB_LEFT(RB_PARENT(old)) == old) {
RB_SET_LEFT(RB_PARENT(old), elm);
} else {
RB_SET_RIGHT(RB_PARENT(old), elm);
}
} else {
head->SetRoot(elm);
}
RB_SET_PARENT(RB_LEFT(old), elm);
if (RB_RIGHT(old)) {
RB_SET_PARENT(RB_RIGHT(old), elm);
}
if (parent) {
left = parent;
}
return finalize();
}
parent = RB_PARENT(elm);
color = RB_COLOR(elm);
if (child) {
RB_SET_PARENT(child, parent);
}
if (parent) {
if (RB_LEFT(parent) == elm) {
RB_SET_LEFT(parent, child);
} else {
RB_SET_RIGHT(parent, child);
}
} else {
head->SetRoot(child);
}
return finalize();
}
// Inserts a node into the RB tree
template <typename Node, typename CompareFunction>
Node* RB_INSERT(RBHead<Node>* head, Node* elm, CompareFunction cmp) {
Node* parent = nullptr;
Node* tmp = head->Root();
int comp = 0;
while (tmp) {
parent = tmp;
comp = cmp(elm, parent);
if (comp < 0) {
tmp = RB_LEFT(tmp);
} else if (comp > 0) {
tmp = RB_RIGHT(tmp);
} else {
return tmp;
}
}
RB_SET(elm, parent);
if (parent != nullptr) {
if (comp < 0) {
RB_SET_LEFT(parent, elm);
} else {
RB_SET_RIGHT(parent, elm);
}
} else {
head->SetRoot(elm);
}
RB_INSERT_COLOR(head, elm);
return nullptr;
}
// Finds the node with the same key as elm
template <typename Node, typename CompareFunction>
Node* RB_FIND(RBHead<Node>* head, Node* elm, CompareFunction cmp) {
Node* tmp = head->Root();
while (tmp) {
const int comp = cmp(elm, tmp);
if (comp < 0) {
tmp = RB_LEFT(tmp);
} else if (comp > 0) {
tmp = RB_RIGHT(tmp);
} else {
return tmp;
}
}
return nullptr;
}
// Finds the first node greater than or equal to the search key
template <typename Node, typename CompareFunction>
Node* RB_NFIND(RBHead<Node>* head, Node* elm, CompareFunction cmp) {
Node* tmp = head->Root();
Node* res = nullptr;
while (tmp) {
const int comp = cmp(elm, tmp);
if (comp < 0) {
res = tmp;
tmp = RB_LEFT(tmp);
} else if (comp > 0) {
tmp = RB_RIGHT(tmp);
} else {
return tmp;
}
}
return res;
}
// Finds the node with the same key as lelm
template <typename Node, typename CompareFunction>
Node* RB_FIND_LIGHT(RBHead<Node>* head, const void* lelm, CompareFunction lcmp) {
Node* tmp = head->Root();
while (tmp) {
const int comp = lcmp(lelm, tmp);
if (comp < 0) {
tmp = RB_LEFT(tmp);
} else if (comp > 0) {
tmp = RB_RIGHT(tmp);
} else {
return tmp;
}
}
return nullptr;
}
// Finds the first node greater than or equal to the search key
template <typename Node, typename CompareFunction>
Node* RB_NFIND_LIGHT(RBHead<Node>* head, const void* lelm, CompareFunction lcmp) {
Node* tmp = head->Root();
Node* res = nullptr;
while (tmp) {
const int comp = lcmp(lelm, tmp);
if (comp < 0) {
res = tmp;
tmp = RB_LEFT(tmp);
} else if (comp > 0) {
tmp = RB_RIGHT(tmp);
} else {
return tmp;
}
}
return res;
}
template <typename Node>
Node* RB_NEXT(Node* elm) {
if (RB_RIGHT(elm)) {
elm = RB_RIGHT(elm);
while (RB_LEFT(elm)) {
elm = RB_LEFT(elm);
}
} else {
if (RB_PARENT(elm) && (elm == RB_LEFT(RB_PARENT(elm)))) {
elm = RB_PARENT(elm);
} else {
while (RB_PARENT(elm) && (elm == RB_RIGHT(RB_PARENT(elm)))) {
elm = RB_PARENT(elm);
}
elm = RB_PARENT(elm);
}
}
return elm;
}
template <typename Node>
Node* RB_PREV(Node* elm) {
if (RB_LEFT(elm)) {
elm = RB_LEFT(elm);
while (RB_RIGHT(elm)) {
elm = RB_RIGHT(elm);
}
} else {
if (RB_PARENT(elm) && (elm == RB_RIGHT(RB_PARENT(elm)))) {
elm = RB_PARENT(elm);
} else {
while (RB_PARENT(elm) && (elm == RB_LEFT(RB_PARENT(elm)))) {
elm = RB_PARENT(elm);
}
elm = RB_PARENT(elm);
}
}
return elm;
}
template <typename Node>
Node* RB_MINMAX(RBHead<Node>* head, bool is_min) {
Node* tmp = head->Root();
Node* parent = nullptr;
while (tmp) {
parent = tmp;
if (is_min) {
tmp = RB_LEFT(tmp);
} else {
tmp = RB_RIGHT(tmp);
}
}
return parent;
}
template <typename Node>
Node* RB_MIN(RBHead<Node>* head) {
return RB_MINMAX(head, true);
}
template <typename Node>
Node* RB_MAX(RBHead<Node>* head) {
return RB_MINMAX(head, false);
}
} // namespace Common

View File

@@ -1,71 +0,0 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#ifdef _MSC_VER
#include <intrin.h>
#pragma intrinsic(_umul128)
#pragma intrinsic(_udiv128)
#endif
#include <cstring>
#include "common/uint128.h"
namespace Common {
#ifdef _MSC_VER
u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) {
u128 r{};
r[0] = _umul128(a, b, &r[1]);
u64 remainder;
#if _MSC_VER < 1923
return udiv128(r[1], r[0], d, &remainder);
#else
return _udiv128(r[1], r[0], d, &remainder);
#endif
}
#else
u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) {
const u64 diva = a / d;
const u64 moda = a % d;
const u64 divb = b / d;
const u64 modb = b % d;
return diva * b + moda * divb + moda * modb / d;
}
#endif
u128 Multiply64Into128(u64 a, u64 b) {
u128 result;
#ifdef _MSC_VER
result[0] = _umul128(a, b, &result[1]);
#else
unsigned __int128 tmp = a;
tmp *= b;
std::memcpy(&result, &tmp, sizeof(u128));
#endif
return result;
}
std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) {
u64 remainder = dividend[0] % divisor;
u64 accum = dividend[0] / divisor;
if (dividend[1] == 0)
return {accum, remainder};
// We ignore dividend[1] / divisor as that overflows
const u64 first_segment = (dividend[1] % divisor) << 32;
accum += (first_segment / divisor) << 32;
const u64 second_segment = (first_segment % divisor) << 32;
accum += (second_segment / divisor);
remainder += second_segment % divisor;
if (remainder >= divisor) {
accum++;
remainder -= divisor;
}
return {accum, remainder};
}
} // namespace Common

View File

@@ -4,19 +4,98 @@
#pragma once
#include <cstring>
#include <utility>
#ifdef _MSC_VER
#include <intrin.h>
#pragma intrinsic(__umulh)
#pragma intrinsic(_umul128)
#pragma intrinsic(_udiv128)
#else
#include <x86intrin.h>
#endif
#include "common/common_types.h"
namespace Common {
// This function multiplies 2 u64 values and divides it by a u64 value.
[[nodiscard]] u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
[[nodiscard]] static inline u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) {
#ifdef _MSC_VER
u128 r{};
r[0] = _umul128(a, b, &r[1]);
u64 remainder;
#if _MSC_VER < 1923
return udiv128(r[1], r[0], d, &remainder);
#else
return _udiv128(r[1], r[0], d, &remainder);
#endif
#else
const u64 diva = a / d;
const u64 moda = a % d;
const u64 divb = b / d;
const u64 modb = b % d;
return diva * b + moda * divb + moda * modb / d;
#endif
}
// This function multiplies 2 u64 values and produces a u128 value;
[[nodiscard]] u128 Multiply64Into128(u64 a, u64 b);
[[nodiscard]] static inline u128 Multiply64Into128(u64 a, u64 b) {
u128 result;
#ifdef _MSC_VER
result[0] = _umul128(a, b, &result[1]);
#else
unsigned __int128 tmp = a;
tmp *= b;
std::memcpy(&result, &tmp, sizeof(u128));
#endif
return result;
}
// This function divides a u128 by a u32 value and produces two u64 values:
// the result of division and the remainder
[[nodiscard]] std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
[[nodiscard]] static inline u64 GetFixedPoint64Factor(u64 numerator, u64 divisor) {
#ifdef __SIZEOF_INT128__
const auto base = static_cast<unsigned __int128>(numerator) << 64ULL;
return static_cast<u64>(base / divisor);
#elif defined(_M_X64) || defined(_M_ARM64)
std::array<u64, 2> r = {0, numerator};
u64 remainder;
#if _MSC_VER < 1923
return udiv128(r[1], r[0], divisor, &remainder);
#else
return _udiv128(r[1], r[0], divisor, &remainder);
#endif
#else
// This one is bit more inaccurate.
return MultiplyAndDivide64(std::numeric_limits<u64>::max(), numerator, divisor);
#endif
}
[[nodiscard]] static inline u64 MultiplyHigh(u64 a, u64 b) {
#ifdef __SIZEOF_INT128__
return (static_cast<unsigned __int128>(a) * static_cast<unsigned __int128>(b)) >> 64;
#elif defined(_M_X64) || defined(_M_ARM64)
return __umulh(a, b); // MSVC
#else
// Generic fallback
const u64 a_lo = u32(a);
const u64 a_hi = a >> 32;
const u64 b_lo = u32(b);
const u64 b_hi = b >> 32;
const u64 a_x_b_hi = a_hi * b_hi;
const u64 a_x_b_mid = a_hi * b_lo;
const u64 b_x_a_mid = b_hi * a_lo;
const u64 a_x_b_lo = a_lo * b_lo;
const u64 carry_bit = (static_cast<u64>(static_cast<u32>(a_x_b_mid)) +
static_cast<u64>(static_cast<u32>(b_x_a_mid)) + (a_x_b_lo >> 32)) >>
32;
const u64 multhi = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit;
return multhi;
#endif
}
} // namespace Common

View File

@@ -14,8 +14,8 @@ constexpr u128 INVALID_UUID{{0, 0}};
struct UUID {
// UUIDs which are 0 are considered invalid!
u128 uuid = INVALID_UUID;
constexpr UUID() = default;
u128 uuid;
UUID() = default;
constexpr explicit UUID(const u128& id) : uuid{id} {}
constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstdint>
#include "common/uint128.h"
#include "common/wall_clock.h"
@@ -18,7 +20,9 @@ using base_time_point = std::chrono::time_point<base_timer>;
class StandardWallClock final : public WallClock {
public:
explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_)
: WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) {
: WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false),
emulated_clock_factor{GetFixedPoint64Factor(emulated_clock_frequency, 1000000000)},
emulated_cpu_factor{GetFixedPoint64Factor(emulated_cpu_frequency, 1000000000)} {
start_time = base_timer::now();
}
@@ -41,16 +45,11 @@ public:
}
u64 GetClockCycles() override {
std::chrono::nanoseconds time_now = GetTimeNS();
const u128 temporary =
Common::Multiply64Into128(time_now.count(), emulated_clock_frequency);
return Common::Divide128On32(temporary, 1000000000).first;
return MultiplyHigh(GetTimeNS().count(), emulated_clock_factor);
}
u64 GetCPUCycles() override {
std::chrono::nanoseconds time_now = GetTimeNS();
const u128 temporary = Common::Multiply64Into128(time_now.count(), emulated_cpu_frequency);
return Common::Divide128On32(temporary, 1000000000).first;
return MultiplyHigh(GetTimeNS().count(), emulated_cpu_factor);
}
void Pause([[maybe_unused]] bool is_paused) override {
@@ -59,6 +58,8 @@ public:
private:
base_time_point start_time;
const u64 emulated_clock_factor;
const u64 emulated_cpu_factor;
};
#ifdef ARCHITECTURE_x86_64

View File

@@ -2,16 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <chrono>
#include <limits>
#include <mutex>
#include <thread>
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
#include "common/atomic_ops.h"
#include "common/uint128.h"
#include "common/x64/native_clock.h"
@@ -48,54 +45,71 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
: WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
rtsc_frequency_} {
_mm_mfence();
last_measure = __rdtsc();
accumulated_ticks = 0U;
time_point.inner.last_measure = __rdtsc();
time_point.inner.accumulated_ticks = 0U;
ns_rtsc_factor = GetFixedPoint64Factor(1000000000, rtsc_frequency);
us_rtsc_factor = GetFixedPoint64Factor(1000000, rtsc_frequency);
ms_rtsc_factor = GetFixedPoint64Factor(1000, rtsc_frequency);
clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency);
cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency);
}
u64 NativeClock::GetRTSC() {
std::scoped_lock scope{rtsc_serialize};
_mm_mfence();
const u64 current_measure = __rdtsc();
u64 diff = current_measure - last_measure;
diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)
if (current_measure > last_measure) {
last_measure = current_measure;
}
accumulated_ticks += diff;
TimePoint new_time_point{};
TimePoint current_time_point{};
do {
current_time_point.pack = time_point.pack;
_mm_mfence();
const u64 current_measure = __rdtsc();
u64 diff = current_measure - current_time_point.inner.last_measure;
diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)
new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure
? current_measure
: current_time_point.inner.last_measure;
new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff;
} while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
current_time_point.pack));
/// The clock cannot be more precise than the guest timer, remove the lower bits
return accumulated_ticks & inaccuracy_mask;
return new_time_point.inner.accumulated_ticks & inaccuracy_mask;
}
void NativeClock::Pause(bool is_paused) {
if (!is_paused) {
_mm_mfence();
last_measure = __rdtsc();
TimePoint current_time_point{};
TimePoint new_time_point{};
do {
current_time_point.pack = time_point.pack;
new_time_point.pack = current_time_point.pack;
_mm_mfence();
new_time_point.inner.last_measure = __rdtsc();
} while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
current_time_point.pack));
}
}
std::chrono::nanoseconds NativeClock::GetTimeNS() {
const u64 rtsc_value = GetRTSC();
return std::chrono::nanoseconds{MultiplyAndDivide64(rtsc_value, 1000000000, rtsc_frequency)};
return std::chrono::nanoseconds{MultiplyHigh(rtsc_value, ns_rtsc_factor)};
}
std::chrono::microseconds NativeClock::GetTimeUS() {
const u64 rtsc_value = GetRTSC();
return std::chrono::microseconds{MultiplyAndDivide64(rtsc_value, 1000000, rtsc_frequency)};
return std::chrono::microseconds{MultiplyHigh(rtsc_value, us_rtsc_factor)};
}
std::chrono::milliseconds NativeClock::GetTimeMS() {
const u64 rtsc_value = GetRTSC();
return std::chrono::milliseconds{MultiplyAndDivide64(rtsc_value, 1000, rtsc_frequency)};
return std::chrono::milliseconds{MultiplyHigh(rtsc_value, ms_rtsc_factor)};
}
u64 NativeClock::GetClockCycles() {
const u64 rtsc_value = GetRTSC();
return MultiplyAndDivide64(rtsc_value, emulated_clock_frequency, rtsc_frequency);
return MultiplyHigh(rtsc_value, clock_rtsc_factor);
}
u64 NativeClock::GetCPUCycles() {
const u64 rtsc_value = GetRTSC();
return MultiplyAndDivide64(rtsc_value, emulated_cpu_frequency, rtsc_frequency);
return MultiplyHigh(rtsc_value, cpu_rtsc_factor);
}
} // namespace X64

View File

@@ -6,7 +6,6 @@
#include <optional>
#include "common/spin_lock.h"
#include "common/wall_clock.h"
namespace Common {
@@ -32,14 +31,28 @@ public:
private:
u64 GetRTSC();
union alignas(16) TimePoint {
TimePoint() : pack{} {}
u128 pack{};
struct Inner {
u64 last_measure{};
u64 accumulated_ticks{};
} inner;
};
/// value used to reduce the native clocks accuracy as some apss rely on
/// undefined behavior where the level of accuracy in the clock shouldn't
/// be higher.
static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1);
SpinLock rtsc_serialize{};
u64 last_measure{};
u64 accumulated_ticks{};
TimePoint time_point;
// factors
u64 clock_rtsc_factor{};
u64 cpu_rtsc_factor{};
u64 ns_rtsc_factor{};
u64 us_rtsc_factor{};
u64 ms_rtsc_factor{};
u64 rtsc_frequency;
};
} // namespace X64

View File

@@ -19,7 +19,6 @@ add_library(core STATIC
core.h
core_timing.cpp
core_timing.h
core_timing_util.cpp
core_timing_util.h
cpu_manager.cpp
cpu_manager.h
@@ -142,49 +141,71 @@ add_library(core STATIC
hardware_interrupt_manager.h
hle/ipc.h
hle/ipc_helpers.h
hle/kernel/address_arbiter.cpp
hle/kernel/address_arbiter.h
hle/kernel/client_port.cpp
hle/kernel/client_port.h
hle/kernel/client_session.cpp
hle/kernel/client_session.h
hle/kernel/code_set.cpp
hle/kernel/code_set.h
hle/kernel/errors.h
hle/kernel/svc_results.h
hle/kernel/global_scheduler_context.cpp
hle/kernel/global_scheduler_context.h
hle/kernel/handle_table.cpp
hle/kernel/handle_table.h
hle/kernel/hle_ipc.cpp
hle/kernel/hle_ipc.h
hle/kernel/k_address_arbiter.cpp
hle/kernel/k_address_arbiter.h
hle/kernel/k_address_space_info.cpp
hle/kernel/k_address_space_info.h
hle/kernel/k_affinity_mask.h
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
hle/kernel/k_event.cpp
hle/kernel/k_event.h
hle/kernel/k_light_condition_variable.h
hle/kernel/k_light_lock.cpp
hle/kernel/k_light_lock.h
hle/kernel/k_memory_block.h
hle/kernel/k_memory_block_manager.cpp
hle/kernel/k_memory_block_manager.h
hle/kernel/k_memory_layout.h
hle/kernel/k_memory_manager.cpp
hle/kernel/k_memory_manager.h
hle/kernel/k_page_bitmap.h
hle/kernel/k_page_heap.cpp
hle/kernel/k_page_heap.h
hle/kernel/k_page_linked_list.h
hle/kernel/k_page_table.cpp
hle/kernel/k_page_table.h
hle/kernel/k_priority_queue.h
hle/kernel/k_readable_event.cpp
hle/kernel/k_readable_event.h
hle/kernel/k_resource_limit.cpp
hle/kernel/k_resource_limit.h
hle/kernel/k_scheduler.cpp
hle/kernel/k_scheduler.h
hle/kernel/k_scheduler_lock.h
hle/kernel/k_scoped_lock.h
hle/kernel/k_scoped_resource_reservation.h
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
hle/kernel/k_shared_memory.cpp
hle/kernel/k_shared_memory.h
hle/kernel/k_slab_heap.h
hle/kernel/k_spin_lock.cpp
hle/kernel/k_spin_lock.h
hle/kernel/k_synchronization_object.cpp
hle/kernel/k_synchronization_object.h
hle/kernel/k_system_control.cpp
hle/kernel/k_system_control.h
hle/kernel/k_thread.cpp
hle/kernel/k_thread.h
hle/kernel/k_thread_queue.h
hle/kernel/k_writable_event.cpp
hle/kernel/k_writable_event.h
hle/kernel/kernel.cpp
hle/kernel/kernel.h
hle/kernel/memory/address_space_info.cpp
hle/kernel/memory/address_space_info.h
hle/kernel/memory/memory_block.h
hle/kernel/memory/memory_block_manager.cpp
hle/kernel/memory/memory_block_manager.h
hle/kernel/memory/memory_layout.h
hle/kernel/memory/memory_manager.cpp
hle/kernel/memory/memory_manager.h
hle/kernel/memory/memory_types.h
hle/kernel/memory/page_linked_list.h
hle/kernel/memory/page_heap.cpp
hle/kernel/memory/page_heap.h
hle/kernel/memory/page_table.cpp
hle/kernel/memory/page_table.h
hle/kernel/memory/slab_heap.h
hle/kernel/memory/system_control.cpp
hle/kernel/memory/system_control.h
hle/kernel/mutex.cpp
hle/kernel/mutex.h
hle/kernel/memory_types.h
hle/kernel/object.cpp
hle/kernel/object.h
hle/kernel/physical_core.cpp
@@ -194,10 +215,6 @@ add_library(core STATIC
hle/kernel/process.h
hle/kernel/process_capability.cpp
hle/kernel/process_capability.h
hle/kernel/readable_event.cpp
hle/kernel/readable_event.h
hle/kernel/resource_limit.cpp
hle/kernel/resource_limit.h
hle/kernel/server_port.cpp
hle/kernel/server_port.h
hle/kernel/server_session.cpp
@@ -206,24 +223,15 @@ add_library(core STATIC
hle/kernel/service_thread.h
hle/kernel/session.cpp
hle/kernel/session.h
hle/kernel/shared_memory.cpp
hle/kernel/shared_memory.h
hle/kernel/svc.cpp
hle/kernel/svc.h
hle/kernel/svc_common.h
hle/kernel/svc_types.h
hle/kernel/svc_wrap.h
hle/kernel/synchronization_object.cpp
hle/kernel/synchronization_object.h
hle/kernel/synchronization.cpp
hle/kernel/synchronization.h
hle/kernel/thread.cpp
hle/kernel/thread.h
hle/kernel/time_manager.cpp
hle/kernel/time_manager.h
hle/kernel/transfer_memory.cpp
hle/kernel/transfer_memory.h
hle/kernel/writable_event.cpp
hle/kernel/writable_event.h
hle/lock.cpp
hle/lock.h
hle/result.h
@@ -260,6 +268,7 @@ add_library(core STATIC
hle/service/am/applets/software_keyboard.h
hle/service/am/applets/web_browser.cpp
hle/service/am/applets/web_browser.h
hle/service/am/applets/web_types.h
hle/service/am/idle.cpp
hle/service/am/idle.h
hle/service/am/omm.cpp
@@ -394,14 +403,13 @@ add_library(core STATIC
hle/service/hid/controllers/xpad.h
hle/service/lbl/lbl.cpp
hle/service/lbl/lbl.h
hle/service/ldn/errors.h
hle/service/ldn/ldn.cpp
hle/service/ldn/ldn.h
hle/service/ldr/ldr.cpp
hle/service/ldr/ldr.h
hle/service/lm/lm.cpp
hle/service/lm/lm.h
hle/service/lm/manager.cpp
hle/service/lm/manager.h
hle/service/mig/mig.cpp
hle/service/mig/mig.h
hle/service/mii/manager.cpp
@@ -635,19 +643,22 @@ if (MSVC)
/we4267
# 'context' : truncation from 'type1' to 'type2'
/we4305
# 'function' : not all control paths return a value
/we4715
)
else()
target_compile_options(core PRIVATE
-Werror=conversion
-Werror=ignored-qualifiers
-Werror=implicit-fallthrough
-Werror=reorder
-Werror=sign-compare
-Werror=unused-variable
$<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
-Wno-sign-conversion
)
endif()

View File

@@ -26,9 +26,10 @@ using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CO
/// Generic ARMv8 CPU interface
class ARM_Interface : NonCopyable {
public:
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers, bool uses_wall_clock)
: system{system_}, interrupt_handlers{interrupt_handlers}, uses_wall_clock{
uses_wall_clock} {}
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_,
bool uses_wall_clock_)
: system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
uses_wall_clock_} {}
virtual ~ARM_Interface() = default;
struct ThreadContext32 {

View File

@@ -71,15 +71,9 @@ public:
}
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
switch (exception) {
case Dynarmic::A32::Exception::UndefinedInstruction:
case Dynarmic::A32::Exception::UnpredictableInstruction:
break;
case Dynarmic::A32::Exception::Breakpoint:
break;
}
LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
LOG_CRITICAL(Core_ARM,
"ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
exception, pc, MemoryReadCode(pc), parent.IsInThumbMode());
UNIMPLEMENTED();
}
@@ -181,6 +175,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
}
}
return std::make_unique<Dynarmic::A32::Jit>(config);
@@ -259,6 +256,9 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
if (!jit) {
return;
}
Dynarmic::A32::Context context;
jit->SaveContext(context);
ctx.cpu_registers = context.Regs();
@@ -268,6 +268,9 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
}
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
if (!jit) {
return;
}
Dynarmic::A32::Context context;
context.Regs() = ctx.cpu_registers;
context.ExtRegs() = ctx.extension_registers;

View File

@@ -50,6 +50,10 @@ public:
u64 GetTPIDR_EL0() const override;
void ChangeProcessorID(std::size_t new_core_id) override;
bool IsInThumbMode() const {
return (GetPSTATE() & 0x20) != 0;
}
void SaveContext(ThreadContext32& ctx) override;
void SaveContext(ThreadContext64& ctx) override {}
void LoadContext(const ThreadContext32& ctx) override;

View File

@@ -212,6 +212,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
}
}
return std::make_shared<Dynarmic::A64::Jit>(config);
@@ -291,6 +294,9 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
if (!jit) {
return;
}
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
@@ -302,6 +308,9 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
}
void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
if (!jit) {
return;
}
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);

View File

@@ -28,15 +28,14 @@
#include "core/hardware_interrupt_manager.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/lm/manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/time/time_manager.h"
@@ -293,8 +292,6 @@ struct System::Impl {
perf_stats->GetMeanFrametime());
}
lm_manager.Flush();
is_powered_on = false;
exit_lock = false;
@@ -398,7 +395,6 @@ struct System::Impl {
/// Service State
Service::Glue::ARPManager arp_manager;
Service::LM::Manager lm_manager{reporter};
Service::Time::TimeManager time_manager;
/// Service manager
@@ -720,14 +716,6 @@ const Service::APM::Controller& System::GetAPMController() const {
return impl->apm_controller;
}
Service::LM::Manager& System::GetLogManager() {
return impl->lm_manager;
}
const Service::LM::Manager& System::GetLogManager() const {
return impl->lm_manager;
}
Service::Time::TimeManager& System::GetTimeManager() {
return impl->time_manager;
}

View File

@@ -62,10 +62,6 @@ namespace Glue {
class ARPManager;
}
namespace LM {
class Manager;
} // namespace LM
namespace SM {
class ServiceManager;
} // namespace SM
@@ -351,9 +347,6 @@ public:
[[nodiscard]] Service::APM::Controller& GetAPMController();
[[nodiscard]] const Service::APM::Controller& GetAPMController() const;
[[nodiscard]] Service::LM::Manager& GetLogManager();
[[nodiscard]] const Service::LM::Manager& GetLogManager() const;
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;

View File

@@ -49,6 +49,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) {
Common::SetCurrentThreadPriority(Common::ThreadPriority::VeryHigh);
instance.on_thread_init();
instance.ThreadLoop();
MicroProfileOnThreadExit();
}
void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {

View File

@@ -1,84 +0,0 @@
// Copyright 2008 Dolphin Emulator Project / 2017 Citra Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "core/core_timing_util.h"
#include <cinttypes>
#include <limits>
#include "common/logging/log.h"
#include "common/uint128.h"
#include "core/hardware_properties.h"
namespace Core::Timing {
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / Hardware::BASE_CLOCK_RATE;
s64 msToCycles(std::chrono::milliseconds ms) {
if (static_cast<u64>(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (static_cast<u64>(ms.count()) > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return Hardware::BASE_CLOCK_RATE * (ms.count() / 1000);
}
return (Hardware::BASE_CLOCK_RATE * ms.count()) / 1000;
}
s64 usToCycles(std::chrono::microseconds us) {
if (static_cast<u64>(us.count() / 1000000) > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (static_cast<u64>(us.count()) > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return Hardware::BASE_CLOCK_RATE * (us.count() / 1000000);
}
return (Hardware::BASE_CLOCK_RATE * us.count()) / 1000000;
}
s64 nsToCycles(std::chrono::nanoseconds ns) {
const u128 temporal = Common::Multiply64Into128(ns.count(), Hardware::BASE_CLOCK_RATE);
return Common::Divide128On32(temporal, static_cast<u32>(1000000000)).first;
}
u64 msToClockCycles(std::chrono::milliseconds ns) {
const u128 temp = Common::Multiply64Into128(ns.count(), Hardware::CNTFREQ);
return Common::Divide128On32(temp, 1000).first;
}
u64 usToClockCycles(std::chrono::microseconds ns) {
const u128 temp = Common::Multiply64Into128(ns.count(), Hardware::CNTFREQ);
return Common::Divide128On32(temp, 1000000).first;
}
u64 nsToClockCycles(std::chrono::nanoseconds ns) {
const u128 temp = Common::Multiply64Into128(ns.count(), Hardware::CNTFREQ);
return Common::Divide128On32(temp, 1000000000).first;
}
u64 CpuCyclesToClockCycles(u64 ticks) {
const u128 temporal = Common::Multiply64Into128(ticks, Hardware::CNTFREQ);
return Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
}
std::chrono::milliseconds CyclesToMs(s64 cycles) {
const u128 temporal = Common::Multiply64Into128(cycles, 1000);
u64 ms = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
return std::chrono::milliseconds(ms);
}
std::chrono::nanoseconds CyclesToNs(s64 cycles) {
const u128 temporal = Common::Multiply64Into128(cycles, 1000000000);
u64 ns = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
return std::chrono::nanoseconds(ns);
}
std::chrono::microseconds CyclesToUs(s64 cycles) {
const u128 temporal = Common::Multiply64Into128(cycles, 1000000);
u64 us = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
return std::chrono::microseconds(us);
}
} // namespace Core::Timing

View File

@@ -1,24 +1,59 @@
// Copyright 2008 Dolphin Emulator Project / 2017 Citra Emulator Project
// Licensed under GPLv2+
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <chrono>
#include "common/common_types.h"
#include "core/hardware_properties.h"
namespace Core::Timing {
s64 msToCycles(std::chrono::milliseconds ms);
s64 usToCycles(std::chrono::microseconds us);
s64 nsToCycles(std::chrono::nanoseconds ns);
u64 msToClockCycles(std::chrono::milliseconds ns);
u64 usToClockCycles(std::chrono::microseconds ns);
u64 nsToClockCycles(std::chrono::nanoseconds ns);
std::chrono::milliseconds CyclesToMs(s64 cycles);
std::chrono::nanoseconds CyclesToNs(s64 cycles);
std::chrono::microseconds CyclesToUs(s64 cycles);
namespace detail {
constexpr u64 CNTFREQ_ADJUSTED = Hardware::CNTFREQ / 1000;
constexpr u64 BASE_CLOCK_RATE_ADJUSTED = Hardware::BASE_CLOCK_RATE / 1000;
} // namespace detail
u64 CpuCyclesToClockCycles(u64 ticks);
[[nodiscard]] constexpr s64 msToCycles(std::chrono::milliseconds ms) {
return ms.count() * detail::BASE_CLOCK_RATE_ADJUSTED;
}
[[nodiscard]] constexpr s64 usToCycles(std::chrono::microseconds us) {
return us.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000;
}
[[nodiscard]] constexpr s64 nsToCycles(std::chrono::nanoseconds ns) {
return ns.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000000;
}
[[nodiscard]] constexpr u64 msToClockCycles(std::chrono::milliseconds ms) {
return static_cast<u64>(ms.count()) * detail::CNTFREQ_ADJUSTED;
}
[[nodiscard]] constexpr u64 usToClockCycles(std::chrono::microseconds us) {
return us.count() * detail::CNTFREQ_ADJUSTED / 1000;
}
[[nodiscard]] constexpr u64 nsToClockCycles(std::chrono::nanoseconds ns) {
return ns.count() * detail::CNTFREQ_ADJUSTED / 1000000;
}
[[nodiscard]] constexpr u64 CpuCyclesToClockCycles(u64 ticks) {
return ticks * detail::CNTFREQ_ADJUSTED / detail::BASE_CLOCK_RATE_ADJUSTED;
}
[[nodiscard]] constexpr std::chrono::milliseconds CyclesToMs(s64 cycles) {
return std::chrono::milliseconds(cycles / detail::BASE_CLOCK_RATE_ADJUSTED);
}
[[nodiscard]] constexpr std::chrono::nanoseconds CyclesToNs(s64 cycles) {
return std::chrono::nanoseconds(cycles * 1000000 / detail::BASE_CLOCK_RATE_ADJUSTED);
}
[[nodiscard]] constexpr std::chrono::microseconds CyclesToUs(s64 cycles) {
return std::chrono::microseconds(cycles * 1000 / detail::BASE_CLOCK_RATE_ADJUSTED);
}
} // namespace Core::Timing

View File

@@ -11,9 +11,9 @@
#include "core/core_timing.h"
#include "core/cpu_manager.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/thread.h"
#include "video_core/gpu.h"
namespace Core {
@@ -147,7 +147,7 @@ void CpuManager::MultiCoreRunSuspendThread() {
while (true) {
auto core = kernel.GetCurrentHostThreadID();
auto& scheduler = *kernel.CurrentScheduler();
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.GetCurrentHostThreadID());
@@ -208,7 +208,6 @@ void CpuManager::SingleCoreRunGuestThread() {
void CpuManager::SingleCoreRunGuestLoop() {
auto& kernel = system.Kernel();
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
while (true) {
auto* physical_core = &kernel.CurrentPhysicalCore();
system.EnterDynarmicProfile();
@@ -217,9 +216,9 @@ void CpuManager::SingleCoreRunGuestLoop() {
physical_core = &kernel.CurrentPhysicalCore();
}
system.ExitDynarmicProfile();
thread->SetPhantomMode(true);
kernel.SetIsPhantomModeForSingleCore(true);
system.CoreTiming().Advance();
thread->SetPhantomMode(false);
kernel.SetIsPhantomModeForSingleCore(false);
physical_core->ArmInterface().ClearExclusiveState();
PreemptSingleCore();
auto& scheduler = kernel.Scheduler(current_core);
@@ -245,7 +244,7 @@ void CpuManager::SingleCoreRunSuspendThread() {
while (true) {
auto core = kernel.GetCurrentHostThreadID();
auto& scheduler = *kernel.CurrentScheduler();
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.GetCurrentHostThreadID());
@@ -255,22 +254,23 @@ void CpuManager::SingleCoreRunSuspendThread() {
void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
{
auto& scheduler = system.Kernel().Scheduler(current_core);
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
auto& kernel = system.Kernel();
auto& scheduler = kernel.Scheduler(current_core);
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
if (idle_count >= 4 || from_running_enviroment) {
if (!from_running_enviroment) {
system.CoreTiming().Idle();
idle_count = 0;
}
current_thread->SetPhantomMode(true);
kernel.SetIsPhantomModeForSingleCore(true);
system.CoreTiming().Advance();
current_thread->SetPhantomMode(false);
kernel.SetIsPhantomModeForSingleCore(false);
}
current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
system.CoreTiming().ResetTicks();
scheduler.Unload(scheduler.GetCurrentThread());
auto& next_scheduler = system.Kernel().Scheduler(current_core);
auto& next_scheduler = kernel.Scheduler(current_core);
Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
}
@@ -278,8 +278,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
{
auto& scheduler = system.Kernel().Scheduler(current_core);
scheduler.Reload(scheduler.GetCurrentThread());
auto* currrent_thread2 = scheduler.GetCurrentThread();
if (!currrent_thread2->IsIdleThread()) {
if (!scheduler.IsIdle()) {
idle_count = 0;
}
}

View File

@@ -143,6 +143,7 @@ u64 GetSignatureTypeDataSize(SignatureType type) {
return 0x3C;
}
UNREACHABLE();
return 0;
}
u64 GetSignatureTypePaddingSize(SignatureType type) {
@@ -157,6 +158,7 @@ u64 GetSignatureTypePaddingSize(SignatureType type) {
return 0x40;
}
UNREACHABLE();
return 0;
}
SignatureType Ticket::GetSignatureType() const {
@@ -169,8 +171,7 @@ SignatureType Ticket::GetSignatureType() const {
if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
return ticket->sig_type;
}
UNREACHABLE();
throw std::bad_variant_access{};
}
TicketData& Ticket::GetData() {
@@ -183,8 +184,7 @@ TicketData& Ticket::GetData() {
if (auto* ticket = std::get_if<ECDSATicket>(&data)) {
return ticket->data;
}
UNREACHABLE();
throw std::bad_variant_access{};
}
const TicketData& Ticket::GetData() const {
@@ -197,8 +197,7 @@ const TicketData& Ticket::GetData() const {
if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
return ticket->data;
}
UNREACHABLE();
throw std::bad_variant_access{};
}
u64 Ticket::GetSize() const {
@@ -569,6 +568,11 @@ KeyManager::KeyManager() {
// Initialize keys
const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath();
const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
if (!Common::FS::Exists(yuzu_keys_dir)) {
Common::FS::CreateDir(yuzu_keys_dir);
}
if (Settings::values.use_dev_keys) {
dev_mode = true;
AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false);

View File

@@ -43,17 +43,17 @@ static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size.");
struct IVFCHeader {
u32_le magic;
u32_le magic_number;
INSERT_UNION_PADDING_BYTES(8);
INSERT_PADDING_BYTES_NOINIT(8);
std::array<IVFCLevel, 6> levels;
INSERT_UNION_PADDING_BYTES(64);
INSERT_PADDING_BYTES_NOINIT(64);
};
static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size.");
struct NCASectionHeaderBlock {
INSERT_UNION_PADDING_BYTES(3);
INSERT_PADDING_BYTES_NOINIT(3);
NCASectionFilesystemType filesystem_type;
NCASectionCryptoType crypto_type;
INSERT_UNION_PADDING_BYTES(3);
INSERT_PADDING_BYTES_NOINIT(3);
};
static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size.");
@@ -61,7 +61,7 @@ struct NCASectionRaw {
NCASectionHeaderBlock header;
std::array<u8, 0x138> block_data;
std::array<u8, 0x8> section_ctr;
INSERT_UNION_PADDING_BYTES(0xB8);
INSERT_PADDING_BYTES_NOINIT(0xB8);
};
static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size.");
@@ -69,19 +69,19 @@ struct PFS0Superblock {
NCASectionHeaderBlock header_block;
std::array<u8, 0x20> hash;
u32_le size;
INSERT_UNION_PADDING_BYTES(4);
INSERT_PADDING_BYTES_NOINIT(4);
u64_le hash_table_offset;
u64_le hash_table_size;
u64_le pfs0_header_offset;
u64_le pfs0_size;
INSERT_UNION_PADDING_BYTES(0x1B0);
INSERT_PADDING_BYTES_NOINIT(0x1B0);
};
static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size.");
struct RomFSSuperblock {
NCASectionHeaderBlock header_block;
IVFCHeader ivfc;
INSERT_UNION_PADDING_BYTES(0x118);
INSERT_PADDING_BYTES_NOINIT(0x118);
};
static_assert(sizeof(RomFSSuperblock) == 0x200, "RomFSSuperblock has incorrect size.");
@@ -89,19 +89,19 @@ struct BKTRHeader {
u64_le offset;
u64_le size;
u32_le magic;
INSERT_UNION_PADDING_BYTES(0x4);
INSERT_PADDING_BYTES_NOINIT(0x4);
u32_le number_entries;
INSERT_UNION_PADDING_BYTES(0x4);
INSERT_PADDING_BYTES_NOINIT(0x4);
};
static_assert(sizeof(BKTRHeader) == 0x20, "BKTRHeader has incorrect size.");
struct BKTRSuperblock {
NCASectionHeaderBlock header_block;
IVFCHeader ivfc;
INSERT_UNION_PADDING_BYTES(0x18);
INSERT_PADDING_BYTES_NOINIT(0x18);
BKTRHeader relocation;
BKTRHeader subsection;
INSERT_UNION_PADDING_BYTES(0xC0);
INSERT_PADDING_BYTES_NOINIT(0xC0);
};
static_assert(sizeof(BKTRSuperblock) == 0x200, "BKTRSuperblock has incorrect size.");

View File

@@ -51,8 +51,8 @@ std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, const BlockTyp
low = mid + 1;
}
}
UNREACHABLE_MSG("Offset could not be found in BKTR block.");
return {0, 0};
}
} // Anonymous namespace

View File

@@ -105,7 +105,8 @@ ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
// TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal.
return ContentRecordType::HtmlDocument;
default:
UNREACHABLE_MSG("Invalid NCAContentType={:02X}", static_cast<u8>(type));
UNREACHABLE_MSG("Invalid NCAContentType={:02X}", type);
return ContentRecordType{};
}
}

View File

@@ -67,18 +67,18 @@ public:
virtual void Refresh() = 0;
virtual bool HasEntry(u64 title_id, ContentRecordType type) const = 0;
virtual bool HasEntry(ContentProviderEntry entry) const;
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;
VirtualFile GetEntryUnparsed(ContentProviderEntry entry) const;
virtual VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const = 0;
virtual VirtualFile GetEntryRaw(ContentProviderEntry entry) const;
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;
std::unique_ptr<NCA> GetEntry(ContentProviderEntry entry) const;
virtual std::vector<ContentProviderEntry> ListEntries() const;

View File

@@ -58,7 +58,7 @@ struct SaveDataAttribute {
SaveDataType type;
SaveDataRank rank;
u16 index;
INSERT_PADDING_BYTES(4);
INSERT_PADDING_BYTES_NOINIT(4);
u64 zero_1;
u64 zero_2;
u64 zero_3;
@@ -72,7 +72,7 @@ struct SaveDataExtraData {
u64 owner_id;
s64 timestamp;
SaveDataFlags flags;
INSERT_PADDING_BYTES(4);
INSERT_PADDING_BYTES_NOINIT(4);
s64 available_size;
s64 journal_size;
s64 commit_id;

View File

@@ -133,8 +133,11 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
}
cache.erase(old_path);
file->Open(new_path, "r+b");
cache.insert_or_assign(new_path, std::move(file));
if (file->Open(new_path, "r+b")) {
cache.insert_or_assign(new_path, std::move(file));
} else {
LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", new_path);
}
} else {
UNREACHABLE();
return nullptr;
@@ -214,9 +217,12 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
}
auto file = cached.lock();
file->Open(file_new_path, "r+b");
cache.erase(file_old_path);
cache.insert_or_assign(std::move(file_new_path), std::move(file));
if (file->Open(file_new_path, "r+b")) {
cache.insert_or_assign(std::move(file_new_path), std::move(file));
} else {
LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", file_new_path);
}
}
return OpenDirectory(new_path, Mode::ReadWrite);

View File

@@ -31,6 +31,7 @@ struct ControllerParameters {
bool allow_dual_joycons{};
bool allow_left_joycon{};
bool allow_right_joycon{};
bool allow_gamecube_controller{};
};
class ControllerApplet {

View File

@@ -21,21 +21,18 @@ public:
std::mutex mutex;
bool touch_pressed = false; ///< True if touchpad area is currently pressed, otherwise false
float touch_x = 0.0f; ///< Touchpad X-position
float touch_y = 0.0f; ///< Touchpad Y-position
Input::TouchStatus status;
private:
class Device : public Input::TouchDevice {
public:
explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {}
std::tuple<float, float, bool> GetStatus() const override {
Input::TouchStatus GetStatus() const override {
if (auto state = touch_state.lock()) {
std::lock_guard guard{state->mutex};
return std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed);
return state->status;
}
return std::make_tuple(0.0f, 0.0f, false);
return {};
}
private:
@@ -79,36 +76,44 @@ std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsi
return std::make_tuple(new_x, new_y);
}
void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) {
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) {
return;
}
if (id >= touch_state->status.size()) {
return;
}
std::lock_guard guard{touch_state->mutex};
touch_state->touch_x =
const float x =
static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
touch_state->touch_y =
const float y =
static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
touch_state->touch_pressed = true;
touch_state->status[id] = std::make_tuple(x, y, true);
}
void EmuWindow::TouchReleased() {
void EmuWindow::TouchReleased(std::size_t id) {
if (id >= touch_state->status.size()) {
return;
}
std::lock_guard guard{touch_state->mutex};
touch_state->touch_pressed = false;
touch_state->touch_x = 0;
touch_state->touch_y = 0;
touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false);
}
void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
if (!touch_state->touch_pressed)
void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) {
if (id >= touch_state->status.size()) {
return;
}
if (!std::get<2>(touch_state->status[id]))
return;
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
TouchPressed(framebuffer_x, framebuffer_y);
TouchPressed(framebuffer_x, framebuffer_y, id);
}
void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {

View File

@@ -117,18 +117,23 @@ public:
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
* @param framebuffer_x Framebuffer x-coordinate that was pressed
* @param framebuffer_y Framebuffer y-coordinate that was pressed
* @param id Touch event ID
*/
void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y);
void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id);
/// Signal that a touch released event has occurred (e.g. mouse click released)
void TouchReleased();
/**
* Signal that a touch released event has occurred (e.g. mouse click released)
* @param id Touch event ID
*/
void TouchReleased(std::size_t id);
/**
* Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window)
* @param framebuffer_x Framebuffer x-coordinate
* @param framebuffer_y Framebuffer y-coordinate
* @param id Touch event ID
*/
void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y);
void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id);
/**
* Returns currently active configuration.

View File

@@ -21,6 +21,11 @@ enum class AnalogDirection : u8 {
UP,
DOWN,
};
struct AnalogProperties {
float deadzone;
float range;
float threshold;
};
/// An abstract class template for an input device (a button, an analog input, etc.).
template <typename StatusType>
@@ -30,6 +35,12 @@ public:
virtual StatusType GetStatus() const {
return {};
}
virtual StatusType GetRawStatus() const {
return GetStatus();
}
virtual AnalogProperties GetAnalogProperties() const {
return {};
}
virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
return {};
}
@@ -163,10 +174,11 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common
using MotionDevice = InputDevice<MotionStatus>;
/**
* A touch status is an object that returns a tuple of two floats and a bool. The floats are
* x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed.
* A touch status is an object that returns an array of 16 tuple elements of two floats and a bool.
* The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is
* pressed.
*/
using TouchStatus = std::tuple<float, float, bool>;
using TouchStatus = std::array<std::tuple<float, float, bool>, 16>;
/**
* A touch device is an input device that returns a touch status object

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