Compare commits

...

67 Commits

Author SHA1 Message Date
458452279c GPU: Track buffer migrations and flush source on incomplete copy (#3952)
* Track buffer migrations and flush source on incomplete copy

Makes sure that the modified range list is always from the latest iteration of the buffer, and flushes earlier iterations of a buffer if the data has not been migrated yet.

* Cleanup 1

* Reduce cost for redundant signal checks on Vulkan

* Only inherit the range list if there are pending ranges.

* Fix OpenGL

* Address Feedback

* Whoops
2022-12-01 16:30:13 +01:00
817b89767a infra: Add distribution files for macOS (#3934)
This upstream macOS packing and distribution files
2022-12-01 14:08:43 +01:00
3fb583c98c Avalonia: Clean up leftover RenderTimer & Fix minimum and initial window size (#3935)
* ava: Cleanup RenderTimer

* ava: Remove ContentControl from RendererHost

* ava: Remove unused actual scale factor

* ava: Enable UseGpu for Linux

* ava: Set better initial size & Scale the window properly

* ava: Realign properties

* ava: Use explicit type & specify where the note applies
2022-11-30 23:34:25 +01:00
d2686e0a5b nuget: bump DiscordRichPresence from 1.0.175 to 1.1.3.18 (#3965)
Bumps [DiscordRichPresence](https://github.com/Lachee/discord-rpc-csharp) from 1.0.175 to 1.1.3.18.
- [Release notes](https://github.com/Lachee/discord-rpc-csharp/releases)
- [Commits](https://github.com/Lachee/discord-rpc-csharp/commits)

---
updated-dependencies:
- dependency-name: DiscordRichPresence
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-30 21:58:45 +00:00
4905101df1 Remove shader dependency on SPV_KHR_shader_ballot and SPV_KHR_subgroup_vote extensions (#3943)
* Remove shader dependency on SPV_KHR_shader_ballot and SPV_KHR_subgroup_vote extensions

* Shader cache version bump
2022-11-30 18:24:15 -03:00
8750b90a7f Ensure that vertex attribute buffer index is valid on GPU (#3942)
* Ensure that vertex attribute buffer index is valid on GPU

* Remove vertex buffer validation code from OpenGL

* Remove some fields that are no longer necessary
2022-11-30 18:06:40 -03:00
af01100050 nuget: bump System.Management from 6.0.0 to 7.0.0 (#3949)
Bumps [System.Management](https://github.com/dotnet/runtime) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v6.0.0...v7.0.0)

---
updated-dependencies:
- dependency-name: System.Management
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-29 23:30:33 +01:00
c0821fee1f Update README.MD (#3946)
Updates the readme to include usage of Metal via MoltenVK, updated game compatibility statistics.
2022-11-29 17:20:26 +01:00
a5c2aead67 ConcurrentBitmap: Use Interlocked Or/And (#3937) 2022-11-29 13:47:57 +00:00
d41c95dcff chore: Update OpenTK to 4.7.5 (#3944) 2022-11-29 13:32:40 +00:00
fbf2b09706 ava: Make dialogs using an overlay window work on Linux (#3938) 2022-11-29 06:33:46 +01:00
1fc0f569de GPU: Always draw polygon topology as triangle fan (#3932)
Polygon topology wasn't really supported and would only work on OpenGL on drivers that haven't removed it. As an alternative, this PR makes all cases of polygon topology use triangle fan. The topology type and transform feedback type have not been changed, as I don't think geo shader/tfb should be used with polygons.

The OpenGL spec states:
Only convex polygons are guaranteed to be drawn correctly by the GL.

For convex polygons, triangle fan is equivalent to polygon. I imagine this is probably how it works on device, as this get-out-of-jail-free card is too enticing to pass up.

This fixes the stat display in Pokemon S/V.
2022-11-28 19:18:22 -03:00
dff138229c amadeus: Fixes and initial 15.0.0 support (#3908)
* amadeus: Allow OOB read of GC-ADPCM coefficients

Fixes "Ninja Gaiden Sigma 2" and possibly "NINJA GAIDEN 3: Razor's Edge"

* amadeus: Fix wrong variable usage in delay effect

We should transform the delay line values, not the input.

* amadeus: Update GroupedBiquadFilterCommand documentation

* amadeus: Simplify PoolMapper alignment checks

* amadeus: Update Surround delay effect matrix to REV11

* amadeus: Add drop parameter support and use 32 bits integers for estimate time

Also implement accurate ExecuteAudioRendererRendering stub.

* Address gdkchan's comments

* Address gdkchan's other comments

* Address gdkchan's comment
2022-11-28 08:28:45 +01:00
472119c8da sfdnsres; Fix deserializer of AddrInfoSerialized when addresses are empty (#3924) 2022-11-28 02:53:57 +01:00
1865ea87e5 bsd: Fix eventfd broken logic (#3647)
* bsd: Fix eventfd broken logic

This commit fix eventfd logic being broken.

The following changes were made:
- EventFd IPC definition had argument inverted
- EventFd events weren't fired correctly
- Poll logic was wrong and unfinished for eventfd
- Reintroduce workaround from #3385 but in a safer way, and spawn 4
  threads.

* ipc: Rework a bit for multithreads

* Clean up debug logs

* Make server thread yield when managed lock isn't availaible

* Fix replyTargetHandle not being added in the proper locking scope

* Simplify some scopes

* Address gdkchan's comments

* Revert IPC workaround for now

* Reintroduce the EventFileDescriptor workaround
2022-11-27 20:18:05 +00:00
18b61aff59 Unbreak bug_report.md (#3915)
* Unbreak bug_report.md

* Update bug_report.md
2022-11-27 20:11:51 +00:00
cb22629ac1 HLE: fix small issue in IPsmSession (#3909) 2022-11-27 01:10:42 +00:00
6f0f99ee2b Avalonia: Fix OpenGL crashing on Linux (#3902)
* ava: Fix OpenGL crashing on Linux

Fixes a regression from #3901

* Fix formatting
2022-11-26 12:06:53 +01:00
70f2da8fdf ava: Fix invisible vulkan window on Linux (#3901)
Co-authored-by: emmauss <emmausssss@gmail.com>

Co-authored-by: emmauss <emmausssss@gmail.com>
2022-11-25 17:40:44 +00:00
5d3ef7761b ava: Refactor Title Update Manager window (#3898)
* ava: Refactor TitleUpdate Manager window

* Update locale
2022-11-25 17:55:08 +01:00
476b4683cf Fix CB0 alignment with addresses used for 8/16-bit LDG/STG (#3897)
This replacement is meant to be done with the original identified byteOffset, not the one assigned later on by the below conditionals (that already has the constant offset added, for instance).

This fixes videos being pixelated in Xenoblade 3, and other regressions that might have happened since #3847.
2022-11-25 14:39:03 +00:00
5fb5079730 chore: Update Avalonia related dependencies (#3891) 2022-11-25 13:27:41 +00:00
3fbacd0f49 ava: Rework DLC Manager, Add various fixes and cleanup (#3896)
* Fixes Everything Part.2

* Change sorting, fix remove and heading
2022-11-25 12:41:34 +01:00
7aa6abc120 nuget: bump SharpZipLib from 1.3.3 to 1.4.1 (#3893)
Bumps [SharpZipLib](https://github.com/icsharpcode/SharpZipLib) from 1.3.3 to 1.4.1.
- [Release notes](https://github.com/icsharpcode/SharpZipLib/releases)
- [Changelog](https://github.com/icsharpcode/SharpZipLib/blob/master/docs/Changes.txt)
- [Commits](https://github.com/icsharpcode/SharpZipLib/compare/v1.3.3...v1.4.1)

---
updated-dependencies:
- dependency-name: SharpZipLib
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-24 20:30:17 +01:00
548bfd60a2 chore: Update Ryujinx.SDL2-CS to 2.24.2 (#3892)
* chore: Update Ryujinx.SDL2-CS to 2.24.2

* Disable SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS
2022-11-24 20:13:16 +01:00
65778a6b78 GPU: Don't trigger uploads for redundant buffer updates (#3828)
* Initial implementation

* Actually do The Thing

* Add remark about performance to IVirtualMemoryManager
2022-11-24 15:50:15 +01:00
f4e879a1e6 Reduce usage of Marshal.PtrToStructure and Marshal.StructureToPtr (#3805)
* common: Make BinaryReaderExtensions Read & Write take unamanged types

This allows us to not rely on Marshal.PtrToStructure and Marshal.StructureToPtr for those.

* common: Make MemoryHelper Read & Write takes unamanged types

* Update Marshal.SizeOf => Unsafe.SizeOf when appropriate and start moving software applet to unmanaged types
2022-11-24 15:26:29 +01:00
a1ddaa2736 ui: Fixes disposing on GTK/Avalonia and Firmware Messages on Avalonia (#3885)
* ui: Only wait on _exitEvent when MainLoop is active under GTK

This fixes a dispose issue under Horizon/GTK, we don't check if the ApplicationClient is null so it throw NCE. We don't check if the main loop is active and waiting an event which is set in the main loop... So that could lead to a freeze.

Everything works fine in GTK now.

Related issue: https://github.com/Ryujinx/Ryujinx/issues/3873

As a side note, same kind of issue appear in Avalonia UI too. Firmware's popup doesn't show anything and the emulator just freeze.

* TSRBerry's change

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Fix Avalonia crashing/freezing

* Add Avalonia OpenGL fixes

* Fix firmware popup on windows

* Fixes everything

* Add _initialized bool to VulkanRenderer and OpenGL Window

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
2022-11-24 15:08:27 +01:00
008286b79f Ryujinx.Ava: Add missing redefinition of app name (#3890)
Before this, Ryujinx would possibly report as "Avalonia Application".
2022-11-24 14:52:39 +01:00
a0c77f8d11 Fix NRE on Avalonia for error applets with unknown error message (#3888) 2022-11-24 09:31:00 +01:00
ece36b274d GAL: Send all buffer assignments at once rather than individually (#3881)
* GAL: Send all buffer assignments at once rather than individually

The `(int first, BufferRange[] ranges)` method call has very significant performance implications when the bindings are spread out, which they generally always are in Vulkan. This change makes it so that these methods are only called a maximum of one time per draw.

Significantly improves GPU thread performance in Pokemon Scarlet/Violet.

* Address Feedback

Removed SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers)
2022-11-24 07:50:59 +00:00
f3cc2e5703 GPU: Access non-prefetch command buffers directly (#3882)
* GPU: Access non-prefetch command buffers directly

Saves allocating new arrays for them constantly - they can be quite small so it can be very wasteful. About 0.4% of GPU thread in SMO, but was a bit higher in S/V when I checked.

Assumes that non-prefetch command buffers won't be randomly clobbered before they finish executing, though that's probably a safe bet.

* Small change while I'm here

* Address feedback
2022-11-24 01:56:55 +00:00
5a39d3c4a1 GPU: Relax locking on Buffer Cache (#3883)
I did this on ncbuffer2 when we were using it for LDN 3, but I noticed that it can apply to the current buffer manager too, and it's an easy performance win.

The only buffer access that can come from another thread is the overlap search for buffers that have been unmapped. Everything else, including modifications, come from the main GPU thread. That means we only need to lock the range list when it's being modified, as that's the only time where we'll cause a race with the unmapped handler.

This has a significant performance improvements in situations where FIFO is high, like the other two PRs. Joined together they give a nice boost (73.6 master -> 79 -> 83 fps in SMO).
2022-11-24 01:41:16 +00:00
cc51a03af9 nuget: bump Avalonia from 0.10.15 to 0.10.18 (#3817)
Bumps [Avalonia](https://github.com/AvaloniaUI/Avalonia) from 0.10.15 to 0.10.18.
- [Release notes](https://github.com/AvaloniaUI/Avalonia/releases)
- [Commits](https://github.com/AvaloniaUI/Avalonia/compare/0.10.15...0.10.18)

---
updated-dependencies:
- dependency-name: Avalonia
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-24 01:26:53 +00:00
567c64e149 ava: Fix JsonSerializer warnings (#3884)
Since we move to .NET7, JsonSerializer now needs to have explicit options as arguments, which leads to some warnings in Avalonia project. This is fixed by using our `JsonHelper` class.
2022-11-23 17:55:26 +00:00
36f00985d3 Update to LibHac 0.17.0 (#3878)
* Update to LibHac 0.17.0

* Don't clear SD card saves when starting the emulator

This was an old workaround for errors that happened when a user's SD card encryption seed changed. SD card saves have been unencrypted for over a year, so we should be fine to remove the workaround.
2022-11-23 18:32:35 +01:00
748d87adcc Stub IFriendService: 1 (Cancel) (#3841)
* Add friend/Cancel. Closes #3824

* Update according to review comments.

* Add comment base on request

* Update Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2022-11-23 16:25:49 +01:00
0fd47ff490 remove redundant logs (#3877) 2022-11-23 11:28:46 +01:00
f088c3d344 Do not update shader state for DrawTextures (#3876) 2022-11-21 18:16:00 +01:00
905a191e28 Use upstream unicorn for Ryujinx.Tests.Unicorn (#3771)
* unicorn: Add modified ver of unicorns const gen

* unicorn: Use upstream consts

These consts were generated from the dev branch of unicorn

* unicorn: Split common consts into multiple enums

* unicorn: Remove arch prefix from consts

* unicorn: Add new windows dll

Windows 10 - MSVC x64 shared build

* unicorn: Use absolute path for const generation

* unicorn: Remove fspcr patch

* unicorn: Fix using the wrong file extension

For some reason _NativeLibraryExtension evaluates to ".so" even on Windows.

* unicorn: Add linux shared object again

* unicron: Add DllImportResolver

* unicorn: Try to import unicorn using an absolute path

* unicorn: Add clean target

* unicorn: Replace IsUnicornAvailable() methods

* unicorn: Skip tests instead of silently passing them if unicorn is missing

* unicorn: Write error message to stderr

* unicorn: Make Interface static

* unicron: Include prefixed unicorn libs (libunicorn.so)

Co-authored-by: merry <git@mary.rs>

* unicorn: Add lib prefix to shared object for linux

Co-authored-by: merry <git@mary.rs>
2022-11-20 20:18:21 +01:00
ab0491817e Reword the description of the 6GB expand DRAM hack to be less tantalizing (#3870)
* Reword the hack to something less tantalizing

* Address feedback
2022-11-20 17:15:57 +00:00
5de6ae426e Unsubscribe MemoryUnmappedHandler even when GPU channel is destroyed (#3872) 2022-11-19 23:54:33 -03:00
69ced3a6e8 Fix shader cache on Vulkan when geometry shaders are inserted (#3868) 2022-11-19 10:24:23 +01:00
2e43d01d36 Move gl_Layer from vertex to geometry if GPU does not support it on vertex (#3866)
* Move gl_Layer from vertex to geometry if GPU does not support it on vertex

* Shader cache version bump

* PR feedback
2022-11-18 23:27:54 -03:00
7373ec5792 Vulkan: Clear dummy texture to (0,0,0,0) on creation (#3867)
This might fix an issue with AMD gpus on linux where the data could contain random garbage data. On the switch, it always samples as 0.
2022-11-18 23:11:34 -03:00
de162a648b Gpu: Fix thread safety of ReregisterRanges (#3865)
A quick fix to prevent reading the wrong value of Count when reregistering ranges for a new target buffer. Buffer flushes from another thread can modify the range list when the lock isn't active, which can change the count.

This prevents some crashes in Pokemon Scarlet/Violet. It's probably likely that buffer migration during flush is causing some other issues in this game, but this at least prevents the crashing.
2022-11-18 21:47:29 +01:00
131baebe2a Vulkan: Don't create preload command buffer outside a render pass (#3864)
* Vulkan: Don't create preload buffer outside a render pass

The preload command buffer is used to avoid render pass splits and barriers when updating buffer data. However, when a render pass is not active (for example, at the start of a pass, or during compute invocations) buffer uploads can be performed at any time, so the optimization isn't as useful.

This PR makes it so that the preload command buffer is only used for buffer updates outside of a render pass. It's still used for textures as I don't want to shake things up right now regarding how the preload buffer is obtained before some other changes, and texture updates are a lot rarer anyways.

Improves performance slightly in Pokemon Scarlet/Violet (43 -> 48), as it was switching to compute, writing a bunch of buffers inline, then dispatching, then flushing commands... It uses 1 command buffer instead of 2 every time it does this now. Maybe it would be nice to find a faster way to sync without creating so many command buffers in a short period of time.

* Address feedback
2022-11-18 14:58:56 +00:00
187372cbde Prune ForceDirty and CheckModified caches on unmap (#3862)
* Prune ForceDirty and CheckModified caches on unmap

Since we're now using this for modified checks on the HLE indirect draw method, I'm worried that leaving these to forever gather cache entries isn't the best idea for performance in the long term, and it could keep old buffer objects alive for longer than they should be.

This PR adds the ability to prune invalid entries before checking these caches, and queues it whenever gpu memory is unmapped. It also aligns modified checks to the page size, as I figured it would be possible for a huge number of overlapping over a game's runtime.

This prevents Super Mario Odyssey from having 10s of thousands of entries in the modified cache in Metro Kingdom, and them duplicating when entering and leaving a building (should be cleared, as they were unmapped).

* Address Feedback
2022-11-18 14:58:24 +00:00
022d495335 am: Stub GetSaveDataSizeMax (#3857)
* am: Stub GetSaveDataSizeMax()

* am: Remove todo comment for GetSaveDataSizeMax()

* am: saveDataSize & journalDataSize should be of type long

* am: Add explanation for returning default values in GetSaveDataSizeMax()
2022-11-18 03:29:01 +00:00
c1372ed775 Use ReadOnlySpan<byte> compiler optimization in more places (#3853)
* Use ReadOnlySpan<byte> compiler optimization in more places

* Revert changes in ShaderBinaries.cs

* Remove unused using;

* Use ReadOnlySpan<byte> compiler optimization in more places
2022-11-18 03:10:44 +00:00
a16682cfd3 Allow _volatile to be set from MultiRegionHandle checks again (#3830)
* Allow _volatile to be set from MultiRegionHandle checks again

Tracking handles have a `_volatile` flag which indicates that the resource being tracked is modified every time it is used under a new sequence number. This is used to reduce the time spent reprotecting memory for tracking writes to commonly modified buffers, like constant buffers.

This optimisation works by detecting if a buffer is modified every time a check happens. If a buffer is checked but it is not dirty, then that data is likely not modified every sequence number, and should use memory protection for write tracking. If the opposite is the case all the time, it is faster to just assume it's dirty as we'd just be wasting time protecting the memory.

The new MultiRegionBitmap could not notify handles that they had been checked as part of the fast bitmap lookup, so bindings larger than 4096 bytes wouldn't trigger it at all. This meant that they would be subject to a ton of reprotection if they were modified often.

This does mean there are two separate sources for a _volatile set: VolatileOrDirty + _checkCount, and the bitmap check. These shouldn't interfere with each other, though.

This fixes performance regressions from #3775 in Pokemon Sword, and hopefully Yu-Gi-Oh! RUSH DUEL: Dawn of the Battle Royale. May affect other games.

* Fix stupid mistake
2022-11-18 02:54:20 +00:00
7c53b69c30 SPIR-V: Fix unscaling helper not being able to find Array textures (#3863)
The type in the `texOp` in the textureSize instruction doesn't have the exact type on SPIR-V (for example, it is missing the Array flag). This PR gives it the proper type before giving it to the unscaling helper.

This fixes the ground textures being broken on Pokemon Scarlet/Violet when scaling. It wasn't finding the texture, so the descriptor index it provided was -1...
2022-11-18 02:37:37 +00:00
33a4d7d1ba GPU: Eliminate CB0 accesses when storage buffer accesses are resolved (#3847)
* Eliminate CB0 accesses

Still some work to do, decouple from hle?

* Forgot the important part somehow

* Fix and improve alignment test

* Address Feedback

* Remove some complexity when checking storage buffer alignment

* Update Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2022-11-17 18:47:41 +01:00
391e08dd27 ci: Clean up Actions leftovers (#3859)
As title say.

Fix Avalonia build versions for PRs.

Also ensure that the --self-contained doesn't warn at build.
2022-11-17 18:30:54 +01:00
b5cf8b8af9 Capitalization to be consistent (#3860)
Thread ID Register, Floating-point Control Register, and Floating-point Status Register all had Register capitalized, so the Register in Processor State register should be capitalized.
2022-11-17 18:13:37 +01:00
55043c8afc Allow to start Ryujinx in wayland environment (#3516)
PrimaryMonitor is only available on X11

At some point it will be deprecated, this change support wayland
2022-11-17 13:02:43 +01:00
5d73a9f5fc Fix Fedora support (#3815)
For some reasons, my fresh installation of Fedora 36 (KDE) doesn't have a
symlink for libX11.so.

This commit fixes this by trying to import the library with its major
version or fallback to the normal way.
2022-11-17 00:18:29 +01:00
2c9ab5e45f Prevent raw Unicode control codes from showing on software keyboard applet. (#3845)
* Revert "Add support for releasing a semaphore to DmaClass (#2926)"

This reverts commit 521a07e612.

* Revert "Revert "Add support for releasing a semaphore to DmaClass (#2926)""

This reverts commit ec8a5fd053.

* Strip non-visible control codes from strings before they are sent to the software keyboard to prevent ugly unicode blocks from being shown on the UI.

* remove debugging junk

* Initialize stringbuilder capacity at the start to prevent resizing (a tiny tiny microoptimization)

* Update remarks documentation. Remove unneeded imports.

* Removing a test that's actually just redundant

Co-authored-by: Logan Stromberg <lostromb@microsoft.com>
2022-11-16 23:53:17 +01:00
d536cc8ae6 Update units of memory from decimal to binary prefixes (#3716)
`MB` and `GB` can either be interpreted as having base-10 units, or
base-2. `MiB` and `GiB` removes this discrepancy so that units of memory
are always interpreted using base-2 units.
2022-11-16 23:27:42 +01:00
d751da84f9 Use new C# 11 u8 string literals (#3854) 2022-11-16 16:30:12 -03:00
11aae9cfbc Make use of Random.Shared (#3852) 2022-11-16 15:34:18 -03:00
b96794e72b Use new LINQ Order() methods (#3851) 2022-11-16 15:17:03 -03:00
f1d1670b0b Implement HLE macro for DrawElementsIndirect (#3748)
* Implement HLE macro for DrawElementsIndirect

* Shader cache version bump

* Use GL_ARB_shader_draw_parameters extension on OpenGL

* Fix DrawIndexedIndirectCount on Vulkan when extension is not supported

* Implement DrawIndex

* Alignment

* Fix some validation errors

* Rename BaseIds to DrawParameters

* Fix incorrect index buffer and vertex buffer size in some cases

* Add HLE macros for DrawArraysInstanced and DrawElementsInstanced

* Perform a regular draw when indirect data is not modified

* Use non-indirect draw methods if indirect buffer was not GPU modified

* Only check if draw parameters match if the shader actually uses them

* Expose Macro HLE setting on GUI

* Reset FirstVertex and FirstInstance after draw

* Update shader cache version again since some people already tested this

* PR feedback

Co-authored-by: riperiperi <rhy3756547@hotmail.com>
2022-11-16 14:53:04 -03:00
b8de72de8f It's REE-YOU-JINX (#3839) 2022-11-15 22:19:25 +01:00
eebc39228d UI: Allow overriding graphics backend + Move command line parser into a new class (#3707)
* Ava: Keep command line args when restarting

* UI: Move common UI functions to ProgramHelper

Add command line option to override the configured graphics backend

* Ava: Add CleanupUpdate task back

* Remove unused usings

* Revert combining common UI functions

Rename ProgramHelper to CommandLineState
Move command line parsing to CommandLineState

* Rename CommandLineProfile to Profile

* Fix assigning the wrong array to Arguments
2022-11-12 20:36:36 -03:00
9daf029f35 Use vector transform feedback outputs if possible (#3832) 2022-11-12 20:20:40 -03:00
51a27032f0 Fix VertexId and InstanceId on Vulkan (#3833)
* Fix VertexId and InstanceId on Vulkan

* Shader cache version bump
2022-11-11 13:22:49 -03:00
302 changed files with 7587 additions and 2710 deletions

View File

@ -1,6 +1,6 @@
---
name: Bug Report
about: Something doesn't work correctly in Ryujinx. Note that game-specific issues should be instead posted on the Game Compatibility List at https://github.com/Ryujinx/Ryujinx-Games-List, unless it is a provable regression.
about: Something doesn't work correctly in Ryujinx. Game-specific issues should be posted at https://github.com/Ryujinx/Ryujinx-Games-List instead, unless it is a provable regression.
#assignees:
---
@ -34,7 +34,7 @@ about: Something doesn't work correctly in Ryujinx. Note that game-specific issu
- OS: *(e.g. Windows 10)*
- CPU: *(e.g. i7-6700)*
- GPU: *(e.g. NVIDIA RTX 2070)*
- RAM: *(e.g. 16GB)*
- RAM: *(e.g. 16GiB)*
- Applied Mods : [ Yes (Which ones) / No ]
### Additional context?

View File

@ -52,26 +52,22 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
- name: Ensure NuGet Source
uses: fabriciomurta/ensure-nuget-source@v1
- name: Get git short hash
id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Clear
run: dotnet clean && dotnet nuget locals all --clear
- name: Build
run: dotnet build -c "${{ matrix.configuration }}" /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
- name: Test
run: dotnet test --no-build -c "${{ matrix.configuration }}"
- name: Publish Ryujinx
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained true
if: github.event_name == 'pull_request'
- name: Publish Ryujinx.Headless.SDL2
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained true
if: github.event_name == 'pull_request'
- name: Publish Ryujinx.Ava
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava --self-contained true
if: github.event_name == 'pull_request'
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v3

View File

@ -29,10 +29,6 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
- name: Ensure NuGet Source
uses: fabriciomurta/ensure-nuget-source@v1
- name: Clear
run: dotnet clean && dotnet nuget locals all --clear
- name: Get version info
id: version_info
run: |
@ -51,9 +47,9 @@ jobs:
run: "mkdir release_output"
- name: Publish Windows
run: |
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
- name: Packing Windows builds
run: |
pushd publish_windows
@ -71,9 +67,9 @@ jobs:
- name: Publish Linux
run: |
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
- name: Packing Linux builds
run: |

View File

@ -1,15 +1,11 @@
using System;
using System.Numerics;
namespace ARMeilleure.Common
{
static class BitUtils
{
private static readonly sbyte[] HbsNibbleLut;
static BitUtils()
{
HbsNibbleLut = new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
}
private static ReadOnlySpan<sbyte> HbsNibbleLut => new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
public static long FillWithOnes(int bits)
{

View File

@ -25,13 +25,13 @@ namespace ARMeilleure.Diagnostics
_funcTabSizeCounter = new PollingCounter("addr-tab-alloc", this, () => _funcTabSize / 1024d / 1024d)
{
DisplayName = "AddressTable Total Bytes Allocated",
DisplayUnits = "MB"
DisplayUnits = "MiB"
};
_funcTabLeafSizeCounter = new PollingCounter("addr-tab-leaf-alloc", this, () => _funcTabLeafSize / 1024d / 1024d)
{
DisplayName = "AddressTable Total Leaf Bytes Allocated",
DisplayUnits = "MB"
DisplayUnits = "MiB"
};
}

View File

@ -36,12 +36,12 @@
## Compatibility
As of October 2022, Ryujinx has been tested on approximately 3,700 titles; over 3,500 boot past menus and into gameplay, with roughly 3,000 of those being considered playable.
As of November 2022, Ryujinx has been tested on approximately 3,800 titles; over 3,600 boot past menus and into gameplay, with roughly 3,200 of those being considered playable.
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
## Usage
To run this emulator, your PC must be equipped with at least 8GB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
To run this emulator, your PC must be equipped with at least 8GiB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator.
@ -90,7 +90,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
- **GPU**
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum) or Vulkan APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
- **Input**

View File

@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.OpenAL" Version="4.7.2" />
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" />
</ItemGroup>
<ItemGroup>

View File

@ -1,4 +1,5 @@
using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Common.Logging;
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@ -71,6 +72,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
return (short)value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
{
if ((uint)index > (uint)coefficients.Length)
{
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
return 0;
}
return coefficients[index];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
{
@ -84,8 +98,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
byte coefficientIndex = (byte)((predScale >> 4) & 0xF);
short history0 = loopContext.History0;
short history1 = loopContext.History1;
short coefficient0 = coefficients[coefficientIndex * 2 + 0];
short coefficient1 = coefficients[coefficientIndex * 2 + 1];
short coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 0);
short coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
@ -109,8 +123,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
coefficientIndex = (byte)((predScale >> 4) & 0xF);
coefficient0 = coefficients[coefficientIndex * 2 + 0];
coefficient1 = coefficients[coefficientIndex * 2 + 1];
coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2);
coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
nibbles += 2;

View File

@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }

View File

@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.AuxiliaryBuffer;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint InputBufferIndex { get; }
public uint OutputBufferIndex { get; }

View File

@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.BiquadFilter;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public Memory<BiquadFilterState> BiquadFilterState { get; }
public int InputBufferIndex { get; }

View File

@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.CaptureBuffer;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint InputBufferIndex { get; }

View File

@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.CircularBufferSink;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort[] Input { get; }
public uint InputCount { get; }

View File

@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.ClearMixBuffer;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ClearMixBufferCommand(int nodeId)
{

View File

@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.CopyMixBuffer;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType { get; }
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }

View File

@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Delay;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public DelayParameter Parameter => _parameter;
public Memory<DelayState> State { get; }
@ -49,15 +49,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
}
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
// TODO: Update delay processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private unsafe void ProcessDelayMono(ref DelayState state, float* outputBuffer, float* inputBuffer, uint sampleCount)
{
const ushort channelCount = 1;
float feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision);
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
@ -70,7 +70,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float temp = input * inGain + delayLineValue * feedbackGain;
state.UpdateLowPassFilter(ref temp, 1);
state.UpdateLowPassFilter(ref temp, channelCount);
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
}
@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
Y = state.DelayLines[1].Read(),
};
Vector2 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
Vector2 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
state.UpdateLowPassFilter(ref Unsafe.As<Vector2, float>(ref temp), channelCount);
@ -148,7 +148,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
W = state.DelayLines[3].Read()
};
Vector4 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
Vector4 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
state.UpdateLowPassFilter(ref Unsafe.As<Vector4, float>(ref temp), channelCount);
@ -171,12 +171,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain,
0.0f, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f,
delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f,
0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f,
delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackBaseGain, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, feedbackGain);
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f,
0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain,
delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f,
delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain,
0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain);
for (int i = 0; i < sampleCount; i++)
{
@ -200,7 +200,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
U = state.DelayLines[5].Read()
};
Vector6 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
Vector6 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
state.UpdateLowPassFilter(ref Unsafe.As<Vector6, float>(ref temp), channelCount);

View File

@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.DepopForMixBuffers;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferOffset { get; }

View File

@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.DepopPrepare;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferCount { get; }

View File

@ -14,7 +14,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.DeviceSink;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public string DeviceName { get; }

View File

@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort[] InputBufferIndices { get; }
public ushort[] OutputBufferIndices { get; }

View File

@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.GroupedBiquadFilter;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
private BiquadFilterParameter[] _parameters;
private Memory<BiquadFilterState> _biquadFilterStates;
@ -47,9 +47,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
}
// NOTE: Nintendo also implements a hot path for double biquad filters, but no generic path when the command definition suggests it could be done.
// As such we currently only implement a generic path for simplicity.
// TODO: Implement double biquad filters fast path.
// NOTE: Nintendo only implement single and double biquad filters but no generic path when the command definition suggests it could be done.
// As such we currently only implement a generic path for simplicity for double biquad.
if (_parameters.Length == 1)
{
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);

View File

@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType { get; }
public ulong EstimatedProcessingTime { get; }
public uint EstimatedProcessingTime { get; }
public void Process(CommandList context);

View File

@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.LimiterVersion1;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public LimiterParameter Parameter => _parameter;
public Memory<LimiterState> State { get; }

View File

@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.LimiterVersion2;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public LimiterParameter Parameter => _parameter;
public Memory<LimiterState> State { get; }

View File

@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Mix;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.MixRamp;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.MixRampGrouped;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferCount { get; }

View File

@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }

View File

@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }

View File

@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Performance;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }

View File

@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Reverb3d;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Reverb;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ReverbParameter Parameter => _parameter;
public Memory<ReverbState> State { get; }

View File

@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Upsample;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint BufferCount { get; }
public uint InputBufferIndex { get; }

View File

@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Volume;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.VolumeRamp;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@ -28,6 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
private object _lock = new object();
private AudioRendererRenderingDevice _renderingDevice;
private AudioRendererExecutionMode _executionMode;
private IWritableEvent _systemEvent;
private ManualResetEvent _terminationEvent;
@ -63,6 +64,7 @@ namespace Ryujinx.Audio.Renderer.Server
private uint _renderingTimeLimitPercent;
private bool _voiceDropEnabled;
private uint _voiceDropCount;
private float _voiceDropParameter;
private bool _isDspRunningBehind;
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
@ -95,6 +97,7 @@ namespace Ryujinx.Audio.Renderer.Server
_totalElapsedTicksUpdating = 0;
_sessionId = 0;
_voiceDropParameter = 1.0f;
}
public ResultCode Initialize(
@ -130,6 +133,7 @@ namespace Ryujinx.Audio.Renderer.Server
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
_appletResourceId = appletResourceId;
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
_renderingDevice = parameter.RenderingDevice;
_executionMode = parameter.ExecutionMode;
_sessionId = sessionId;
MemoryManager = memoryManager;
@ -337,6 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server
_processHandle = processHandle;
_elapsedFrameCount = 0;
_voiceDropParameter = 1.0f;
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
{
@ -515,7 +520,7 @@ namespace Ryujinx.Audio.Renderer.Server
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
}
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp)
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, uint voicesEstimatedTime, long deltaTimeDsp)
{
int i;
@ -584,7 +589,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
command.Enabled = false;
voicesEstimatedTime -= (long)command.EstimatedProcessingTime;
voicesEstimatedTime -= (uint)(_voiceDropParameter * command.EstimatedProcessingTime);
}
}
}
@ -618,13 +623,13 @@ namespace Ryujinx.Audio.Renderer.Server
_voiceContext.Sort();
commandGenerator.GenerateVoices();
long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
uint voicesEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
commandGenerator.GenerateSubMixes();
commandGenerator.GenerateFinalMixes();
commandGenerator.GenerateSinks();
long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
uint totalEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
if (_voiceDropEnabled)
{
@ -856,5 +861,26 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
}
public void SetVoiceDropParameter(float voiceDropParameter)
{
_voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 2.0f);
}
public float GetVoiceDropParameter()
{
return _voiceDropParameter;
}
public ResultCode ExecuteAudioRendererRendering()
{
if (_executionMode == AudioRendererExecutionMode.Manual && _renderingDevice == AudioRendererRenderingDevice.Cpu)
{
// NOTE: Here Nintendo aborts with this error code, we don't want that.
return ResultCode.InvalidExecutionContextOperation;
}
return ResultCode.UnsupportedOperation;
}
}
}

View File

@ -94,8 +94,9 @@ namespace Ryujinx.Audio.Renderer.Server
/// REV11:
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
/// A new version of the command estimator was added to address timing changes caused by the legacy effects changes.
/// A voice drop parameter was added in 15.0.0: This allows an application to amplify or attenuate the estimated time of DSP commands.
/// </summary>
/// <remarks>This was added in system update 14.0.0</remarks>
/// <remarks>This was added in system update 14.0.0 but some changes were made in 15.0.0</remarks>
public const int Revision11 = 11 << 24;
/// <summary>

View File

@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <summary>
/// The estimated total processing time.
/// </summary>
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
/// <summary>
/// The command list that is populated by the <see cref="CommandBuffer"/>.

View File

@ -263,12 +263,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
return UpdateResult.Success;
}
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0)
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress % pageSize) != 0)
{
return UpdateResult.InvalidParameter;
}
if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0)
if (inParameter.Size == 0 || (inParameter.Size % pageSize) != 0)
{
return UpdateResult.InvalidParameter;
}

View File

@ -34,10 +34,10 @@ namespace Ryujinx.Audio.Renderer.Utils
writer.Seek(0, SeekOrigin.Begin);
writer.Write(Encoding.ASCII.GetBytes("RIFF"));
writer.Write("RIFF"u8);
writer.Write((int)(writer.BaseStream.Length - 8));
writer.Write(Encoding.ASCII.GetBytes("WAVE"));
writer.Write(Encoding.ASCII.GetBytes("fmt "));
writer.Write("WAVE"u8);
writer.Write("fmt "u8);
writer.Write(16);
writer.Write((short)1);
writer.Write((short)GetChannelCount());
@ -45,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Utils
writer.Write(GetSampleRate() * GetChannelCount() * sizeof(short));
writer.Write((short)(GetChannelCount() * sizeof(short)));
writer.Write((short)(sizeof(short) * 8));
writer.Write(Encoding.ASCII.GetBytes("data"));
writer.Write("data"u8);
writer.Write((int)(writer.BaseStream.Length - HeaderSize));
writer.Seek((int)currentPos, SeekOrigin.Begin);

View File

@ -17,5 +17,6 @@ namespace Ryujinx.Audio
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
InvalidExecutionContextOperation = (514 << ErrorCodeShift) | ModuleId,
}
}

View File

@ -10,6 +10,7 @@ using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Ui.Common.Configuration;
using Ryujinx.Ui.Common.Helper;
using System;
using System.Diagnostics;
using System.IO;
@ -20,6 +21,8 @@ namespace Ryujinx.Ava
{
public override void Initialize()
{
Name = $"Ryujinx {Program.Version}";
AvaloniaXamlLoader.Load(this);
}
@ -64,8 +67,7 @@ namespace Ryujinx.Ava
if (result == UserResult.Yes)
{
var path = Process.GetCurrentProcess().MainModule.FileName;
var info = new ProcessStartInfo() { FileName = path, UseShellExecute = false };
var proc = Process.Start(info);
var proc = Process.Start(path, CommandLineState.Arguments);
desktop.Shutdown();
Environment.Exit(0);
}

View File

@ -60,7 +60,7 @@ namespace Ryujinx.Ava
private const float VolumeDelta = 0.05f;
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
private readonly long _ticksPerFrame;
private readonly Stopwatch _chrono;
@ -349,7 +349,10 @@ namespace Ryujinx.Ava
_isActive = false;
_renderingThread.Join();
if (_renderingThread.IsAlive)
{
_renderingThread.Join();
}
DisplaySleep.Restore();
@ -378,7 +381,7 @@ namespace Ryujinx.Ava
_gpuCancellationTokenSource.Cancel();
_gpuCancellationTokenSource.Dispose();
_chrono.Stop();
}
@ -393,7 +396,7 @@ namespace Ryujinx.Ava
Renderer?.MakeCurrent();
Device.DisposeGpu();
Renderer?.MakeCurrent(null);
}
@ -417,7 +420,6 @@ namespace Ryujinx.Ava
public async Task<bool> LoadGuestApplication()
{
InitializeSwitchInstance();
MainWindow.UpdateGraphicsConfig();
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
@ -428,17 +430,16 @@ namespace Ryujinx.Ava
{
if (userError == UserError.NoFirmware)
{
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"],
firmwareVersion.VersionString);
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"], message,
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"],
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], firmwareVersion.VersionString),
LocaleManager.Instance["InputDialogYes"],
LocaleManager.Instance["InputDialogNo"],
"");
if (result != UserResult.Yes)
{
Dispatcher.UIThread.Post(async () => await
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
Device.Dispose();
return false;
@ -447,8 +448,7 @@ namespace Ryujinx.Ava
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
{
Dispatcher.UIThread.Post(async () => await
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
Device.Dispose();
return false;
@ -461,11 +461,9 @@ namespace Ryujinx.Ava
_parent.RefreshFirmwareStatus();
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString);
await ContentDialogHelper.CreateInfoDialog(
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
message,
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString),
LocaleManager.Instance["InputDialogOk"],
"",
LocaleManager.Instance["RyujinxInfo"]);
@ -473,9 +471,7 @@ namespace Ryujinx.Ava
}
else
{
Dispatcher.UIThread.Post(async () => await
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
Device.Dispose();
return false;
@ -514,7 +510,7 @@ namespace Ryujinx.Ava
}
else if (File.Exists(ApplicationPath))
{
switch (System.IO.Path.GetExtension(ApplicationPath).ToLowerInvariant())
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
{
case ".xci":
{
@ -602,7 +598,7 @@ namespace Ryujinx.Ava
if (Renderer.IsVulkan)
{
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
}
else
@ -741,7 +737,7 @@ namespace Ryujinx.Ava
}
}
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GB : HLE.MemoryConfiguration.MemoryConfiguration4GB;
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GiB : HLE.MemoryConfiguration.MemoryConfiguration4GiB;
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (Kann Fehler verursachen)",
"SettingsTabSystemExpandDramSize": "Erweitere DRAM Größe auf 6GB",
"SettingsTabSystemExpandDramSize": "Erweitere DRAM Größe auf 6GiB",
"SettingsTabSystemIgnoreMissingServices": "Ignoriere fehlende Dienste",
"SettingsTabGraphics": "Grafik",
"SettingsTabGraphicsAPI": "Grafik-API",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "Verwendung einer Software-Seitentabelle für die Adressumsetzung. Höchste Genauigkeit, aber langsamste Leistung.",
"MemoryManagerHostTooltip": "Direkte Zuordnung von Speicher im Host-Adressraum. Viel schnellere JIT-Kompilierung und Ausführung.",
"MemoryManagerUnsafeTooltip": "Direkte Zuordnung des Speichers, aber keine Maskierung der Adresse innerhalb des Gastadressraums vor dem Zugriff. Schneller, aber auf Kosten der Sicherheit. Die Gastanwendung kann von überall in Ryujinx auf den Speicher zugreifen, daher sollte in diesem Modus nur Programme ausgeführt werden denen vertraut wird.",
"DRamTooltip": "Erhöht den Arbeitsspeicher des emulierten Systems von 4 GB auf 6 GB.\n\nDies ist nur für Texturenpakete mit höherer Auflösung oder Mods mit 4K-Auflösung nützlich. Diese Option verbessert NICHT die Leistung.\n\nIm Zweifelsfall AUS lassen.",
"DRamTooltip": "Erhöht den Arbeitsspeicher des emulierten Systems von 4 GiB auf 6 GiB.\n\nDies ist nur für Texturenpakete mit höherer Auflösung oder Mods mit 4K-Auflösung nützlich. Diese Option verbessert NICHT die Leistung.\n\nIm Zweifelsfall AUS lassen.",
"IgnoreMissingServicesTooltip": "Durch diese Option werden nicht implementierte Dienste der Switch-Firmware ignoriert. Dies kann dabei helfen, Abstürze beim Starten bestimmter Spiele zu umgehen.\n\nIm Zweifelsfall AUS lassen.",
"GraphicsBackendThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf AUTO stellen.",
"GalThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies Beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf auf AUTO stellen.",
@ -583,7 +583,7 @@
"SettingsTabGraphicsBackend": "Grafik-Backend:",
"SettingsTabGraphicsBackendTooltip": "Verwendendetes Grafik-Backend",
"SettingsEnableTextureRecompression": "Textur-Rekompression",
"SettingsEnableTextureRecompressionTooltip": "Komprimiert bestimmte Texturen, um den VRAM-Verbrauch zu reduzieren.\n\nEmpfohlen für die Verwendung von GPUs, die weniger als 4 GB VRAM haben.\n\nIm Zweifelsfall AUS lassen",
"SettingsEnableTextureRecompressionTooltip": "Komprimiert bestimmte Texturen, um den VRAM-Verbrauch zu reduzieren.\n\nEmpfohlen für die Verwendung von GPUs, die weniger als 4 GiB VRAM haben.\n\nIm Zweifelsfall AUS lassen",
"SettingsTabGraphicsPreferredGpu": "Bevorzugte GPU:",
"SettingsTabGraphicsPreferredGpuTooltip": "Wähle die Grafikkarte aus, die mit dem Vulkan Grafik-Backend verwendet werden soll.\n\nDies hat keinen Einfluss auf die GPU die OpenGL verwendet.\n\nIm Zweifelsfall die als \"dGPU\" gekennzeichnete GPU auswählen. Diese Einstellung unberührt lassen, wenn keine zur Auswahl steht.",
"SettingsAppRequiredRestartMessage": "Ein Neustart von Ryujinx ist erforderlich",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Μικροδιορθώσεις",
"SettingsTabSystemHacksNote": " (Μπορεί να προκαλέσουν αστάθεια)",
"SettingsTabSystemExpandDramSize": "Επέκταση μεγέθους DRAM στα 6GB",
"SettingsTabSystemExpandDramSize": "Επέκταση μεγέθους DRAM στα 6GiB",
"SettingsTabSystemIgnoreMissingServices": "Αγνόηση υπηρεσιών που λείπουν",
"SettingsTabGraphics": "Γραφικά",
"SettingsTabGraphicsAPI": "API Γραφικά",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "Χρησιμοποιήστε έναν πίνακα σελίδων λογισμικού για τη μετάφραση διευθύνσεων. Υψηλότερη ακρίβεια αλλά πιο αργή απόδοση.",
"MemoryManagerHostTooltip": "Απευθείας αντιστοίχιση της μνήμης στον χώρο διευθύνσεων υπολογιστή υποδοχής. Πολύ πιο γρήγορη μεταγλώττιση και εκτέλεση JIT.",
"MemoryManagerUnsafeTooltip": "Απευθείας χαρτογράφηση της μνήμης, αλλά μην καλύπτετε τη διεύθυνση εντός του χώρου διευθύνσεων επισκέπτη πριν από την πρόσβαση. Πιο γρήγορα, αλλά με κόστος ασφάλειας. Η εφαρμογή μπορεί να έχει πρόσβαση στη μνήμη από οπουδήποτε στο Ryujinx, επομένως εκτελείτε μόνο προγράμματα που εμπιστεύεστε με αυτήν τη λειτουργία.",
"DRamTooltip": "Επεκτείνει την ποσότητα της μνήμης στο εξομοιούμενο σύστημα από 4 GB σε 6 GB",
"DRamTooltip": "Επεκτείνει την ποσότητα της μνήμης στο εξομοιούμενο σύστημα από 4 GiB σε 6 GiB",
"IgnoreMissingServicesTooltip": "Ενεργοποίηση ή απενεργοποίηση της αγνοώησης για υπηρεσίες που λείπουν",
"GraphicsBackendThreadingTooltip": "Ενεργοποίηση Πολυνηματικής Επεξεργασίας Γραφικών",
"GalThreadingTooltip": "Εκτελεί εντολές γραφικών σε ένα δεύτερο νήμα. Επιτρέπει την πολυνηματική μεταγλώττιση Shader σε χρόνο εκτέλεσης, μειώνει το τρεμόπαιγμα και βελτιώνει την απόδοση των προγραμμάτων οδήγησης χωρίς τη δική τους υποστήριξη πολλαπλών νημάτων. Ποικίλες κορυφαίες επιδόσεις σε προγράμματα οδήγησης με multithreading. Μπορεί να χρειαστεί επανεκκίνηση του Ryujinx για να απενεργοποιήσετε σωστά την ενσωματωμένη λειτουργία πολλαπλών νημάτων του προγράμματος οδήγησης ή ίσως χρειαστεί να το κάνετε χειροκίνητα για να έχετε την καλύτερη απόδοση.",
@ -480,17 +480,17 @@
"AudioVolumeTooltip": "Αλλαγή Έντασης Ήχου",
"SettingsTabSystemEnableInternetAccess": "Ενεργοποίηση πρόσβασης επισκέπτη στο Διαδίκτυο",
"EnableInternetAccessTooltip": "Επιτρέπει την πρόσβαση επισκέπτη στο Διαδίκτυο. Εάν ενεργοποιηθεί, η εξομοιωμένη κονσόλα Switch θα συμπεριφέρεται σαν να είναι συνδεδεμένη στο Διαδίκτυο. Λάβετε υπόψη ότι σε ορισμένες περιπτώσεις, οι εφαρμογές ενδέχεται να εξακολουθούν να έχουν πρόσβαση στο Διαδίκτυο, ακόμη και όταν αυτή η επιλογή είναι απενεργοποιημένη",
"GameListContextMenuManageCheatToolTip" : "Διαχείριση Κόλπων",
"GameListContextMenuManageCheat" : "Διαχείριση Κόλπων",
"ControllerSettingsStickRange" : "Εύρος:",
"DialogStopEmulationTitle" : "Ryujinx - Διακοπή εξομοίωσης",
"GameListContextMenuManageCheatToolTip": "Διαχείριση Κόλπων",
"GameListContextMenuManageCheat": "Διαχείριση Κόλπων",
"ControllerSettingsStickRange": "Εύρος:",
"DialogStopEmulationTitle": "Ryujinx - Διακοπή εξομοίωσης",
"DialogStopEmulationMessage": "Είστε βέβαιοι ότι θέλετε να σταματήσετε την εξομοίωση;",
"SettingsTabCpu": "Επεξεργαστής",
"SettingsTabAudio": "Ήχος",
"SettingsTabNetwork": "Δίκτυο",
"SettingsTabNetworkConnection" : "Σύνδεση δικτύου",
"SettingsTabCpuCache" : "Προσωρινή Μνήμη CPU",
"SettingsTabCpuMemory" : "Μνήμη CPU",
"SettingsTabNetworkConnection": "Σύνδεση δικτύου",
"SettingsTabCpuCache": "Προσωρινή Μνήμη CPU",
"SettingsTabCpuMemory": "Μνήμη CPU",
"ControllerMotionTitle": "Motion Control Settings",
"ControllerRumbleTitle": "Rumble Settings"
}

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (may cause instability)",
"SettingsTabSystemExpandDramSize": "Expand DRAM Size to 6GB",
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
"SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services",
"SettingsTabGraphics": "Graphics",
"SettingsTabGraphicsAPI": "Graphics API",
@ -410,6 +410,8 @@
"DlcManagerTableHeadingContainerPathLabel": "Container Path",
"DlcManagerTableHeadingFullPathLabel": "Full Path",
"DlcManagerRemoveAllButton": "Remove All",
"DlcManagerEnableAllButton": "Enable All",
"DlcManagerDisableAllButton": "Disable All",
"MenuBarOptionsChangeLanguage": "Change Language",
"CommonSort": "Sort",
"CommonShowNames": "Show Names",
@ -440,7 +442,7 @@
"MemoryManagerSoftwareTooltip": "Use a software page table for address translation. Highest accuracy but slowest performance.",
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
"MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.",
"DRamTooltip": "Increases the amount of memory on the emulated system from 4GB to 6GB.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
"DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
"IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.",
"GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
"GalThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
@ -562,12 +564,12 @@
"Writable": "Writable",
"SelectDlcDialogTitle": "Select DLC files",
"SelectUpdateDialogTitle": "Select update files",
"UserProfileWindowTitle": "Manage User Profiles",
"CheatWindowTitle": "Manage Game Cheats",
"DlcWindowTitle": "Manage Game DLC",
"UpdateWindowTitle": "Manage Game Updates",
"UserProfileWindowTitle": "User Profiles Manager",
"CheatWindowTitle": "Cheats Manager",
"DlcWindowTitle": "Downloadable Content Manager",
"UpdateWindowTitle": "Title Update Manager",
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
"DlcWindowHeading": "DLC Available for {0} [{1}]",
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
"UserProfilesEditProfile": "Edit Selected",
"Cancel": "Cancel",
"Save": "Save",
@ -575,7 +577,7 @@
"UserProfilesSetProfileImage": "Set Profile Image",
"UserProfileEmptyNameError": "Name is required",
"UserProfileNoImageError": "Profile image must be set",
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
"GameUpdateWindowHeading": "{0} Update(s) available for {1} ({2})",
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
"UserProfilesName": "Name:",
@ -583,14 +585,16 @@
"SettingsTabGraphicsBackend": "Graphics Backend",
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
"SettingsEnableTextureRecompressionTooltip": "Compresses certain textures in order to reduce VRAM usage.\n\nRecommended for use with GPUs that have less than 4GB VRAM.\n\nLeave OFF if unsure.",
"SettingsEnableTextureRecompressionTooltip": "Compresses certain textures in order to reduce VRAM usage.\n\nRecommended for use with GPUs that have less than 4GiB VRAM.\n\nLeave OFF if unsure.",
"SettingsTabGraphicsPreferredGpu": "Preferred GPU",
"SettingsTabGraphicsPreferredGpuTooltip": "Select the graphics card that will be used with the Vulkan graphics backend.\n\nDoes not affect the GPU that OpenGL will use.\n\nSet to the GPU flagged as \"dGPU\" if unsure. If there isn't one, leave untouched.",
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
"SettingsGpuBackendRestartMessage": "Graphics Backend or GPU settings have been modified. This will require a restart to be applied",
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
"VolumeShort": "Vol"
"VolumeShort": "Vol",
"SettingsEnableMacroHLE": "Enable Macro HLE",
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure."
}

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (Pueden causar inestabilidad)",
"SettingsTabSystemExpandDramSize": "Expandir DRAM a 6GB",
"SettingsTabSystemExpandDramSize": "Expandir DRAM a 6GiB",
"SettingsTabSystemIgnoreMissingServices": "Ignorar servicios no implementados",
"SettingsTabGraphics": "Gráficos",
"SettingsTabGraphicsAPI": "API de gráficos",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "Usa una tabla de paginación de software para traducir direcciones. Ofrece la precisión más exacta pero el rendimiento más lento.",
"MemoryManagerHostTooltip": "Mapea la memoria directamente en la dirección de espacio del host. Compilación y ejecución JIT mucho más rápida.",
"MemoryManagerUnsafeTooltip": "Mapea la memoria directamente, pero no enmascara la dirección dentro del espacio de dirección del guest antes del acceso. El modo más rápido, pero a costa de seguridad. La aplicación guest puede acceder a la memoria desde cualquier parte en Ryujinx, así que ejecuta solo programas en los que confíes cuando uses este modo.",
"DRamTooltip": "Expande la memoria DRAM del sistema emulado de 4GB a 6GB.\n\nUtilizar solo con packs de texturas HD o mods de resolución 4K. NO mejora el rendimiento.\n\nDesactívalo si no sabes qué hacer.",
"DRamTooltip": "Expande la memoria DRAM del sistema emulado de 4GiB a 6GiB.\n\nUtilizar solo con packs de texturas HD o mods de resolución 4K. NO mejora el rendimiento.\n\nDesactívalo si no sabes qué hacer.",
"IgnoreMissingServicesTooltip": "Hack para ignorar servicios no implementados del Horizon OS. Esto puede ayudar a sobrepasar crasheos cuando inicies ciertos juegos.\n\nDesactívalo si no sabes qué hacer.",
"GraphicsBackendThreadingTooltip": "Ejecuta los comandos del motor gráfico en un segundo hilo. Acelera la compilación de sombreadores, reduce los tirones, y mejora el rendimiento en controladores gráficos que no realicen su propio multihilado. Rendimiento máximo ligeramente superior en controladores gráficos que soporten multihilado.\n\nSelecciona \"Auto\" si no sabes qué hacer.",
"GalThreadingTooltip": "Ejecuta los comandos del motor gráfico en un segundo hilo. Acelera la compilación de sombreadores, reduce los tirones, y mejora el rendimiento en controladores gráficos que no realicen su propio multihilado. Rendimiento máximo ligeramente superior en controladores gráficos que soporten multihilado.\n\nSelecciona \"Auto\" si no sabes qué hacer.",

View File

@ -112,7 +112,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (Cela peut causer des instabilitées)",
"SettingsTabSystemExpandDramSize": "Augmenter la taille de la DRAM à 6GB",
"SettingsTabSystemExpandDramSize": "Augmenter la taille de la DRAM à 6GiB",
"SettingsTabSystemIgnoreMissingServices": "Ignorer les services manquant",
"SettingsTabGraphics": "Graphique",
"SettingsTabGraphicsAPI": "API Graphique",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (Possono causare instabilità)",
"SettingsTabSystemExpandDramSize": "Espandi dimensione DRAM a 6GB",
"SettingsTabSystemExpandDramSize": "Espandi dimensione DRAM a 6GiB",
"SettingsTabSystemIgnoreMissingServices": "Ignora servizi mancanti",
"SettingsTabGraphics": "Grafica",
"SettingsTabGraphicsAPI": "API Grafiche",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "Usa una software page table per la traduzione degli indirizzi. Massima precisione ma prestazioni più lente.",
"MemoryManagerHostTooltip": "Mappa direttamente la memoria nello spazio degli indirizzi dell'host. Compilazione ed esecuzione JIT molto più veloce.",
"MemoryManagerUnsafeTooltip": "Mappa direttamente la memoria, ma non maschera l'indirizzo all'interno dello spazio degli indirizzi guest prima dell'accesso. Più veloce, ma a costo della sicurezza. L'applicazione guest può accedere alla memoria da qualsiasi punto di Ryujinx, quindi esegui solo programmi di cui ti fidi con questa modalità.",
"DRamTooltip": "Espande l'ammontare di memoria sul sistema emulato da 4GB A 6GB",
"DRamTooltip": "Espande l'ammontare di memoria sul sistema emulato da 4GiB A 6GiB",
"IgnoreMissingServicesTooltip": "Attiva o disattiva l'opzione di ignorare i servizi mancanti",
"GraphicsBackendThreadingTooltip": "Attiva il Graphics Backend Multithreading",
"GalThreadingTooltip": "Esegue i comandi del backend grafico su un secondo thread. Permette il multithreading runtime della compilazione degli shader, riduce lo stuttering e migliora le prestazioni sui driver senza supporto multithreading proprio. Varia leggermente le prestazioni di picco sui driver con multithreading. Ryujinx potrebbe aver bisogno di essere riavviato per disabilitare correttamente il multithreading integrato nel driver, o potrebbe essere necessario farlo manualmente per ottenere le migliori prestazioni.",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "ハック",
"SettingsTabSystemHacksNote": " (挙動が不安定になる可能性があります)",
"SettingsTabSystemExpandDramSize": "DRAMサイズを6GBに拡大",
"SettingsTabSystemExpandDramSize": "DRAMサイズを6GiBに拡大",
"SettingsTabSystemIgnoreMissingServices": "未実装サービスを無視",
"SettingsTabGraphics": "グラフィックス",
"SettingsTabGraphicsAPI": "グラフィックスAPI",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "アドレス変換にソフトウェアページテーブルを使用します. 非常に正確ですがパフォーマンスが大きく低下します.",
"MemoryManagerHostTooltip": "ホストのアドレス空間にメモリを直接マップします.JITのコンパイルと実行速度が大きく向上します.",
"MemoryManagerUnsafeTooltip": "メモリを直接マップしますが, アクセス前にゲストのアドレス空間内のアドレスをマスクしません. より高速になりますが, 安全性が犠牲になります. ゲストアプリケーションは Ryujinx のどこからでもメモリにアクセスできるので,このモードでは信頼できるプログラムだけを実行するようにしてください.",
"DRamTooltip": "エミュレートされたシステムのメモリ容量を 4GB から 6GB に増加します.\n\n高解像度のテクスチャパックや 4K解像度の mod を使用する場合に有用です. パフォーマンスを改善するものではありません.\n\nよくわからない場合はオフのままにしてください.",
"DRamTooltip": "エミュレートされたシステムのメモリ容量を 4GiB から 6GiB に増加します.\n\n高解像度のテクスチャパックや 4K解像度の mod を使用する場合に有用です. パフォーマンスを改善するものではありません.\n\nよくわからない場合はオフのままにしてください.",
"IgnoreMissingServicesTooltip": "未実装の Horizon OS サービスを無視します. 特定のゲームにおいて起動時のクラッシュを回避できる場合があります.\n\nよくわからない場合はオフのままにしてください.",
"GraphicsBackendThreadingTooltip": "グラフィックスバックエンドのコマンドを別スレッドで実行します.\n\nシェーダのコンパイルを高速化し, 遅延を軽減し, マルチスレッド非対応の GPU ドライバにおいてパフォーマンスを改善します. マルチスレッド対応のドライバでも若干パフォーマンス改善が見られます.\n\nよくわからない場合は自動に設定してください.",
"GalThreadingTooltip": "グラフィックスバックエンドのコマンドを別スレッドで実行します.\n\nシェーダのコンパイルを高速化し, 遅延を軽減し, マルチスレッド非対応の GPU ドライバにおいてパフォーマンスを改善します. マルチスレッド対応のドライバでも若干パフォーマンス改善が見られます.\n\nよくわからない場合は自動に設定してください.",
@ -583,7 +583,7 @@
"SettingsTabGraphicsBackend": "グラフィックスバックエンド",
"SettingsTabGraphicsBackendTooltip": "使用するグラフィックスバックエンドです",
"SettingsEnableTextureRecompression": "テクスチャの再圧縮を有効",
"SettingsEnableTextureRecompressionTooltip": "VRAMの使用量を削減するためテクスチャを圧縮します.\n\nGPUのVRAMが4GB未満の場合は使用を推奨します.\n\nよくわからない場合はオフのままにしてください.",
"SettingsEnableTextureRecompressionTooltip": "VRAMの使用量を削減するためテクスチャを圧縮します.\n\nGPUのVRAMが4GiB未満の場合は使用を推奨します.\n\nよくわからない場合はオフのままにしてください.",
"SettingsTabGraphicsPreferredGpu": "優先使用するGPU",
"SettingsTabGraphicsPreferredGpuTooltip": "Vulkanグラフィックスバックエンドで使用されるグラフィックスカードを選択します.\n\nOpenGLが使用するGPUには影響しません.\n\n不明な場合は, \"dGPU\" としてフラグが立っているGPUに設定します. ない場合はそのままにします.",
"SettingsAppRequiredRestartMessage": "Ryujinx の再起動が必要です",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "해킹",
"SettingsTabSystemHacksNote": " (불안정을 일으킬 수 있음)",
"SettingsTabSystemExpandDramSize": "DRAM 크기를 6GB로 확장",
"SettingsTabSystemExpandDramSize": "DRAM 크기를 6GiB로 확장",
"SettingsTabSystemIgnoreMissingServices": "누락된 서비스 무시",
"SettingsTabGraphics": "제도법",
"SettingsTabGraphicsAPI": "그래픽 API",
@ -439,7 +439,7 @@
"MemoryManagerSoftwareTooltip": "주소 변환을 위해 소프트웨어 페이지 테이블을 사용하십시오. 정확도는 가장 높지만 성능은 가장 느립니다.",
"MemoryManagerHostTooltip": "호스트 주소 공간에서 메모리를 직접 매핑합니다. 훨씬 더 빠른 JIT 컴파일 및 실행.",
"MemoryManagerUnsafeTooltip": "메모리를 직접 매핑하지만 액세스하기 전에 게스트 주소 공간 내의 주소를 마스킹하지 마십시오. 더 빠르지만 안전을 희생해야 합니다. 게스트 응용 프로그램은 Ryujinx의 어디에서나 메모리에 액세스할 수 있으므로 이 모드로 신뢰할 수 있는 프로그램만 실행하십시오.",
"DRamTooltip": "에뮬레이트된 시스템의 메모리 양을 4GB에서 6GB로 확장",
"DRamTooltip": "에뮬레이트된 시스템의 메모리 양을 4GiB에서 6GiB로 확장",
"IgnoreMissingServicesTooltip": "누락된 서비스 무시 옵션 활성화 또는 비활성화",
"GraphicsBackendThreadingTooltip": "그래픽 백엔드 멀티스레딩 활성화",
"GalThreadingTooltip": "두 번째 스레드에서 그래픽 백엔드 명령을 실행합니다. 셰이더 컴파일의 런타임 멀티스레딩을 허용하고, 말더듬을 줄이고, 자체 멀티스레딩 지원 없이 드라이버의 성능을 개선합니다. 멀티스레딩이 있는 드라이버에서 약간 다른 최대 성능. 드라이버 내장 멀티스레딩을 올바르게 비활성화하려면 Ryujinx를 다시 시작해야 할 수도 있고 최상의 성능을 얻으려면 수동으로 수행해야 할 수도 있습니다.",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacki",
"SettingsTabSystemHacksNote": " (mogą powodować niestabilność)",
"SettingsTabSystemExpandDramSize": "Rozszerz Rozmiar DRAM do 6 GB",
"SettingsTabSystemExpandDramSize": "Rozszerz Rozmiar DRAM do 6 GiB",
"SettingsTabSystemIgnoreMissingServices": "Ignoruj Brakujące Usługi",
"SettingsTabGraphics": "Grafika",
"SettingsTabGraphicsAPI": "Graficzne API",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "Użyj tabeli stron oprogramowania do translacji adresów. Najwyższa celność, ale najwolniejsza wydajność.",
"MemoryManagerHostTooltip": "Bezpośrednio mapuj pamięć w przestrzeni adresowej hosta. Znacznie szybsza kompilacja i wykonanie JIT.",
"MemoryManagerUnsafeTooltip": "Bezpośrednio mapuj pamięć, ale nie maskuj adresu w przestrzeni adresowej gościa przed uzyskaniem dostępu. Szybciej, ale kosztem bezpieczeństwa. Aplikacja gościa może uzyskać dostęp do pamięci z dowolnego miejsca w Ryujinx, więc w tym trybie uruchamiaj tylko programy, którym ufasz.",
"DRamTooltip": "Zwiększa ilość pamięci w emulowanym systemie z 4 GB do 6 GB.\n\nJest to przydatne tylko w przypadku pakietów tekstur o wyższej rozdzielczości lub modów w rozdzielczości 4k. NIE poprawia wydajności.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
"DRamTooltip": "Zwiększa ilość pamięci w emulowanym systemie z 4 GiB do 6 GiB.\n\nJest to przydatne tylko w przypadku pakietów tekstur o wyższej rozdzielczości lub modów w rozdzielczości 4k. NIE poprawia wydajności.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
"IgnoreMissingServicesTooltip": "Ignoruje niezaimplementowane usługi Horizon OS. Może to pomóc w ominięciu awarii podczas uruchamiania niektórych gier.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
"GraphicsBackendThreadingTooltip": "Wykonuje polecenia backend'u graficznego w drugim wątku.\n\nPrzyspiesza kompilację shaderów, zmniejsza zacinanie się i poprawia wydajność sterowników GPU bez własnej obsługi wielowątkowości. Nieco lepsza wydajność w sterownikach z wielowątkowością.\n\nUstaw na AUTO, jeśli nie masz pewności.",
"GalThreadingTooltip": "Wykonuje polecenia backend'u graficznego w drugim wątku.\n\nPrzyspiesza kompilację shaderów, zmniejsza zacinanie się i poprawia wydajność sterowników GPU bez własnej obsługi wielowątkowości. Nieco lepsza wydajność w sterownikach z wielowątkowością.\n\nUstaw na AUTO, jeśli nie masz pewności.",
@ -583,7 +583,7 @@
"SettingsTabGraphicsBackend": "Backend Graficzny",
"SettingsTabGraphicsBackendTooltip": "Używalne Backendy Graficzne",
"SettingsEnableTextureRecompression": "Włącz Rekompresję Tekstur",
"SettingsEnableTextureRecompressionTooltip": "Kompresuje niektóre tekstury w celu zmniejszenia zużycia pamięci VRAM.\n\nZalecane do użytku z GPU, które mają mniej niż 4 GB pamięci VRAM.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
"SettingsEnableTextureRecompressionTooltip": "Kompresuje niektóre tekstury w celu zmniejszenia zużycia pamięci VRAM.\n\nZalecane do użytku z GPU, które mają mniej niż 4 GiB pamięci VRAM.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
"SettingsTabGraphicsPreferredGpu": "Preferowane GPU",
"SettingsTabGraphicsPreferredGpuTooltip": "Wybierz kartę graficzną, która będzie używana z backendem graficznym Vulkan.\n\nNie wpływa na GPU używane przez OpenGL.\n\nW razie wątpliwości ustaw flagę GPU jako \"dGPU\". Jeśli żadnej nie ma, pozostaw nietknięte.",
"SettingsAppRequiredRestartMessage": "Wymagane Zrestartowanie Ryujinx",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (Pode causar instabilidade)",
"SettingsTabSystemExpandDramSize": "Expandir memória para 6GB",
"SettingsTabSystemExpandDramSize": "Expandir memória para 6GiB",
"SettingsTabSystemIgnoreMissingServices": "Ignorar serviços não implementados",
"SettingsTabGraphics": "Gráficos",
"SettingsTabGraphicsAPI": "API gráfica",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "Usar uma tabela de página via software para tradução de endereços. Maior precisão, porém performance mais baixa.",
"MemoryManagerHostTooltip": "Mapeia memória no espaço de endereço hóspede diretamente. Compilação e execução do JIT muito mais rápida.",
"MemoryManagerUnsafeTooltip": "Mapeia memória diretamente, mas sem limitar o acesso ao espaço de endereçamento do sistema convidado. Mais rápido, porém menos seguro. O aplicativo convidado pode acessar memória de qualquer parte do Ryujinx, então apenas rode programas em que você confia nesse modo.",
"DRamTooltip": "Expande a memória do sistema emulado de 4GB para 6GB",
"DRamTooltip": "Expande a memória do sistema emulado de 4GiB para 6GiB",
"IgnoreMissingServicesTooltip": "Habilita ou desabilita a opção de ignorar serviços não implementados",
"GraphicsBackendThreadingTooltip": "Habilita multithreading do backend gráfico",
"GalThreadingTooltip": "Executa comandos do backend gráfico em uma segunda thread. Permite multithreading em tempo de execução da compilação de shader, diminui os travamentos, e melhora performance em drivers sem suporte embutido a multithreading. Pequena variação na performance máxima em drivers com suporte a multithreading. Ryujinx pode precisar ser reiniciado para desabilitar adequadamente o multithreading embutido do driver, ou você pode precisar fazer isso manualmente para ter a melhor performance.",
@ -556,5 +556,7 @@
"SettingsSelectThemeFileDialogTitle" : "Selecionar arquivo do tema",
"SettingsXamlThemeFile" : "Arquivo de tema Xaml",
"SettingsTabHotkeysResScaleUpHotkey": "Aumentar a resolução:",
"SettingsTabHotkeysResScaleDownHotkey": "Diminuir a resolução:"
"SettingsTabHotkeysResScaleDownHotkey": "Diminuir a resolução:",
"SettingsEnableMacroHLE": "Habilitar emulação de alto nível para Macros",
"SettingsEnableMacroHLETooltip": "Habilita emulação de alto nível de códigos Macro da GPU.\n\nMelhora a performance, mas pode causar problemas gráficos em alguns jogos.\n\nEm caso de dúvida, deixe ATIVADO."
}

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Хаки",
"SettingsTabSystemHacksNote": " (Эти многие настройки вызывают нестабильность)",
"SettingsTabSystemExpandDramSize": "Увеличение размера DRAM до 6GB",
"SettingsTabSystemExpandDramSize": "Увеличение размера DRAM до 6GiB",
"SettingsTabSystemIgnoreMissingServices": "Игнорировать отсутствующие службы",
"SettingsTabGraphics": "Графика",
"SettingsTabGraphicsAPI": "Графические API",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacklar",
"SettingsTabSystemHacksNote": " (Bunlar birçok dengesizlik oluşturabilir)",
"SettingsTabSystemExpandDramSize": "DRAM boyutunu 6GB'a genişlet",
"SettingsTabSystemExpandDramSize": "DRAM boyutunu 6GiB'a genişlet",
"SettingsTabSystemIgnoreMissingServices": "Eksik Servisleri Görmezden Gel",
"SettingsTabGraphics": "Grafikler",
"SettingsTabGraphicsAPI": "Grafikler API",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "Adres çevirisi için bir işlemci sayfası kullanır. En yüksek doğruluğu ve en yavaş performansı sunar.",
"MemoryManagerHostTooltip": "Hafızayı doğrudan host adres aralığında tahsis eder. Çok daha hızlı JIT derleme ve işletimi sunar.",
"MemoryManagerUnsafeTooltip": "Hafızayı doğrudan tahsis eder, ancak host aralığına erişimden önce adresi maskelemez. Daha iyi performansa karşılık emniyetten ödün verir. Misafir uygulama Ryujinx içerisinden istediği hafızaya erişebilir, bu sebeple bu seçenek ile sadece güvendiğiniz uygulamaları çalıştırın.",
"DRamTooltip": "Emüle edilen sistem hafızasını 4GB'dan 6GB'a yükseltir.\n\nBu seçenek yalnızca yüksek çözünürlük doku paketleri veya 4k çözünürlük modları için kullanılır. Performansı artırMAZ!\n\nEmin değilseniz devre dışı bırakın.",
"DRamTooltip": "Emüle edilen sistem hafızasını 4GiB'dan 6GiB'a yükseltir.\n\nBu seçenek yalnızca yüksek çözünürlük doku paketleri veya 4k çözünürlük modları için kullanılır. Performansı artırMAZ!\n\nEmin değilseniz devre dışı bırakın.",
"IgnoreMissingServicesTooltip": "Henüz programlanmamış Horizon işletim sistemi servislerini görmezden gelir. Bu seçenek belirli oyunların açılırken çökmesinin önüne geçmeye yardımcı olabilir.\n\nEmin değilseniz devre dışı bırakın.",
"GraphicsBackendThreadingTooltip": "Grafik arka uç komutlarını ikinci bir iş parçacığında işletir.\n\nKendi multithreading desteği olmayan sürücülerde shader derlemeyi hızlandırıp performansı artırır. Multithreading desteği olan sürücülerde çok az daha iyi performans sağlar.\n\nEmin değilseniz Otomatik seçeneğine ayarlayın.",
"GalThreadingTooltip": "Grafik arka uç komutlarını ikinci bir iş parçacığında işletir.\n\nKendi multithreading desteği olmayan sürücülerde shader derlemeyi hızlandırıp performansı artırır. Multithreading desteği olan sürücülerde çok az daha iyi performans sağlar.\n\nEmin değilseniz Otomatik seçeneğine ayarlayın.",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "修正",
"SettingsTabSystemHacksNote": " (会引起模拟器不稳定)",
"SettingsTabSystemExpandDramSize": "将模拟RAM大小扩展到 6GB",
"SettingsTabSystemExpandDramSize": "将模拟RAM大小扩展到 6GiB",
"SettingsTabSystemIgnoreMissingServices": "忽略缺少的服务",
"SettingsTabGraphics": "图形",
"SettingsTabGraphicsAPI": "图形 API",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "使用软件内存页管理,最精确但是速度最慢",
"MemoryManagerHostTooltip": "直接映射内存页到电脑内存JIT效率高",
"MemoryManagerUnsafeTooltip": "直接映射内存页但不检查内存溢出JIT效率最高。\nRyujinx可以访问任何位置的内存因而相对不安全。\n此模式下只应运行您信任的游戏或软件(即官方游戏)",
"DRamTooltip": "扩展模拟的 Switch 内存为6GB。\n某些高清纹理MOD或4K MOD需要此选项",
"DRamTooltip": "扩展模拟的 Switch 内存为6GiB。\n某些高清纹理MOD或4K MOD需要此选项",
"IgnoreMissingServicesTooltip": "开启后,游戏会忽略未实现的系统服务,从而继续运行。\n少部分新发布的游戏由于使用新的未知系统服务可能需要此选项来避免闪退。\n模拟器更新完善系统服务之后则无需开启选项。\n如您的游戏已经正常运行请保持此选项关闭",
"GraphicsBackendThreadingTooltip": "启用后端多线程",
"GalThreadingTooltip": "使用模拟器内置的多线程优化,减少着色器编译的卡顿,并提高驱动程序的性能(尤其是缺失多线程的AMD)。\nNVIDIA显卡需要重启模拟器才能禁用驱动本身的线程优化您也可以手动在控制面板将其禁用",
@ -583,7 +583,7 @@
"SettingsTabGraphicsBackend": "图形后端",
"SettingsTabGraphicsBackendTooltip": "显卡使用的图形后端",
"SettingsEnableTextureRecompression": "启用纹理重压缩",
"SettingsEnableTextureRecompressionTooltip": "压缩某些纹理以减少显存的使用。\n适合显存小于 4GB 的 GPU开启。\n如果您不确定请保持此项为关闭。",
"SettingsEnableTextureRecompressionTooltip": "压缩某些纹理以减少显存的使用。\n适合显存小于 4GiB 的 GPU开启。\n如果您不确定请保持此项为关闭。",
"SettingsTabGraphicsPreferredGpu": "首选 GPU",
"SettingsTabGraphicsPreferredGpuTooltip": "选择Vulkan API使用的显卡。\n此选项不会影响OpenGL API。\n如果您不确定建议选择\"dGPU(独立显卡)\"。如果没有独立显卡,则无需改动此选项",
"SettingsAppRequiredRestartMessage": "Ryujinx 需要重启",

View File

@ -119,7 +119,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "修正",
"SettingsTabSystemHacksNote": " (會引起模擬器不穩定)",
"SettingsTabSystemExpandDramSize": "將模擬記憶體大小擴充至 6GB",
"SettingsTabSystemExpandDramSize": "將模擬記憶體大小擴充至 6GiB",
"SettingsTabSystemIgnoreMissingServices": "忽略缺少的服務",
"SettingsTabGraphics": "圖形",
"SettingsTabGraphicsEnhancements": "增強",
@ -440,7 +440,7 @@
"MemoryManagerSoftwareTooltip": "使用軟體記憶體頁管理,最精確但是速度最慢",
"MemoryManagerHostTooltip": "直接映射記憶體頁到電腦記憶體JIT效率高",
"MemoryManagerUnsafeTooltip": "直接映射記憶體頁但是不檢查記憶體溢出JIT效率最高。\nRyujinx可以存取任何位置的記憶體因而相對不安全。此模式下只應執行您信任的遊戲或軟體(即官方遊戲)",
"DRamTooltip": "擴展模擬的 Switch 記憶體為6GB某些高畫質材質模組或 4K 模組需要此選項",
"DRamTooltip": "擴展模擬的 Switch 記憶體為6GiB某些高畫質材質模組或 4K 模組需要此選項",
"IgnoreMissingServicesTooltip": "忽略某些未實現的系統服務,少部分遊戲需要此選項才能啟動",
"GraphicsBackendThreadingTooltip": "啟用後端多執行緒",
"GalThreadingTooltip": "使用模擬器自帶的多執行緒調度,減少渲染器編譯的卡頓,並提高驅動程式的效能(尤其是缺失多執行緒的AMD)。\nNVIDIA使用者需要重啟模擬器才能停用驅動本身的多執行緒否則您需手動執行停用獲得最佳效能",

View File

@ -1,5 +1,6 @@
using Ryujinx.Ava.Ui.ViewModels;
using Ryujinx.Common;
using Ryujinx.Common.Utilities;
using Ryujinx.Ui.Common.Configuration;
using System.Collections.Concurrent;
using System.Collections.Generic;
@ -93,7 +94,7 @@ namespace Ryujinx.Ava.Common.Locale
return;
}
var strings = JsonSerializer.Deserialize<Dictionary<string, string>>(languageJson);
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
foreach (var item in strings)
{

View File

@ -1,8 +1,5 @@
using ARMeilleure.Translation.PTC;
using Avalonia;
using Avalonia.Rendering;
using Avalonia.Threading;
using Ryujinx.Ava.Ui.Controls;
using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
@ -13,6 +10,7 @@ using Ryujinx.Common.SystemInfo;
using Ryujinx.Modules;
using Ryujinx.Ui.Common;
using Ryujinx.Ui.Common.Configuration;
using Ryujinx.Ui.Common.Helper;
using System;
using System.IO;
using System.Runtime.InteropServices;
@ -23,19 +21,14 @@ namespace Ryujinx.Ava
internal class Program
{
public static double WindowScaleFactor { get; set; }
public static double ActualScaleFactor { get; set; }
public static string Version { get; private set; }
public static string Version { get; private set; }
public static string ConfigurationPath { get; private set; }
public static string CommandLineProfile { get; set; }
public static bool PreviewerDetached { get; private set; }
public static RenderTimer RenderTimer { get; private set; }
public static bool PreviewerDetached { get; private set; }
[DllImport("user32.dll", SetLastError = true)]
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
private const uint MB_ICONWARNING = 0x30;
private const int BaseDpi = 96;
public static void Main(string[] args)
{
@ -43,18 +36,14 @@ namespace Ryujinx.Ava
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
{
MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
_ = MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
}
PreviewerDetached = true;
Initialize(args);
RenderTimer = new RenderTimer();
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
RenderTimer.Dispose();
}
public static AppBuilder BuildAvaloniaApp()
@ -64,69 +53,25 @@ namespace Ryujinx.Ava
.With(new X11PlatformOptions
{
EnableMultiTouch = true,
EnableIme = true,
UseEGL = false,
UseGpu = false
EnableIme = true,
UseEGL = false,
UseGpu = true
})
.With(new Win32PlatformOptions
{
EnableMultitouch = true,
UseWgl = false,
AllowEglInitialization = false,
CompositionBackdropCornerRadius = 8f,
EnableMultitouch = true,
UseWgl = false,
AllowEglInitialization = false,
CompositionBackdropCornerRadius = 8.0f,
})
.UseSkia()
.AfterSetup(_ =>
{
AvaloniaLocator.CurrentMutable
.Bind<IRenderTimer>().ToConstant(RenderTimer)
.Bind<IRenderLoop>().ToConstant(new RenderLoop(RenderTimer, Dispatcher.UIThread));
})
.LogToTrace();
}
private static void Initialize(string[] args)
{
// Parse Arguments.
string launchPathArg = null;
string baseDirPathArg = null;
bool startFullscreenArg = false;
for (int i = 0; i < args.Length; ++i)
{
string arg = args[i];
if (arg == "-r" || arg == "--root-data-dir")
{
if (i + 1 >= args.Length)
{
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
continue;
}
baseDirPathArg = args[++i];
}
else if (arg == "-p" || arg == "--profile")
{
if (i + 1 >= args.Length)
{
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
continue;
}
CommandLineProfile = args[++i];
}
else if (arg == "-f" || arg == "--fullscreen")
{
startFullscreenArg = true;
}
else
{
launchPathArg = arg;
}
}
// Parse arguments
CommandLineState.ParseArguments(args);
// Delete backup files after updating.
Task.Run(Updater.CleanupUpdate);
@ -135,10 +80,10 @@ namespace Ryujinx.Ava
// Hook unhandled exception and process exit events.
AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
// Setup base data directory.
AppDataManager.Initialize(baseDirPathArg);
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
// Initialize the configuration.
ConfigurationState.Initialize();
@ -154,18 +99,15 @@ namespace Ryujinx.Ava
ForceDpiAware.Windows();
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
ActualScaleFactor = ForceDpiAware.GetActualScaleFactor() / BaseDpi;
// Logging system information.
PrintSystemInfo();
// Enable OGL multithreading on the driver, when available.
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off);
DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
// Check if keys exists.
bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"));
if (!hasSystemProdKeys)
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
{
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
{
@ -173,15 +115,15 @@ namespace Ryujinx.Ava
}
}
if (launchPathArg != null)
if (CommandLineState.LaunchPathArg != null)
{
MainWindow.DeferLoadApplication(launchPathArg, startFullscreenArg);
MainWindow.DeferLoadApplication(CommandLineState.LaunchPathArg, CommandLineState.StartFullscreenArg);
}
}
public static void ReloadConfig()
{
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json");
// Now load the configuration as the other subsystems are now registered
@ -215,6 +157,19 @@ namespace Ryujinx.Ava
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}");
}
}
// Check if graphics backend was overridden
if (CommandLineState.OverrideGraphicsBackend != null)
{
if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl")
{
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl;
}
else if (CommandLineState.OverrideGraphicsBackend.ToLower() == "vulkan")
{
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
}
}
}
private static void PrintSystemInfo()
@ -222,8 +177,7 @@ namespace Ryujinx.Ava
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
SystemInfo.Gather().Print();
var enabledLogs = Logger.GetEnabledLevels();
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "<None>" : string.Join(", ", enabledLogs))}");
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(Logger.GetEnabledLevels().Count == 0 ? "<None>" : string.Join(", ", Logger.GetEnabledLevels()))}");
if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom)
{

View File

@ -18,26 +18,26 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.15" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.15" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.15" />
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.15" />
<PackageReference Include="Avalonia.Svg" Version="0.10.14" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.14" />
<PackageReference Include="Avalonia" Version="0.10.18" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
<PackageReference Include="DynamicData" Version="7.9.4" />
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
<PackageReference Include="DynamicData" Version="7.12.8" />
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.4.2" />
<PackageReference Include="OpenTK.Core" Version="4.7.2" />
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
<PackageReference Include="SPB" Version="0.0.4-build27" />
<PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="SPB" Version="0.0.4-build28" />
<PackageReference Include="SharpZipLib" Version="1.4.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
</ItemGroup>

View File

@ -57,14 +57,14 @@ namespace Ryujinx.Ava.Ui.Applet
bool opened = false;
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
title,
message,
"",
LocaleManager.Instance["DialogOpenSettingsWindowLabel"],
"",
LocaleManager.Instance["SettingsButtonClose"],
(int)Symbol.Important,
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
title,
message,
"",
LocaleManager.Instance["DialogOpenSettingsWindowLabel"],
"",
LocaleManager.Instance["SettingsButtonClose"],
(int)Symbol.Important,
deferEvent,
async (window) =>
{
@ -168,7 +168,7 @@ namespace Ryujinx.Ava.Ui.Applet
object response = await msgDialog.Run();
if (response != null && buttons.Length > 1 && (int)response != buttons.Length - 1)
if (response != null && buttons != null && buttons.Length > 1 && (int)response != buttons.Length - 1)
{
showDetails = true;
}

View File

@ -127,9 +127,16 @@ namespace Ryujinx.Ava.Ui.Controls
contentDialog.PrimaryButtonClick += deferCloseAction;
}
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
if (useOverlay)
{
await contentDialog.ShowAsync(overlay, ContentDialogPlacement.Popup);
overlay?.Close();
overlay!.Close();
}
else
{
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
}
}
if (useOverlay)
@ -391,4 +398,4 @@ namespace Ryujinx.Ava.Ui.Controls
return string.Empty;
}
}
}
}

View File

@ -6,8 +6,8 @@ using SPB.Graphics;
using SPB.Platform;
using SPB.Platform.GLX;
using SPB.Platform.X11;
using SPB.Windowing;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
@ -15,12 +15,12 @@ using static Ryujinx.Ava.Ui.Controls.Win32NativeInterop;
namespace Ryujinx.Ava.Ui.Controls
{
public unsafe class EmbeddedWindow : NativeControlHost
public class EmbeddedWindow : NativeControlHost
{
private WindowProc _wndProcDelegate;
private string _className;
protected GLXWindow X11Window { get; private set; }
protected GLXWindow X11Window { get; set; }
protected IntPtr WindowHandle { get; set; }
protected IntPtr X11Display { get; set; }
@ -94,19 +94,17 @@ namespace Ryujinx.Ava.Ui.Controls
}
[SupportedOSPlatform("linux")]
IPlatformHandle CreateLinux(IPlatformHandle parent)
protected virtual IPlatformHandle CreateLinux(IPlatformHandle parent)
{
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
WindowHandle = X11Window.WindowHandle.RawHandle;
X11Display = X11Window.DisplayHandle.RawHandle;
X11Display = X11Window.DisplayHandle.RawHandle;
return new PlatformHandle(WindowHandle, "X11");
}
[SupportedOSPlatform("windows")]
unsafe IPlatformHandle CreateWin32(IPlatformHandle parent)
IPlatformHandle CreateWin32(IPlatformHandle parent)
{
_className = "NativeWindow-" + Guid.NewGuid();
_wndProcDelegate = WndProc;
@ -142,7 +140,7 @@ namespace Ryujinx.Ava.Ui.Controls
}
[SupportedOSPlatform("windows")]
internal IntPtr WndProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
IntPtr WndProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
{
var point = new Point((long)lParam & 0xFFFF, ((long)lParam >> 16) & 0xFFFF);
var root = VisualRoot as Window;

View File

@ -49,7 +49,7 @@ namespace Ryujinx.Ava.Ui.Controls
{
throw new PlatformNotSupportedException();
}
var flags = OpenGLContextFlags.Compat;
if (_graphicsDebugLevel != GraphicsDebugLevel.None)
{
@ -69,12 +69,12 @@ namespace Ryujinx.Ava.Ui.Controls
public void MakeCurrent()
{
Context.MakeCurrent(_window);
Context?.MakeCurrent(_window);
}
public void MakeCurrent(NativeWindowBase window)
{
Context.MakeCurrent(window);
Context?.MakeCurrent(window);
}
public void SwapBuffers()

View File

@ -1,100 +0,0 @@
using Avalonia.Rendering;
using System;
using System.Threading;
using System.Timers;
namespace Ryujinx.Ava.Ui.Controls
{
internal class RenderTimer : IRenderTimer, IDisposable
{
public event Action<TimeSpan> Tick
{
add
{
_tick += value;
if (_subscriberCount++ == 0)
{
Start();
}
}
remove
{
if (--_subscriberCount == 0)
{
Stop();
}
_tick -= value;
}
}
private Thread _tickThread;
private readonly System.Timers.Timer _timer;
private Action<TimeSpan> _tick;
private int _subscriberCount;
private bool _isRunning;
private AutoResetEvent _resetEvent;
public RenderTimer()
{
_timer = new System.Timers.Timer(15);
_resetEvent = new AutoResetEvent(true);
_timer.Elapsed += Timer_Elapsed;
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
TickNow();
}
public void Start()
{
_timer.Start();
if (_tickThread == null)
{
_tickThread = new Thread(RunTick);
_tickThread.Name = "RenderTimerTickThread";
_tickThread.IsBackground = true;
_isRunning = true;
_tickThread.Start();
}
}
public void RunTick()
{
while (_isRunning)
{
_resetEvent.WaitOne();
_tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount));
}
}
public void TickNow()
{
lock (_timer)
{
_resetEvent.Set();
}
}
public void Stop()
{
_timer.Stop();
}
public void Dispose()
{
_timer.Elapsed -= Timer_Elapsed;
_timer.Stop();
_isRunning = false;
_resetEvent.Set();
_tickThread.Join();
_resetEvent.Dispose();
}
}
}

View File

@ -4,11 +4,4 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost">
<ContentControl
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
Name="View"
/>
</UserControl>

View File

@ -41,7 +41,7 @@ namespace Ryujinx.Ava.Ui.Controls
{
_currentWindow.WindowCreated += CurrentWindow_WindowCreated;
_currentWindow.SizeChanged += CurrentWindow_SizeChanged;
View.Content = _currentWindow;
Content = _currentWindow;
}
public void CreateVulkan()

View File

@ -1,10 +1,13 @@
using Avalonia.Platform;
using Ryujinx.Ava.Ui.Controls;
using Silk.NET.Vulkan;
using SPB.Graphics.Vulkan;
using SPB.Platform.GLX;
using SPB.Platform.Win32;
using SPB.Platform.X11;
using SPB.Windowing;
using System;
using System.Runtime.Versioning;
namespace Ryujinx.Ava.Ui
{
@ -12,6 +15,18 @@ namespace Ryujinx.Ava.Ui
{
private NativeWindowBase _window;
[SupportedOSPlatform("linux")]
protected override IPlatformHandle CreateLinux(IPlatformHandle parent)
{
X11Window = new GLXWindow(new NativeHandle(X11.DefaultDisplay), new NativeHandle(parent.Handle));
WindowHandle = X11Window.WindowHandle.RawHandle;
X11Display = X11Window.DisplayHandle.RawHandle;
X11Window.Hide();
return new PlatformHandle(WindowHandle, "X11");
}
public SurfaceKHR CreateSurface(Instance instance)
{
if (OperatingSystem.IsWindows())
@ -20,7 +35,7 @@ namespace Ryujinx.Ava.Ui
}
else if (OperatingSystem.IsLinux())
{
_window = X11Window;
_window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
}
else
{

View File

@ -1,8 +1,22 @@
namespace Ryujinx.Ava.Ui.Models
using Ryujinx.Ava.Ui.ViewModels;
namespace Ryujinx.Ava.Ui.Models
{
public class DownloadableContentModel
public class DownloadableContentModel : BaseModel
{
public bool Enabled { get; set; }
private bool _enabled;
public bool Enabled
{
get => _enabled;
set
{
_enabled = value;
OnPropertyChanged();
}
}
public string TitleId { get; }
public string ContainerPath { get; }
public string FullPath { get; }

View File

@ -10,22 +10,22 @@ namespace Ryujinx.Ava.Ui.Models
string aValue = (x as ApplicationData).TimePlayed;
string bValue = (y as ApplicationData).TimePlayed;
if (aValue[^2..] == "GB")
if (aValue[^3..] == "GiB")
{
aValue = (float.Parse(aValue[0..^2]) * 1024).ToString();
aValue = (float.Parse(aValue[0..^3]) * 1024).ToString();
}
else
{
aValue = aValue[0..^2];
aValue = aValue[0..^3];
}
if (bValue[^2..] == "GB")
if (bValue[^3..] == "GiB")
{
bValue = (float.Parse(bValue[0..^2]) * 1024).ToString();
bValue = (float.Parse(bValue[0..^3]) * 1024).ToString();
}
else
{
bValue = bValue[0..^2];
bValue = bValue[0..^3];
}
if (float.Parse(aValue) > float.Parse(bValue))

View File

@ -15,22 +15,22 @@ namespace Ryujinx.Ava.Ui.Models.Generic
string aValue = x.FileSize;
string bValue = y.FileSize;
if (aValue[^2..] == "GB")
if (aValue[^3..] == "GiB")
{
aValue = (float.Parse(aValue[0..^2]) * 1024).ToString();
aValue = (float.Parse(aValue[0..^3]) * 1024).ToString();
}
else
{
aValue = aValue[0..^2];
aValue = aValue[0..^3];
}
if (bValue[^2..] == "GB")
if (bValue[^3..] == "GiB")
{
bValue = (float.Parse(bValue[0..^2]) * 1024).ToString();
bValue = (float.Parse(bValue[0..^3]) * 1024).ToString();
}
else
{
bValue = bValue[0..^2];
bValue = bValue[0..^3];
}
if (float.Parse(aValue) > float.Parse(bValue))

View File

@ -8,6 +8,7 @@ using Ryujinx.Ava.Ui.Models;
using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Utilities;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@ -189,7 +190,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
amiiboJsonString = File.ReadAllText(_amiiboJsonPath);
if (await NeedsUpdate(JsonSerializer.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated))
if (await NeedsUpdate(JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated))
{
amiiboJsonString = await DownloadAmiiboJson();
}
@ -206,7 +207,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
}
}
_amiiboList = JsonSerializer.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo;
_amiiboList = JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo;
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
ParseAmiiboData();

View File

@ -460,8 +460,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Configuration, $"{GetShortGamepadName(gamepad.Name)} has been connected with ID: {gamepad.Id}");
if (gamepad != null)
{
Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}"));
@ -472,8 +470,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
using IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Configuration, $"{GetShortGamepadName(gamepad.Name)} has been connected with ID: {gamepad.Id}");
if (gamepad != null)
{
if (Devices.Any(controller => GetShortGamepadId(controller.Id) == GetShortGamepadId(gamepad.Id)))

View File

@ -19,6 +19,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.Modules;
using Ryujinx.Ui.App.Common;
using Ryujinx.Ui.Common;
@ -47,6 +48,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
private string _loadHeading;
private string _cacheLoadStatus;
private string _searchText;
private Timer _searchTimer;
private string _dockedStatusText;
private string _fifoStatusText;
private string _gameStatusText;
@ -115,10 +117,20 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
_searchText = value;
RefreshView();
_searchTimer?.Dispose();
_searchTimer = new Timer(TimerCallback, null, 1000, 0);
}
}
private void TimerCallback(object obj)
{
RefreshView();
_searchTimer.Dispose();
_searchTimer = null;
}
public ReadOnlyObservableCollection<ApplicationData> AppsObservableList
{
get => _appsObservableList;
@ -200,22 +212,19 @@ namespace Ryujinx.Ava.Ui.ViewModels
private string _showUikey = "F4";
private string _pauseKey = "F5";
private string _screenshotkey = "F8";
private float _volume;
private float _volume;
private string _backendText;
public ApplicationData SelectedApplication
{
get
{
switch (Glyph)
return Glyph switch
{
case Glyph.List:
return _owner.GameList.SelectedApplication;
case Glyph.Grid:
return _owner.GameGrid.SelectedApplication;
default:
return null;
}
Glyph.List => _owner.GameList.SelectedApplication,
Glyph.Grid => _owner.GameGrid.SelectedApplication,
_ => null,
};
}
}
@ -408,6 +417,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
_owner.AppHost.Device.SetVolume(_volume);
}
OnPropertyChanged(nameof(VolumeStatusText));
OnPropertyChanged(nameof(VolumeMuted));
OnPropertyChanged();
@ -477,38 +487,36 @@ namespace Ryujinx.Ava.Ui.ViewModels
internal void Sort(bool isAscending)
{
IsAscending = isAscending;
RefreshView();
}
internal void Sort(ApplicationSort sort)
{
SortMode = sort;
RefreshView();
}
private IComparer<ApplicationData> GetComparer()
{
switch (SortMode)
return SortMode switch
{
case ApplicationSort.LastPlayed:
return new Models.Generic.LastPlayedSortComparer(IsAscending);
case ApplicationSort.FileSize:
return new Models.Generic.FileSizeSortComparer(IsAscending);
case ApplicationSort.TotalTimePlayed:
return new Models.Generic.TimePlayedSortComparer(IsAscending);
case ApplicationSort.Title:
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName) : SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName);
case ApplicationSort.Favorite:
return !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite) : SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite);
case ApplicationSort.Developer:
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer) : SortExpressionComparer<ApplicationData>.Descending(app => app.Developer);
case ApplicationSort.FileType:
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension) : SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension);
case ApplicationSort.Path:
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path) : SortExpressionComparer<ApplicationData>.Descending(app => app.Path);
default:
return null;
}
ApplicationSort.LastPlayed => new Models.Generic.LastPlayedSortComparer(IsAscending),
ApplicationSort.FileSize => new Models.Generic.FileSizeSortComparer(IsAscending),
ApplicationSort.TotalTimePlayed => new Models.Generic.TimePlayedSortComparer(IsAscending),
ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName)
: SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName),
ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite)
: SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite),
ApplicationSort.Developer => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer)
: SortExpressionComparer<ApplicationData>.Descending(app => app.Developer),
ApplicationSort.FileType => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension)
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension),
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
_ => null,
};
}
private void RefreshView()
@ -611,40 +619,31 @@ namespace Ryujinx.Ava.Ui.ViewModels
}
}
public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite;
public bool IsSortedByTitle => SortMode == ApplicationSort.Title;
public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer;
public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite;
public bool IsSortedByTitle => SortMode == ApplicationSort.Title;
public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer;
public bool IsSortedByLastPlayed => SortMode == ApplicationSort.LastPlayed;
public bool IsSortedByTimePlayed => SortMode == ApplicationSort.TotalTimePlayed;
public bool IsSortedByType => SortMode == ApplicationSort.FileType;
public bool IsSortedBySize => SortMode == ApplicationSort.FileSize;
public bool IsSortedByPath => SortMode == ApplicationSort.Path;
public bool IsSortedByType => SortMode == ApplicationSort.FileType;
public bool IsSortedBySize => SortMode == ApplicationSort.FileSize;
public bool IsSortedByPath => SortMode == ApplicationSort.Path;
public string SortName
{
get
{
switch (SortMode)
return SortMode switch
{
case ApplicationSort.Title:
return LocaleManager.Instance["GameListHeaderApplication"];
case ApplicationSort.Developer:
return LocaleManager.Instance["GameListHeaderDeveloper"];
case ApplicationSort.LastPlayed:
return LocaleManager.Instance["GameListHeaderLastPlayed"];
case ApplicationSort.TotalTimePlayed:
return LocaleManager.Instance["GameListHeaderTimePlayed"];
case ApplicationSort.FileType:
return LocaleManager.Instance["GameListHeaderFileExtension"];
case ApplicationSort.FileSize:
return LocaleManager.Instance["GameListHeaderFileSize"];
case ApplicationSort.Path:
return LocaleManager.Instance["GameListHeaderPath"];
case ApplicationSort.Favorite:
return LocaleManager.Instance["CommonFavorite"];
}
return string.Empty;
ApplicationSort.Title => LocaleManager.Instance["GameListHeaderApplication"],
ApplicationSort.Developer => LocaleManager.Instance["GameListHeaderDeveloper"],
ApplicationSort.LastPlayed => LocaleManager.Instance["GameListHeaderLastPlayed"],
ApplicationSort.TotalTimePlayed => LocaleManager.Instance["GameListHeaderTimePlayed"],
ApplicationSort.FileType => LocaleManager.Instance["GameListHeaderFileExtension"],
ApplicationSort.FileSize => LocaleManager.Instance["GameListHeaderFileSize"],
ApplicationSort.Path => LocaleManager.Instance["GameListHeaderPath"],
ApplicationSort.Favorite => LocaleManager.Instance["CommonFavorite"],
_ => string.Empty,
};
}
}
@ -668,6 +667,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
get => KeyGesture.Parse(_showUikey); set
{
_showUikey = value.ToString();
OnPropertyChanged();
}
}
@ -677,6 +677,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
get => KeyGesture.Parse(_screenshotkey); set
{
_screenshotkey = value.ToString();
OnPropertyChanged();
}
}
@ -686,14 +687,15 @@ namespace Ryujinx.Ava.Ui.ViewModels
get => KeyGesture.Parse(_pauseKey); set
{
_pauseKey = value.ToString();
OnPropertyChanged();
}
}
public bool IsGridSmall => ConfigurationState.Instance.Ui.GridSize == 1;
public bool IsGridSmall => ConfigurationState.Instance.Ui.GridSize == 1;
public bool IsGridMedium => ConfigurationState.Instance.Ui.GridSize == 2;
public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3;
public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4;
public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3;
public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4;
public int GridSizeScale
{
@ -728,14 +730,14 @@ namespace Ryujinx.Ava.Ui.ViewModels
if (_owner.AppHost.Device.System.SearchingForAmiibo(out int deviceId))
{
string titleId = _owner.AppHost.Device.Application.TitleIdText.ToUpper();
string titleId = _owner.AppHost.Device.Application.TitleIdText.ToUpper();
AmiiboWindow window = new(_showAll, _lastScannedAmiiboId, titleId);
await window.ShowDialog(_owner);
if (window.IsScanned)
{
_showAll = window.ViewModel.ShowAllAmiibo;
_showAll = window.ViewModel.ShowAllAmiibo;
_lastScannedAmiiboId = window.ScannedAmiibo.GetId();
_owner.AppHost.Device.System.ScanAmiibo(deviceId, _lastScannedAmiiboId, window.ViewModel.UseRandomUuid);
@ -766,8 +768,9 @@ namespace Ryujinx.Ava.Ui.ViewModels
private void ApplicationLibrary_ApplicationCountUpdated(object sender, ApplicationCountUpdatedEventArgs e)
{
StatusBarProgressValue = e.NumAppsLoaded;
StatusBarProgressValue = e.NumAppsLoaded;
StatusBarProgressMaximum = e.NumAppsFound;
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", StatusBarProgressValue, StatusBarProgressMaximum);
Dispatcher.UIThread.Post(() =>
@ -792,9 +795,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
await Dispatcher.UIThread.InvokeAsync(() =>
{
Applications.Clear();
_owner.LoadProgressBar.IsVisible = true;
StatusBarProgressMaximum = 0;
StatusBarProgressValue = 0;
StatusBarProgressMaximum = 0;
StatusBarProgressValue = 0;
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", 0, 0);
});
@ -842,12 +847,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
}
});
dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } });
dialog.Filters.Add(new FileDialogFilter { Name = "PFS0", Extensions = { "pfs0" } });
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NCA", Extensions = { "nca" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NRO", Extensions = { "nro" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NSO", Extensions = { "nso" } });
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NCA", Extensions = { "nca" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NRO", Extensions = { "nro" } });
dialog.Filters.Add(new FileDialogFilter { Name = "NSO", Extensions = { "nso" } });
string[] files = await dialog.ShowAsync(_owner);
@ -878,10 +883,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
ShowUiKey = new KeyGesture(showUiKey, KeyModifiers.None);
}
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
{
ScreenshotKey = new KeyGesture(screenshotKey, KeyModifiers.None);
}
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
{
PauseKey = new KeyGesture(pauseKey, KeyModifiers.None);
@ -941,9 +948,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
_lastFullscreenToggle = Environment.TickCount64;
WindowState state = _owner.WindowState;
if (state == WindowState.FullScreen)
if (_owner.WindowState == WindowState.FullScreen)
{
_owner.WindowState = WindowState.Normal;
@ -971,8 +976,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
if (IsGameRunning)
{
ConfigurationState.Instance.System.EnableDockedMode.Value =
!ConfigurationState.Instance.System.EnableDockedMode.Value;
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
}
}
@ -985,6 +989,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
else if (IsGameRunning)
{
await Task.Delay(100);
_owner.AppHost?.ShowExitPrompt();
}
}
@ -994,6 +999,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
_owner.SettingsWindow = new(_owner.VirtualFileSystem, _owner.ContentManager);
await _owner.SettingsWindow.ShowDialog(_owner);
LoadConfigurableHotKeys();
}
@ -1004,9 +1010,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
public async void OpenAboutWindow()
{
AboutWindow window = new();
await window.ShowDialog(_owner);
await new AboutWindow().ShowDialog(_owner);
}
public void ChangeLanguage(object obj)
@ -1020,7 +1024,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
try
{
ProgressMaximum = total;
ProgressValue = current;
ProgressValue = current;
switch (state)
{
@ -1030,13 +1034,13 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
case PtcLoadingState.Start:
case PtcLoadingState.Loading:
LoadHeading = LocaleManager.Instance["CompilingPPTC"];
LoadHeading = LocaleManager.Instance["CompilingPPTC"];
IsLoadingIndeterminate = false;
break;
case PtcLoadingState.Loaded:
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
IsLoadingIndeterminate = true;
CacheLoadStatus = "";
CacheLoadStatus = "";
break;
}
break;
@ -1046,13 +1050,13 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
case ShaderCacheLoadingState.Start:
case ShaderCacheLoadingState.Loading:
LoadHeading = LocaleManager.Instance["CompilingShaders"];
LoadHeading = LocaleManager.Instance["CompilingShaders"];
IsLoadingIndeterminate = false;
break;
case ShaderCacheLoadingState.Loaded:
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
IsLoadingIndeterminate = true;
CacheLoadStatus = "";
CacheLoadStatus = "";
break;
}
break;
@ -1065,14 +1069,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void OpenUserSaveDirectory()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
Task.Run(() =>
{
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
out ulong titleIdNumber))
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
{
Dispatcher.UIThread.Post(async () =>
{
@ -1082,8 +1084,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
return;
}
var userId = new LibHac.Fs.UserId((ulong)_owner.AccountManager.LastOpenedUser.UserId.High, (ulong)_owner.AccountManager.LastOpenedUser.UserId.Low);
var saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveType: default, userId, saveDataId: default, index: default);
UserId userId = new((ulong)_owner.AccountManager.LastOpenedUser.UserId.High, (ulong)_owner.AccountManager.LastOpenedUser.UserId.Low);
SaveDataFilter saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveType: default, userId, saveDataId: default, index: default);
OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber);
});
}
@ -1091,8 +1093,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void ToggleFavorite()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
selection.Favorite = !selection.Favorite;
@ -1108,11 +1109,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void OpenModsDirectory()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
string modsBasePath = _owner.VirtualFileSystem.ModLoader.GetModsBasePath();
string modsBasePath = _owner.VirtualFileSystem.ModLoader.GetModsBasePath();
string titleModsPath = _owner.VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, selection.TitleId);
OpenHelper.OpenFolder(titleModsPath);
@ -1121,12 +1121,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void OpenSdModsDirectory()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
string sdModsBasePath = _owner.VirtualFileSystem.ModLoader.GetSdModsBasePath();
string titleModsPath = _owner.VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, selection.TitleId);
string titleModsPath = _owner.VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, selection.TitleId);
OpenHelper.OpenFolder(titleModsPath);
}
@ -1134,13 +1134,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void OpenPtcDirectory()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu");
string mainPath = Path.Combine(ptcDir, "0");
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu");
string mainPath = Path.Combine(ptcDir, "0");
string backupPath = Path.Combine(ptcDir, "1");
if (!Directory.Exists(ptcDir))
@ -1156,16 +1154,18 @@ namespace Ryujinx.Ava.Ui.ViewModels
public async void PurgePtcCache()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "0"));
DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "0"));
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName), LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], LocaleManager.Instance["RyujinxConfirm"]);
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName),
LocaleManager.Instance["InputDialogYes"],
LocaleManager.Instance["InputDialogNo"],
LocaleManager.Instance["RyujinxConfirm"]);
List<FileInfo> cacheFiles = new();
@ -1198,8 +1198,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void OpenShaderCacheDirectory()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader");
@ -1220,18 +1219,20 @@ namespace Ryujinx.Ava.Ui.ViewModels
public async void PurgeShaderCache()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"));
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName), LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], LocaleManager.Instance["RyujinxConfirm"]);
string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName),
LocaleManager.Instance["InputDialogYes"],
LocaleManager.Instance["InputDialogNo"],
LocaleManager.Instance["RyujinxConfirm"]);
List<DirectoryInfo> oldCacheDirectories = new List<DirectoryInfo>();
List<FileInfo> newCacheFiles = new List<FileInfo>();
List<DirectoryInfo> oldCacheDirectories = new();
List<FileInfo> newCacheFiles = new();
if (shaderCacheDir.Exists)
{
@ -1279,38 +1280,28 @@ namespace Ryujinx.Ava.Ui.ViewModels
public async void OpenTitleUpdateManager()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
TitleUpdateWindow titleUpdateManager =
new(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName);
await titleUpdateManager.ShowDialog(_owner);
await new TitleUpdateWindow(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(_owner);
}
}
public async void OpenDownloadableContentManager()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
DownloadableContentManagerWindow downloadableContentManager = new(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName);
await downloadableContentManager.ShowDialog(_owner);
await new DownloadableContentManagerWindow(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(_owner);
}
}
public async void OpenCheatManager()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
CheatWindow cheatManager = new(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName);
await cheatManager.ShowDialog(_owner);
await new CheatWindow(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName).ShowDialog(_owner);
}
}
@ -1321,13 +1312,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
return;
}
var application = _owner.AppHost.Device.Application;
ApplicationLoader application = _owner.AppHost.Device.Application;
if (application != null)
{
CheatWindow cheatManager = new(_owner.VirtualFileSystem, application.TitleIdText, application.TitleName);
await cheatManager.ShowDialog(_owner);
await new CheatWindow(_owner.VirtualFileSystem, application.TitleIdText, application.TitleName).ShowDialog(_owner);
_owner.AppHost.Device.EnableCheats();
}
@ -1335,14 +1323,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void OpenDeviceSaveDirectory()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
Task.Run(() =>
{
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
out ulong titleIdNumber))
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
{
Dispatcher.UIThread.Post(async () =>
{
@ -1360,14 +1346,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void OpenBcatSaveDirectory()
{
var selection = SelectedApplication;
ApplicationData selection = SelectedApplication;
if (selection != null)
{
Task.Run(() =>
{
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
out ulong titleIdNumber))
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
{
Dispatcher.UIThread.Post(async () =>
{
@ -1420,12 +1404,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
_owner.Close();
}
private async Task HandleFirmwareInstallation(string path)
private async Task HandleFirmwareInstallation(string filename)
{
try
{
string filename = path;
SystemVersion firmwareVersion = _owner.ContentManager.VerifyFirmwarePackage(filename);
if (firmwareVersion == null)
@ -1437,7 +1419,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
string dialogTitle = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallTitle"], firmwareVersion.VersionString);
SystemVersion currentVersion = _owner.ContentManager.GetCurrentFirmwareVersion();
string dialogMessage = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallMessage"], firmwareVersion.VersionString);
@ -1480,11 +1461,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSuccessMessage"], firmwareVersion.VersionString);
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]);
Logger.Info?.Print(LogClass.Application, message);
// Purge Applet Cache.
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
if (miiEditorCacheFolder.Exists)
{
@ -1514,8 +1496,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
catch (LibHac.Common.Keys.MissingKeyException ex)
{
Logger.Error?.Print(LogClass.Application, ex.ToString());
Dispatcher.UIThread.Post(async () => await
UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, _owner));
Dispatcher.UIThread.Post(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, _owner));
}
catch (Exception ex)
{
@ -1527,8 +1509,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
OpenFileDialog dialog = new() { AllowMultiple = false };
dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance["FileDialogAllTypes"], Extensions = { "xci", "zip" } });
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } });
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } });
string[] file = await dialog.ShowAsync(_owner);

View File

@ -21,14 +21,10 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.Input;
using Ryujinx.Ui.Common.Configuration;
using Ryujinx.Ui.Common.Configuration.System;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
namespace Ryujinx.Ava.Ui.ViewModels
@ -138,6 +134,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
public bool ExpandDramSize { get; set; }
public bool EnableShaderCache { get; set; }
public bool EnableTextureRecompression { get; set; }
public bool EnableMacroHLE { get; set; }
public bool EnableFileLog { get; set; }
public bool EnableStub { get; set; }
public bool EnableInfo { get; set; }
@ -339,6 +336,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
ExpandDramSize = config.System.ExpandRam;
EnableShaderCache = config.Graphics.EnableShaderCache;
EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
EnableMacroHLE = config.Graphics.EnableMacroHLE;
EnableFileLog = config.Logger.EnableFileLog;
EnableStub = config.Logger.EnableStub;
EnableInfo = config.Logger.EnableInfo;
@ -422,6 +420,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
config.Graphics.EnableVsync.Value = EnableVsync;
config.Graphics.EnableShaderCache.Value = EnableShaderCache;
config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
config.Graphics.EnableMacroHLE.Value = EnableMacroHLE;
config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
config.System.EnablePtc.Value = EnablePptc;
config.System.EnableInternetAccess.Value = EnableInternetAccess;

View File

@ -3,89 +3,128 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Width="800"
Height="500"
MinWidth="800"
MinHeight="500"
MaxWidth="800"
MaxHeight="500"
SizeToContent="Height"
Width="600" MinHeight="500" Height="500"
WindowStartupLocation="CenterOwner"
MinWidth="600"
mc:Ignorable="d">
<Grid Name="DownloadableContentGrid" Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Name="Heading"
Grid.Row="1"
MaxWidth="500"
Margin="20,15,20,20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MaxWidth="500"
LineHeight="18"
TextWrapping="Wrap"
Text="{Binding Heading}"
TextAlignment="Center" />
<Border
TextAlignment="Center"
TextWrapping="Wrap" />
<DockPanel
Grid.Row="2"
Margin="0"
HorizontalAlignment="Left">
<Button
Name="EnableAllButton"
MinWidth="90"
Margin="5"
Command="{Binding EnableAll}">
<TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" />
</Button>
<Button
Name="DisableAllButton"
MinWidth="90"
Margin="5"
Command="{Binding DisableAll}">
<TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" />
</Button>
</DockPanel>
<Border
Grid.Row="3"
Margin="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
BorderBrush="Gray"
BorderThickness="1">
<DataGrid
MinHeight="200"
HorizontalAlignment="Stretch"
<ScrollViewer
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
Items="{Binding DownloadableContents}"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTemplateColumn Width="90">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Width="50"
MinWidth="40"
HorizontalAlignment="Right"
IsChecked="{Binding Enabled}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.Header>
<TextBlock Text="{locale:Locale DlcManagerTableHeadingEnabledLabel}" />
</DataGridTemplateColumn.Header>
</DataGridTemplateColumn>
<DataGridTextColumn
Width="190"
Binding="{Binding TitleId}"
CanUserResize="True">
<DataGridTextColumn.Header>
<TextBlock Text="{locale:Locale DlcManagerTableHeadingTitleIdLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn
Width="*"
Binding="{Binding ContainerPath}"
CanUserResize="True">
<DataGridTextColumn.Header>
<TextBlock Text="{locale:Locale DlcManagerTableHeadingContainerPathLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn
Width="*"
Binding="{Binding FullPath}"
CanUserResize="True">
<DataGridTextColumn.Header>
<TextBlock Text="{locale:Locale DlcManagerTableHeadingFullPathLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<DataGrid
Name="DlcDataGrid"
MinHeight="200"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CanUserReorderColumns="False"
CanUserResizeColumns="True"
CanUserSortColumns="True"
HorizontalScrollBarVisibility="Auto"
Items="{Binding _downloadableContents}"
SelectionMode="Extended"
VerticalScrollBarVisibility="Auto">
<DataGrid.Styles>
<Styles>
<Style Selector="DataGridCell:nth-child(3), DataGridCell:nth-child(4)">
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
</Style>
</Styles>
<Styles>
<Style Selector="DataGridCell:nth-child(1)">
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="HorizontalContentAlignment" Value="Right" />
</Style>
</Styles>
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridTemplateColumn Width="90">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Width="50"
MinWidth="40"
HorizontalAlignment="Center"
IsChecked="{Binding Enabled}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.Header>
<TextBlock Text="{locale:Locale DlcManagerTableHeadingEnabledLabel}" />
</DataGridTemplateColumn.Header>
</DataGridTemplateColumn>
<DataGridTextColumn Width="140" Binding="{Binding TitleId}">
<DataGridTextColumn.Header>
<TextBlock Text="{locale:Locale DlcManagerTableHeadingTitleIdLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Width="280" Binding="{Binding FullPath}">
<DataGridTextColumn.Header>
<TextBlock Text="{locale:Locale DlcManagerTableHeadingFullPathLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding ContainerPath}">
<DataGridTextColumn.Header>
<TextBlock Text="{locale:Locale DlcManagerTableHeadingContainerPathLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
</Border>
<DockPanel
Grid.Row="3"
Grid.Row="4"
Margin="0"
HorizontalAlignment="Stretch">
<DockPanel Margin="0" HorizontalAlignment="Left">

View File

@ -18,6 +18,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using Path = System.IO.Path;
@ -27,14 +28,13 @@ namespace Ryujinx.Ava.Ui.Windows
public partial class DownloadableContentManagerWindow : StyleableWindow
{
private readonly List<DownloadableContentContainer> _downloadableContentContainerList;
private readonly string _downloadableContentJsonPath;
private readonly string _downloadableContentJsonPath;
public VirtualFileSystem VirtualFileSystem { get; }
public AvaloniaList<DownloadableContentModel> DownloadableContents { get; set; } = new AvaloniaList<DownloadableContentModel>();
public ulong TitleId { get; }
public string TitleName { get; }
private VirtualFileSystem _virtualFileSystem { get; }
private AvaloniaList<DownloadableContentModel> _downloadableContents { get; set; }
public string Heading => string.Format(LocaleManager.Instance["DlcWindowHeading"], TitleName, TitleId.ToString("X16"));
private ulong _titleId { get; }
private string _titleName { get; }
public DownloadableContentManagerWindow()
{
@ -42,14 +42,16 @@ namespace Ryujinx.Ava.Ui.Windows
InitializeComponent();
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["DlcWindowTitle"];
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {_titleName} ({_titleId:X16})";
}
public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
{
VirtualFileSystem = virtualFileSystem;
TitleId = titleId;
TitleName = titleName;
_virtualFileSystem = virtualFileSystem;
_downloadableContents = new AvaloniaList<DownloadableContentModel>();
_titleId = titleId;
_titleName = titleName;
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json");
@ -66,9 +68,24 @@ namespace Ryujinx.Ava.Ui.Windows
InitializeComponent();
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["DlcWindowTitle"];
RemoveButton.IsEnabled = false;
DlcDataGrid.SelectionChanged += DlcDataGrid_SelectionChanged;
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {_titleName} ({_titleId:X16})";
LoadDownloadableContents();
PrintHeading();
}
private void DlcDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
RemoveButton.IsEnabled = (DlcDataGrid.SelectedItems.Count > 0);
}
private void PrintHeading()
{
Heading.Text = string.Format(LocaleManager.Instance["DlcWindowHeading"], _downloadableContents.Count, _titleName, _titleId.ToString("X16"));
}
private void LoadDownloadableContents()
@ -79,23 +96,23 @@ namespace Ryujinx.Ava.Ui.Windows
{
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
VirtualFileSystem.ImportTickets(pfs);
_virtualFileSystem.ImportTickets(partitionFileSystem);
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
{
using var ncaFile = new UniqueRef<IFile>();
using UniqueRef<IFile> ncaFile = new();
pfs.OpenFile(ref ncaFile.Ref(), downloadableContentNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
partitionFileSystem.OpenFile(ref ncaFile.Ref(), downloadableContentNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath);
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath);
if (nca != null)
{
DownloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"),
downloadableContentContainer.ContainerPath,
downloadableContentNca.FullPath,
downloadableContentNca.Enabled));
_downloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"),
downloadableContentContainer.ContainerPath,
downloadableContentNca.FullPath,
downloadableContentNca.Enabled));
}
}
}
@ -105,11 +122,11 @@ namespace Ryujinx.Ava.Ui.Windows
Save();
}
private Nca TryCreateNca(IStorage ncaStorage, string containerPath)
private Nca TryOpenNca(IStorage ncaStorage, string containerPath)
{
try
{
return new Nca(VirtualFileSystem.KeySet, ncaStorage);
return new Nca(_virtualFileSystem.KeySet, ncaStorage);
}
catch (Exception ex)
{
@ -124,61 +141,73 @@ namespace Ryujinx.Ava.Ui.Windows
private async Task AddDownloadableContent(string path)
{
if (!File.Exists(path) || DownloadableContents.FirstOrDefault(x => x.ContainerPath == path) != null)
if (!File.Exists(path) || _downloadableContents.FirstOrDefault(x => x.ContainerPath == path) != null)
{
return;
}
using (FileStream containerFile = File.OpenRead(path))
using FileStream containerFile = File.OpenRead(path);
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
bool containsDownloadableContent = false;
_virtualFileSystem.ImportTickets(partitionFileSystem);
foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca"))
{
PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
bool containsDownloadableContent = false;
using var ncaFile = new UniqueRef<IFile>();
VirtualFileSystem.ImportTickets(pfs);
partitionFileSystem.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), path);
if (nca == null)
{
using var ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), path);
if (nca == null)
{
continue;
}
if (nca.Header.ContentType == NcaContentType.PublicData)
{
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != TitleId)
{
break;
}
DownloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true));
containsDownloadableContent = true;
}
continue;
}
if (!containsDownloadableContent)
if (nca.Header.ContentType == NcaContentType.PublicData)
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]);
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != _titleId)
{
break;
}
_downloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true));
containsDownloadableContent = true;
}
}
if (!containsDownloadableContent)
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]);
}
}
private void RemoveDownloadableContents(bool removeSelectedOnly = false)
{
if (removeSelectedOnly)
{
DownloadableContents.RemoveAll(DownloadableContents.Where(x => x.Enabled).ToList());
AvaloniaList<DownloadableContentModel> removedItems = new();
foreach (var item in DlcDataGrid.SelectedItems)
{
removedItems.Add(item as DownloadableContentModel);
}
DlcDataGrid.SelectedItems.Clear();
foreach (var item in removedItems)
{
_downloadableContents.RemoveAll(_downloadableContents.Where(x => x.TitleId == item.TitleId).ToList());
}
}
else
{
DownloadableContents.Clear();
_downloadableContents.Clear();
}
PrintHeading();
}
public void RemoveSelected()
@ -191,6 +220,22 @@ namespace Ryujinx.Ava.Ui.Windows
RemoveDownloadableContents();
}
public void EnableAll()
{
foreach(var item in _downloadableContents)
{
item.Enabled = true;
}
}
public void DisableAll()
{
foreach (var item in _downloadableContents)
{
item.Enabled = false;
}
}
public async void Add()
{
OpenFileDialog dialog = new OpenFileDialog()
@ -214,6 +259,8 @@ namespace Ryujinx.Ava.Ui.Windows
await AddDownloadableContent(file);
}
}
PrintHeading();
}
public void Save()
@ -222,7 +269,7 @@ namespace Ryujinx.Ava.Ui.Windows
DownloadableContentContainer container = default;
foreach (DownloadableContentModel downloadableContent in DownloadableContents)
foreach (DownloadableContentModel downloadableContent in _downloadableContents)
{
if (container.ContainerPath != downloadableContent.ContainerPath)
{

View File

@ -13,7 +13,7 @@
Title="Ryujinx"
Width="1280"
Height="785"
MinWidth="1024"
MinWidth="1092"
MinHeight="680"
d:DesignHeight="720"
d:DesignWidth="1280"
@ -57,6 +57,8 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel
Name="MenuBar"
MinHeight="35"
Grid.Row="0"
Margin="0"
HorizontalAlignment="Stretch"
@ -549,6 +551,7 @@
<Grid
Name="StatusBar"
Grid.Row="2"
MinHeight="30"
Height="30"
Margin="0,0"
HorizontalAlignment="Stretch"

View File

@ -23,6 +23,7 @@ using Ryujinx.Modules;
using Ryujinx.Ui.App.Common;
using Ryujinx.Ui.Common;
using Ryujinx.Ui.Common.Configuration;
using Ryujinx.Ui.Common.Helper;
using SixLabors.ImageSharp.PixelFormats;
using System;
using System.ComponentModel;
@ -89,8 +90,10 @@ namespace Ryujinx.Ava.Ui.Windows
Title = $"Ryujinx {Program.Version}";
Height = Height / Program.WindowScaleFactor;
Width = Width / Program.WindowScaleFactor;
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
double barHeight = MenuBar.MinHeight + StatusBar.MinHeight;
Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight;
Width /= Program.WindowScaleFactor;
if (Program.PreviewerDetached)
{
@ -247,27 +250,32 @@ namespace Ryujinx.Ava.Ui.Windows
{
RendererControl.CreateVulkan();
}
AppHost = new AppHost(RendererControl, InputManager, path, VirtualFileSystem, ContentManager, AccountManager, _userChannelPersistence, this);
if (!AppHost.LoadGuestApplication().Result)
Dispatcher.UIThread.Post(async () =>
{
AppHost.DisposeContext();
if (!await AppHost.LoadGuestApplication())
{
AppHost.DisposeContext();
AppHost = null;
return;
}
return;
}
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
SwitchToGameControl(startFullscreen);
SwitchToGameControl(startFullscreen);
_currentEmulatedGamePath = path;
Thread gameThread = new Thread(InitializeGame)
{
Name = "GUI.WindowThread"
};
gameThread.Start();
_currentEmulatedGamePath = path;
Thread gameThread = new(InitializeGame)
{
Name = "GUI.WindowThread"
};
gameThread.Start();
});
}
private void InitializeGame()
@ -432,7 +440,7 @@ namespace Ryujinx.Ava.Ui.Windows
// Consider removing this at some point in the future when we don't need to worry about old saves.
VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient);
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, Program.CommandLineProfile);
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, CommandLineState.Profile);
VirtualFileSystem.ReloadKeySet();
@ -517,22 +525,20 @@ namespace Ryujinx.Ava.Ui.Windows
public static void UpdateGraphicsConfig()
{
int resScale = ConfigurationState.Instance.Graphics.ResScale;
float resScaleCustom = ConfigurationState.Instance.Graphics.ResScaleCustom;
GraphicsConfig.ResScale = resScale == -1 ? resScaleCustom : resScale;
GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale;
GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
}
public void LoadHotKeys()
{
HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt));
HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt));
HotKeyManager.SetHotKey(FullscreenHotKey2, new KeyGesture(Key.F11));
HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9));
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9));
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
}
public static void SaveConfig()
@ -544,10 +550,12 @@ namespace Ryujinx.Ava.Ui.Windows
{
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
{
DateTime lastPlayedDateTime = DateTime.Parse(appMetadata.LastPlayed);
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
if (DateTime.TryParse(appMetadata.LastPlayed, out DateTime lastPlayedDateTime))
{
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
}
});
}

View File

@ -75,7 +75,7 @@
Spacing="10">
<ListBox
Name="GameList"
MinHeight="150"
MinHeight="250"
Items="{Binding GameDirectories}" />
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
@ -568,6 +568,10 @@
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
</CheckBox>
<CheckBox IsChecked="{Binding EnableMacroHLE}"
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
</CheckBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"

View File

@ -16,7 +16,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
namespace Ryujinx.Ava.Ui.Windows
@ -31,7 +30,7 @@ namespace Ryujinx.Ava.Ui.Windows
{
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["Settings"]}";
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
DataContext = ViewModel;
InitializeComponent();
@ -48,7 +47,7 @@ namespace Ryujinx.Ava.Ui.Windows
public SettingsWindow()
{
ViewModel = new SettingsViewModel();
ViewModel = new SettingsViewModel();
DataContext = ViewModel;
InitializeComponent();
@ -79,7 +78,7 @@ namespace Ryujinx.Ava.Ui.Windows
PointerPressed += MouseClick;
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad(ViewModel.AvaloniaKeyboardDriver.GamepadsIds[0]);
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad(ViewModel.AvaloniaKeyboardDriver.GamepadsIds[0]);
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
_currentAssigner.GetInputAndAssign(assigner);
@ -92,6 +91,7 @@ namespace Ryujinx.Ava.Ui.Windows
_currentAssigner.Cancel();
_currentAssigner = null;
button.IsChecked = false;
}
}
@ -122,36 +122,19 @@ namespace Ryujinx.Ava.Ui.Windows
{
if (e.SelectedItem is NavigationViewItem navitem)
{
switch (navitem.Tag.ToString())
NavPanel.Content = navitem.Tag.ToString() switch
{
case "UiPage":
NavPanel.Content = UiPage;
break;
case "InputPage":
NavPanel.Content = InputPage;
break;
case "HotkeysPage":
NavPanel.Content = HotkeysPage;
break;
case "SystemPage":
NavPanel.Content = SystemPage;
break;
case "CpuPage":
NavPanel.Content = CpuPage;
break;
case "GraphicsPage":
NavPanel.Content = GraphicsPage;
break;
case "AudioPage":
NavPanel.Content = AudioPage;
break;
case "NetworkPage":
NavPanel.Content = NetworkPage;
break;
case "LoggingPage":
NavPanel.Content = LoggingPage;
break;
}
"UiPage" => UiPage,
"InputPage" => InputPage,
"HotkeysPage" => HotkeysPage,
"SystemPage" => SystemPage,
"CpuPage" => CpuPage,
"GraphicsPage" => GraphicsPage,
"AudioPage" => AudioPage,
"NetworkPage" => NetworkPage,
"LoggingPage" => LoggingPage,
_ => throw new NotImplementedException()
};
}
}
@ -178,13 +161,18 @@ namespace Ryujinx.Ava.Ui.Windows
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
{
List<string> selected = new(GameList.SelectedItems.Cast<string>());
int oldIndex = GameList.SelectedIndex;
foreach (string path in selected)
foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>()))
{
ViewModel.GameDirectories.Remove(path);
ViewModel.DirectoryChanged = true;
}
if (GameList.ItemCount > 0)
{
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
}
}
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
@ -214,7 +202,6 @@ namespace Ryujinx.Ava.Ui.Windows
private void SaveButton_Clicked(object sender, RoutedEventArgs e)
{
SaveSettings();
Close();
}
@ -232,7 +219,6 @@ namespace Ryujinx.Ava.Ui.Windows
private void SaveSettings()
{
ViewModel.SaveSettings();
ControllerSettings?.SaveCurrentProfile();
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
@ -246,8 +232,10 @@ namespace Ryujinx.Ava.Ui.Windows
protected override void OnClosed(EventArgs e)
{
ControllerSettings.Dispose();
_currentAssigner?.Cancel();
_currentAssigner = null;
base.OnClosed(e);
}
}

View File

@ -3,13 +3,17 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
SizeToContent="Height"
Width="600" MinHeight="500" Height="500"
WindowStartupLocation="CenterOwner"
Width="600"
Height="400"
MinWidth="600"
MinHeight="400"
MaxWidth="600"
MaxHeight="400"
SizeToContent="Height"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
<Grid Margin="15">
<Grid.RowDefinitions>
@ -19,15 +23,15 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Name="Heading"
Grid.Row="1"
MaxWidth="500"
Margin="20,15,20,20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MaxWidth="500"
LineHeight="18"
TextWrapping="Wrap"
Text="{Binding Heading}"
TextAlignment="Center" />
TextAlignment="Center"
TextWrapping="Wrap" />
<Border
Grid.Row="2"
Margin="5"
@ -36,8 +40,6 @@
BorderBrush="Gray"
BorderThickness="1">
<ScrollViewer
Width="550"
MinHeight="200"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
@ -45,11 +47,19 @@
Margin="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Items="{Binding TitleUpdates}">
Items="{Binding _titleUpdates}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton Padding="8, 0" VerticalContentAlignment="Center" GroupName="Update" IsChecked="{Binding IsEnabled, Mode=TwoWay}">
<Label Margin="0" VerticalAlignment="Center" Content="{Binding Label}" />
<RadioButton
Padding="8,0"
VerticalContentAlignment="Center"
GroupName="Update"
IsChecked="{Binding IsEnabled, Mode=TwoWay}">
<Label
Margin="0"
VerticalAlignment="Center"
Content="{Binding Label}"
FontSize="12" />
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>

View File

@ -30,13 +30,11 @@ namespace Ryujinx.Ava.Ui.Windows
private readonly string _titleUpdateJsonPath;
private TitleUpdateMetadata _titleUpdateWindowData;
public VirtualFileSystem VirtualFileSystem { get; }
private VirtualFileSystem _virtualFileSystem { get; }
private AvaloniaList<TitleUpdateModel> _titleUpdates { get; set; }
internal AvaloniaList<TitleUpdateModel> TitleUpdates { get; set; } = new AvaloniaList<TitleUpdateModel>();
public string TitleId { get; }
public string TitleName { get; }
public string Heading => string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], TitleName, TitleId.ToUpper());
private ulong _titleId { get; }
private string _titleName { get; }
public TitleUpdateWindow()
{
@ -44,16 +42,18 @@ namespace Ryujinx.Ava.Ui.Windows
InitializeComponent();
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["UpdateWindowTitle"];
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
}
public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName)
public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
{
VirtualFileSystem = virtualFileSystem;
TitleId = titleId;
TitleName = titleName;
_virtualFileSystem = virtualFileSystem;
_titleUpdates = new AvaloniaList<TitleUpdateModel>();
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId, "updates.json");
_titleId = titleId;
_titleName = titleName;
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
try
{
@ -64,7 +64,7 @@ namespace Ryujinx.Ava.Ui.Windows
_titleUpdateWindowData = new TitleUpdateMetadata
{
Selected = "",
Paths = new List<string>()
Paths = new List<string>()
};
}
@ -72,14 +72,20 @@ namespace Ryujinx.Ava.Ui.Windows
InitializeComponent();
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["UpdateWindowTitle"];
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
LoadUpdates();
PrintHeading();
}
private void PrintHeading()
{
Heading.Text = string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], _titleUpdates.Count, _titleName, _titleId.ToString("X16"));
}
private void LoadUpdates()
{
TitleUpdates.Add(new TitleUpdateModel(default, string.Empty, true));
_titleUpdates.Add(new TitleUpdateModel(default, string.Empty, true));
foreach (string path in _titleUpdateWindowData.Paths)
{
@ -88,12 +94,12 @@ namespace Ryujinx.Ava.Ui.Windows
if (_titleUpdateWindowData.Selected == "")
{
TitleUpdates[0].IsEnabled = true;
_titleUpdates[0].IsEnabled = true;
}
else
{
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected);
List<TitleUpdateModel> enabled = TitleUpdates.Where(x => x.IsEnabled).ToList();
TitleUpdateModel selected = _titleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected);
List<TitleUpdateModel> enabled = _titleUpdates.Where(x => x.IsEnabled).ToList();
foreach (TitleUpdateModel update in enabled)
{
@ -111,43 +117,47 @@ namespace Ryujinx.Ava.Ui.Windows
private void AddUpdate(string path)
{
if (File.Exists(path) && !TitleUpdates.Any(x => x.Path == path))
if (File.Exists(path) && !_titleUpdates.Any(x => x.Path == path))
{
using (FileStream file = new(path, FileMode.Open, FileAccess.Read))
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
try
{
PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());
(Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
try
if (controlNca != null && patchNca != null)
{
(Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(VirtualFileSystem, nsp, TitleId, 0);
ApplicationControlProperty controlData = new();
if (controlNca != null && patchNca != null)
using UniqueRef<IFile> nacpFile = new();
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
_titleUpdates.Add(new TitleUpdateModel(controlData, path));
foreach (var update in _titleUpdates)
{
ApplicationControlProperty controlData = new ApplicationControlProperty();
using var nacpFile = new UniqueRef<IFile>();
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
}
else
{
Dispatcher.UIThread.Post(async () =>
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdateAddUpdateErrorMessage"]);
});
update.IsEnabled = false;
}
_titleUpdates.Last().IsEnabled = true;
}
catch (Exception ex)
else
{
Dispatcher.UIThread.Post(async () =>
{
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, path));
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdateAddUpdateErrorMessage"]);
});
}
}
catch (Exception ex)
{
Dispatcher.UIThread.Post(async () =>
{
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, path));
});
}
}
}
@ -155,16 +165,17 @@ namespace Ryujinx.Ava.Ui.Windows
{
if (removeSelectedOnly)
{
TitleUpdates.RemoveAll(TitleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList());
_titleUpdates.RemoveAll(_titleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList());
}
else
{
TitleUpdates.RemoveAll(TitleUpdates.Where(x => !x.IsNoUpdate).ToList());
_titleUpdates.RemoveAll(_titleUpdates.Where(x => !x.IsNoUpdate).ToList());
}
TitleUpdates.FirstOrDefault(x => x.IsNoUpdate).IsEnabled = true;
_titleUpdates.FirstOrDefault(x => x.IsNoUpdate).IsEnabled = true;
SortUpdates();
PrintHeading();
}
public void RemoveSelected()
@ -179,7 +190,7 @@ namespace Ryujinx.Ava.Ui.Windows
public async void Add()
{
OpenFileDialog dialog = new OpenFileDialog()
OpenFileDialog dialog = new()
{
Title = LocaleManager.Instance["SelectUpdateDialogTitle"],
AllowMultiple = true
@ -202,11 +213,12 @@ namespace Ryujinx.Ava.Ui.Windows
}
SortUpdates();
PrintHeading();
}
private void SortUpdates()
{
var list = TitleUpdates.ToList();
var list = _titleUpdates.ToList();
list.Sort((first, second) =>
{
@ -222,8 +234,8 @@ namespace Ryujinx.Ava.Ui.Windows
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
});
TitleUpdates.Clear();
TitleUpdates.AddRange(list);
_titleUpdates.Clear();
_titleUpdates.AddRange(list);
}
public void Save()
@ -232,7 +244,7 @@ namespace Ryujinx.Ava.Ui.Windows
_titleUpdateWindowData.Selected = "";
foreach (TitleUpdateModel update in TitleUpdates)
foreach (TitleUpdateModel update in _titleUpdates)
{
_titleUpdateWindowData.Paths.Add(update.Path);

View File

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Common
@ -7,49 +8,15 @@ namespace Ryujinx.Common
public static class BinaryReaderExtensions
{
public unsafe static T ReadStruct<T>(this BinaryReader reader)
where T : struct
where T : unmanaged
{
int size = Marshal.SizeOf<T>();
byte[] data = reader.ReadBytes(size);
fixed (byte* ptr = data)
{
return Marshal.PtrToStructure<T>((IntPtr)ptr);
}
}
public unsafe static T[] ReadStructArray<T>(this BinaryReader reader, int count)
where T : struct
{
int size = Marshal.SizeOf<T>();
T[] result = new T[count];
for (int i = 0; i < count; i++)
{
byte[] data = reader.ReadBytes(size);
fixed (byte* ptr = data)
{
result[i] = Marshal.PtrToStructure<T>((IntPtr)ptr);
}
}
return result;
return MemoryMarshal.Cast<byte, T>(reader.ReadBytes(Unsafe.SizeOf<T>()))[0];
}
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
where T : struct
where T : unmanaged
{
long size = Marshal.SizeOf<T>();
byte[] data = new byte[size];
fixed (byte* ptr = data)
{
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
}
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
writer.Write(data);
}

View File

@ -8,7 +8,7 @@
<ItemGroup>
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" />
<PackageReference Include="System.Management" Version="7.0.0" />
</ItemGroup>
</Project>

View File

@ -36,13 +36,13 @@ namespace Ryujinx.Common.SystemInfo
ParseKeyValues("/proc/meminfo", memDict);
// Entries are in KB
ulong.TryParse(memDict["MemTotal"]?.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong totalKB);
ulong.TryParse(memDict["MemAvailable"]?.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong availableKB);
// Entries are in KiB
ulong.TryParse(memDict["MemTotal"]?.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong totalKiB);
ulong.TryParse(memDict["MemAvailable"]?.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong availableKiB);
CpuName = $"{cpuName} ; {LogicalCoreCount} logical";
RamTotal = totalKB * 1024;
RamAvailable = availableKB * 1024;
RamTotal = totalKiB * 1024;
RamAvailable = availableKiB * 1024;
}
private static void ParseKeyValues(string filePath, Dictionary<string, string> itemDict)

View File

@ -20,13 +20,13 @@ namespace Ryujinx.Common.SystemInfo
CpuName = "Unknown";
}
private static string ToMBString(ulong bytesValue) => (bytesValue == 0) ? "Unknown" : $"{bytesValue / 1024 / 1024} MB";
private static string ToMiBString(ulong bytesValue) => (bytesValue == 0) ? "Unknown" : $"{bytesValue / 1024 / 1024} MiB";
public void Print()
{
Logger.Notice.Print(LogClass.Application, $"Operating System: {OsDescription}");
Logger.Notice.Print(LogClass.Application, $"CPU: {CpuName}");
Logger.Notice.Print(LogClass.Application, $"RAM: Total {ToMBString(RamTotal)} ; Available {ToMBString(RamAvailable)}");
Logger.Notice.Print(LogClass.Application, $"RAM: Total {ToMiBString(RamTotal)} ; Available {ToMiBString(RamAvailable)}");
}
public static SystemInfo Gather()

View File

@ -27,7 +27,7 @@ namespace Ryujinx.Cpu
long TpidrroEl0 { get; set; }
/// <summary>
/// Processor State register.
/// Processor State Register.
/// </summary>
uint Pstate { get; set; }
@ -109,4 +109,4 @@ namespace Ryujinx.Cpu
/// </remarks>
void StopRunning();
}
}
}

View File

@ -180,6 +180,37 @@ namespace Ryujinx.Cpu.Jit
WriteImpl(va, data);
}
/// <inheritdoc/>
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
{
if (data.Length == 0)
{
return false;
}
SignalMemoryTracking(va, (ulong)data.Length, false);
if (IsContiguousAndMapped(va, data.Length))
{
var target = _backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length);
bool changed = !data.SequenceEqual(target);
if (changed)
{
data.CopyTo(target);
}
return changed;
}
else
{
WriteImpl(va, data);
return true;
}
}
/// <summary>
/// Writes data to CPU mapped memory.
/// </summary>

View File

@ -307,6 +307,34 @@ namespace Ryujinx.Cpu.Jit
}
}
/// <inheritdoc/>
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
{
try
{
SignalMemoryTracking(va, (ulong)data.Length, false);
Span<byte> target = _addressSpaceMirror.GetSpan(va, data.Length);
bool changed = !data.SequenceEqual(target);
if (changed)
{
data.CopyTo(target);
}
return changed;
}
catch (InvalidMemoryRegionException)
{
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
{
throw;
}
return true;
}
}
/// <inheritdoc/>
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
{

View File

@ -1,6 +1,7 @@
using Ryujinx.Memory;
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
@ -23,34 +24,18 @@ namespace Ryujinx.Cpu
}
}
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : struct
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : unmanaged
{
long size = Marshal.SizeOf<T>();
byte[] data = new byte[size];
memory.Read(position, data);
fixed (byte* ptr = data)
{
return Marshal.PtrToStructure<T>((IntPtr)ptr);
}
return MemoryMarshal.Cast<byte, T>(memory.GetSpan(position, Unsafe.SizeOf<T>()))[0];
}
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : struct
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : unmanaged
{
long size = Marshal.SizeOf<T>();
byte[] data = new byte[size];
fixed (byte* ptr = data)
{
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
}
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
memory.Write(position, data);
return (ulong)size;
return (ulong)data.Length;
}
public static string ReadAsciiString(IVirtualMemoryManager memory, ulong position, long maxSize = -1)

View File

@ -0,0 +1,14 @@
namespace Ryujinx.Graphics.GAL
{
public struct BufferAssignment
{
public readonly int Binding;
public readonly BufferRange Range;
public BufferAssignment(int binding, BufferRange range)
{
Binding = binding;
Range = range;
}
}
}

View File

@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsFragmentShaderOrderingIntel;
public readonly bool SupportsGeometryShaderPassthrough;
public readonly bool SupportsImageLoadFormatted;
public readonly bool SupportsLayerVertexTessellation;
public readonly bool SupportsMismatchingViewFormat;
public readonly bool SupportsCubemapView;
public readonly bool SupportsNonConstantTextureOffset;
@ -55,6 +56,7 @@ namespace Ryujinx.Graphics.GAL
bool supportsFragmentShaderOrderingIntel,
bool supportsGeometryShaderPassthrough,
bool supportsImageLoadFormatted,
bool supportsLayerVertexTessellation,
bool supportsMismatchingViewFormat,
bool supportsCubemapView,
bool supportsNonConstantTextureOffset,
@ -86,6 +88,7 @@ namespace Ryujinx.Graphics.GAL
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
SupportsImageLoadFormatted = supportsImageLoadFormatted;
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
SupportsCubemapView = supportsCubemapView;
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;

View File

@ -34,13 +34,14 @@ namespace Ryujinx.Graphics.GAL
int firstIndex,
int firstVertex,
int firstInstance);
void DrawIndexedIndirect(BufferRange indirectBuffer);
void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
void DrawIndirect(BufferRange indirectBuffer);
void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion);
void EndTransformFeedback();
void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
void MultiDrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
void SetAlphaTest(bool enable, float reference, CompareOp op);
void SetBlendState(int index, BlendDescriptor blend);
@ -85,12 +86,12 @@ namespace Ryujinx.Graphics.GAL
void SetStencilTest(StencilTestDescriptor stencilTest);
void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers);
void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers);
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers);
void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);
void SetUserClipDistance(int index, bool enableClip);

View File

@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.GAL
ReadOnlySpan<byte> GetBufferData(BufferHandle buffer, int offset, int size);
Capabilities GetCapabilities();
ulong GetCurrentSync();
HardwareInfo GetHardwareInfo();
IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);

View File

@ -142,6 +142,30 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return ranges;
}
internal Span<BufferAssignment> MapBufferRanges(Span<BufferAssignment> ranges)
{
// Rewrite the buffer ranges to point to the mapped handles.
lock (_bufferMap)
{
for (int i = 0; i < ranges.Length; i++)
{
ref BufferAssignment assignment = ref ranges[i];
BufferRange range = assignment.Range;
BufferHandle result;
if (!_bufferMap.TryGetValue(range.Handle, out result))
{
result = BufferHandle.Null;
}
assignment = new BufferAssignment(ranges[i].Binding, new BufferRange(result, range.Offset, range.Size));
}
}
return ranges;
}
internal Span<VertexBufferDescriptor> MapBufferRanges(Span<VertexBufferDescriptor> ranges)
{
// Rewrite the buffer ranges to point to the mapped handles.

View File

@ -141,16 +141,20 @@ namespace Ryujinx.Graphics.GAL.Multithreading
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndexed] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndexedIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.EndHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
EndHostConditionalRenderingCommand.Run(renderer);
_lookup[(int)CommandType.EndTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.MultiDrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
MultiDrawIndirectCountCommand.Run(ref GetCommand<MultiDrawIndirectCountCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.MultiDrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
MultiDrawIndexedIndirectCountCommand.Run(ref GetCommand<MultiDrawIndexedIndirectCountCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetAlphaTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetBlendState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>

View File

@ -52,11 +52,13 @@
DispatchCompute,
Draw,
DrawIndexed,
DrawIndexedIndirect,
DrawIndexedIndirectCount,
DrawIndirect,
DrawIndirectCount,
DrawTexture,
EndHostConditionalRendering,
EndTransformFeedback,
MultiDrawIndirectCount,
MultiDrawIndexedIndirectCount,
SetAlphaTest,
SetBlendState,
SetDepthBias,

View File

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct DrawIndexedIndirectCommand : IGALCommand
{
public CommandType CommandType => CommandType.DrawIndexedIndirect;
private BufferRange _indirectBuffer;
public void Set(BufferRange indirectBuffer)
{
_indirectBuffer = indirectBuffer;
}
public static void Run(ref DrawIndexedIndirectCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.DrawIndexedIndirect(threaded.Buffers.MapBufferRange(command._indirectBuffer));
}
}
}

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