182 Commits
Author SHA1 Message Date
KeatonTheBot 72ecef8b9f Migrate custom settings for SDL2 to SDL3 2026-05-25 12:12:09 -05:00
blackfa765 472b0e2bdb Fix custom settings invalidating global settings 2026-05-25 12:12:09 -05:00
KeatonTheBot 8f6d22d92d Add Turbo Mode to CPU settings 2026-05-25 12:12:09 -05:00
KeatonTheBot 645a4c99af Add custom audio settings 2026-05-25 12:12:09 -05:00
blackfa765andKeatonTheBot a94c18bc0a Basic custom settings functionality
Co-authored-by: KeatonTheBot <keaton@ryujinx.app>
2026-05-25 12:12:09 -05:00
Babib3l 74d6b310b8 Windows Fullscreen Fixes
This PR fixes two bugs introduced in #80 :
- Exiting fullscreen could exit the Ryujinx window  (https://github.com/Ryubing/Issues/issues/415)
- Toggling fullscreen on would move the window to the primary monitor

And two other bugs related to input view :
- Exiting fullscreen when window was previously in a non maximized state now conserves the window coordinates and size properly (https://github.com/Ryubing/Issues/issues/425)
- Opening the ryujinx app no makes the app grow slightly larger vertically on each launch (+31px on my 1080p monitor) (https://github.com/Ryubing/Issues/issues/425)
2026-05-25 11:59:44 -05:00
Babib3l 3289715b8c River : HLE: Make process identity explicit for service metadata resolution
This PR is the first in a batch of structural changes to Ryujinx.

**Changes**

- Added `ProcessIdentity` and `ProcessKind` to describe loaded programs by:
  - PID, program ID, application ID, program index, display version, process kind
- Stored identity metadata on `ProcessResult`.
- Added PID-based process lookup helpers to `ProcessLoader`.
- Updated HLE services to resolve application metadata through the caller PID instead of `Processes.ActiveApplication`.
- Added PTC/JIT disk cache initialization logging with PID, title ID, display version, selector, and enabled state.
- Added `ClientProcessId` property to ServiceCtx (/src/Ryujinx.HLE/HOS/ServiceCtx.cs) that uses the handle descriptor PId when available, falling back to `Process.Pid`.
- Updated 15 HLE service files to use `context.ClientProcessId` instead of `context.Process.Pid` for client process access, ensuring services correctly identify the calling process even when invoked via IPC with handle descriptors.

These changes make service metadata resolution more explicit and prepare the emulator for other structural changes later on.
2026-05-25 11:50:28 -05:00
Mabel 3a3129252a Fix Clipboard Copy Operation Crash
Fixes a COM exception crash related to clipboard copy events from changes in Avalonia 11.3

Solves [Ryubing/Issues#294](https://github.com/Ryubing/Issues/issues/294) caused by Avalonia 11.3's changes, see [AvaloniaUI/Avalonia#20007](https://github.com/AvaloniaUI/Avalonia/issues/20007) for more information

I've only tested this on Windows, no idea if this has issues in MacOS or Linux, or if it's even a problem there at all.
2026-05-24 14:56:27 -05:00
LotP ff47cb1d66 remap joy-cons 2026-05-22 14:31:00 -05:00
KeatonTheBot d440ff41d2 Update NuGet packages
- Ryujinx.Graphics.Vulkan.MoltenVK to 1.4.2-ryujinx.3

- System.IO.Hashing to 10.0.8
2026-05-20 14:30:24 -05:00
Renovate Bot 46308c32e7 Update dependency NUnit to 4.6.1 (#6)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [NUnit](https://nunit.org/) ([source](https://github.com/nunit/nunit)) | `4.5.1` → `4.6.1` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/NUnit/4.6.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/NUnit/4.5.1/4.6.1?slim=true) |

---

### Release Notes

<details>
<summary>nunit/nunit (NUnit)</summary>

### [`v4.6.1`](https://github.com/nunit/nunit/releases/tag/v4.6.1): NUnit version 4.6.1

See [release notes](https://docs.nunit.org/articles/nunit/release-notes/framework.html#nunit-461---may-18-2026) for details.

### [`v4.6.0`](https://github.com/nunit/nunit/releases/tag/v4.6.0): NUnit 4.6.0

[Compare Source](https://github.com/nunit/nunit/compare/4.5.1...4.6.0)

See [release notes](https://docs.nunit.org/articles/nunit/release-notes/framework.html#nunit-460---may-4-2026) for details.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzguMCIsInVwZGF0ZWRJblZlciI6IjQzLjE3OC4wIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=-->

Reviewed-on: https://git.ryujinx.app/projects/Kenji-NX/pulls/6
2026-05-20 18:43:04 +00:00
Renovate Bot bf09e153f1 Update dependency Microsoft.IdentityModel.JsonWebTokens to 8.18.0 (#5)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) | `8.17.0` → `8.18.0` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/Microsoft.IdentityModel.JsonWebTokens/8.18.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Microsoft.IdentityModel.JsonWebTokens/8.17.0/8.18.0?slim=true) |

---

### Release Notes

<details>
<summary>AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet (Microsoft.IdentityModel.JsonWebTokens)</summary>

### [`v8.18.0`](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/HEAD/CHANGELOG.md#8180)

[Compare Source](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.17.0...8.18.0)

\====

#### New Features

- Introduced a new interface `IConfigurationEventHandlerContextAware<T>` that provides context to the configuration event handler implementation, allowing it to optionally bypass a cache lookup. See [PR #&#8203;3444](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3444).
- Added Microsoft.IdentityModel.Dpop — a new package implementing DPoP (Demonstrating Proof-of-Possession) per RFC 9449. Provides both client-side and server-side proof validation with no System.Net.Http dependency. See [PR #&#8203;3443](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3443).

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzguMCIsInVwZGF0ZWRJblZlciI6IjQzLjE3OC4wIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=-->

Reviewed-on: https://git.ryujinx.app/projects/Kenji-NX/pulls/5
2026-05-20 18:42:52 +00:00
Renovate Bot 0d1eebad31 Update dependency Microsoft.NET.Test.Sdk to 18.5.1 (#4)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) | `18.5.0` → `18.5.1` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/Microsoft.NET.Test.Sdk/18.5.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Microsoft.NET.Test.Sdk/18.5.0/18.5.1?slim=true) |

---

### Release Notes

<details>
<summary>microsoft/vstest (Microsoft.NET.Test.Sdk)</summary>

### [`v18.5.1`](https://github.com/microsoft/vstest/releases/tag/v18.5.1)

#### What's Changed

- Fix System.Collections.Immutable binding mismatch in Common.dll (rel/18.5) by [@&#8203;nohwnd](https://github.com/nohwnd) in [#&#8203;15720](https://github.com/microsoft/vstest/pull/15720)
- Port verify-binding-redirects.ps1 to rel/18.5 by [@&#8203;nohwnd](https://github.com/nohwnd) in [#&#8203;15719](https://github.com/microsoft/vstest/pull/15719)
- Bump to 18.5.1 by [@&#8203;nohwnd](https://github.com/nohwnd) in [#&#8203;15721](https://github.com/microsoft/vstest/pull/15721)

**Full Changelog**: <https://github.com/microsoft/vstest/compare/v18.5.0...v18.5.1>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzguMCIsInVwZGF0ZWRJblZlciI6IjQzLjE3OC4wIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=-->

Reviewed-on: https://git.ryujinx.app/projects/Kenji-NX/pulls/4
2026-05-20 18:28:36 +00:00
Renovate Bot b1b260ed17 Update avalonia monorepo to 11.3.16 (#3)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [Avalonia](https://avaloniaui.net/?utm_source=nuget&utm_medium=referral&utm_content=project_homepage_link) ([source](https://github.com/AvaloniaUI/Avalonia)) | `11.3.14` → `11.3.16` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/Avalonia/11.3.16?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Avalonia/11.3.14/11.3.16?slim=true) |
| [Avalonia.Desktop](https://avaloniaui.net/?utm_source=nuget&utm_medium=referral&utm_content=project_homepage_link) ([source](https://github.com/AvaloniaUI/Avalonia)) | `11.3.14` → `11.3.16` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/Avalonia.Desktop/11.3.16?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Avalonia.Desktop/11.3.14/11.3.16?slim=true) |
| [Avalonia.Diagnostics](https://avaloniaui.net/?utm_source=nuget&utm_medium=referral&utm_content=project_homepage_link) ([source](https://github.com/AvaloniaUI/Avalonia)) | `11.3.14` → `11.3.16` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/Avalonia.Diagnostics/11.3.16?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Avalonia.Diagnostics/11.3.14/11.3.16?slim=true) |
| [Avalonia.Markup.Xaml.Loader](https://avaloniaui.net/?utm_source=nuget&utm_medium=referral&utm_content=project_homepage_link) ([source](https://github.com/AvaloniaUI/Avalonia)) | `11.3.14` → `11.3.16` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/Avalonia.Markup.Xaml.Loader/11.3.16?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Avalonia.Markup.Xaml.Loader/11.3.14/11.3.16?slim=true) |

---

### Release Notes

<details>
<summary>AvaloniaUI/Avalonia (Avalonia)</summary>

### [`v11.3.16`](https://github.com/AvaloniaUI/Avalonia/releases/tag/11.3.16)

[Compare Source](https://github.com/AvaloniaUI/Avalonia/compare/11.3.15...11.3.16)

##### What's Changed

- Core – Align Touch/Pen capture semantics with Mouse by [@&#8203;miloush](https://github.com/miloush) in [#&#8203;21363](https://github.com/AvaloniaUI/Avalonia/pull/21363)

**Full Changelog**: <https://github.com/AvaloniaUI/Avalonia/compare/11.3.15...11.3.16>

### [`v11.3.15`](https://github.com/AvaloniaUI/Avalonia/releases/tag/11.3.15)

[Compare Source](https://github.com/AvaloniaUI/Avalonia/compare/11.3.14...11.3.15)

##### What's Changed

##### Security

- VNC – Bump SharpCompress from 0.24.0 to 0.48.0 by [@&#8203;kekekeks](https://github.com/kekekeks)

**Full Changelog**: <https://github.com/AvaloniaUI/Avalonia/compare/11.3.14...11.3.15>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzguMCIsInVwZGF0ZWRJblZlciI6IjQzLjE3OC4wIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=-->

Reviewed-on: https://git.ryujinx.app/projects/Kenji-NX/pulls/3
2026-05-20 18:27:08 +00:00
Renovate BotandKeatonTheBot a57756f447 Configure Renovate (#1)
Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.

🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged.

📚 See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading.

🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to `.forgejo/renovate.json` in this branch. Renovate will update the Pull Request description the next time it runs.

---
### Detected Package Files

 * `Directory.Packages.props` (nuget)
 * `global.json` (nuget)
 * `src/ARMeilleure/ARMeilleure.csproj` (nuget)
 * `src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj` (nuget)
 * `src/Ryujinx.Common/Ryujinx.Common.csproj` (nuget)
 * `src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj` (nuget)
 * `src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj` (nuget)
 * `src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj` (nuget)
 * `src/Ryujinx.HLE/Ryujinx.HLE.csproj` (nuget)
 * `src/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj` (nuget)
 * `src/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj` (nuget)
 * `src/Ryujinx.Horizon/Ryujinx.Horizon.csproj` (nuget)
 * `src/Ryujinx.Input/Ryujinx.Input.csproj` (nuget)
 * `src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj` (nuget)
 * `src/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj` (nuget)
 * `src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj` (nuget)
 * `src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj` (nuget)
 * `src/Ryujinx.Tests/Ryujinx.Tests.csproj` (nuget)
 * `src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj` (nuget)
 * `src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj` (nuget)
 * `src/Ryujinx/Ryujinx.csproj` (nuget)

### Configuration Summary

Based on the default config's presets, Renovate will:

  - Start dependency updates only once this onboarding PR is merged
  - Enable Renovate Dependency Dashboard creation.
  - Use semantic commit type `fix` for dependencies and `chore` for all others if semantic commits are in use.
  - Ignore `node_modules`, `bower_components`, `vendor` and various test/tests (except for nuget) directories.
  - Group known monorepo packages together.
  - Use curated list of recommended non-monorepo package groupings.
  - Show only the Age and Confidence Merge Confidence badges for pull requests.
  - Apply crowd-sourced package replacement rules.
  - Apply crowd-sourced workarounds for known problems with packages.
  - Ensure that every dependency pinned by digest and sourced from Forgejo contains a link to the commit-to-commit diff
  - Ensure that every dependency pinned by digest and sourced from GitHub.com and Github enterprise contains a link to the commit-to-commit diff
  - Enable Renovate configuration migration PRs when needed.
  - Require Dependency Dashboard approval for `major` updates.

---

### What to Expect

With your current configuration, Renovate will create 9 Pull Requests:

<details>
<summary>Update avalonia monorepo to 11.3.16</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/avalonia-monorepo`
  - Merge into: `master`
  - Upgrade [Avalonia](https://github.com/AvaloniaUI/Avalonia) to `11.3.16`
  - Upgrade [Avalonia.Desktop](https://github.com/AvaloniaUI/Avalonia) to `11.3.16`
  - Upgrade [Avalonia.Diagnostics](https://github.com/AvaloniaUI/Avalonia) to `11.3.16`
  - Upgrade [Avalonia.Markup.Xaml.Loader](https://github.com/AvaloniaUI/Avalonia) to `11.3.16`

</details>

<details>
<summary>Update dependency Microsoft.NET.Test.Sdk to 18.5.1</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/vstest-monorepo`
  - Merge into: `master`
  - Upgrade [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) to `18.5.1`

</details>

<details>
<summary>Update dependency Microsoft.IdentityModel.JsonWebTokens to 8.18.0</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/dotnet-azure-ad-identitymodel-extensions-monorepo`
  - Merge into: `master`
  - Upgrade [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) to `8.18.0`

</details>

<details>
<summary>Update dependency NUnit to 4.6.1</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/nunit-4.x`
  - Merge into: `master`
  - Upgrade [NUnit](https://github.com/nunit/nunit) to `4.6.1`

</details>

<details>
<summary>Update dotnet monorepo</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/dotnet-monorepo`
  - Merge into: `master`
  - Upgrade [Microsoft.CodeAnalysis.Analyzers](https://github.com/dotnet/roslyn) to `3.11.0`
  - Upgrade [Microsoft.CodeAnalysis.CSharp](https://github.com/dotnet/roslyn) to `4.14.0`
  - Upgrade [System.IO.Hashing](https://github.com/dotnet/dotnet) to `10.0.8`
  - Upgrade [dotnet-sdk](https://github.com/dotnet/sdk) to `10.0.300`

</details>

<details>
<summary>Update avalonia monorepo to v12</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/major-avalonia-monorepo`
  - Merge into: `master`
  - Upgrade [Avalonia](https://github.com/AvaloniaUI/Avalonia) to `12.0.3`
  - Upgrade [Avalonia.Desktop](https://github.com/AvaloniaUI/Avalonia) to `12.0.3`
  - Upgrade [Avalonia.Markup.Xaml.Loader](https://github.com/AvaloniaUI/Avalonia) to `12.0.3`

</details>

<details>
<summary>Update dependency Avalonia.Controls.DataGrid to v12</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/avalonia.controls.datagrid-12.x`
  - Merge into: `master`
  - Upgrade [Avalonia.Controls.DataGrid](https://github.com/AvaloniaUI/Avalonia.Controls.DataGrid) to `12.0.0`

</details>

<details>
<summary>Update dotnet monorepo to v5</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/major-dotnet-monorepo`
  - Merge into: `master`
  - Upgrade [Microsoft.CodeAnalysis.Analyzers](https://github.com/dotnet/roslyn) to `5.3.0`
  - Upgrade [Microsoft.CodeAnalysis.CSharp](https://github.com/dotnet/roslyn) to `5.3.0`

</details>

<details>
<summary>Update Svg.Controls to v12</summary>

  - Schedule: ["at any time"]
  - Branch name: `renovate/major-svg.controls`
  - Merge into: `master`
  - Upgrade [Svg.Controls.Avalonia](https://github.com/wieslawsoltes/Svg.Skia) to `12.0.0.9`
  - Upgrade [Svg.Controls.Skia.Avalonia](https://github.com/wieslawsoltes/Svg.Skia) to `12.0.0.9`

</details>

🚸 PR creation will be limited to maximum 2 per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for `prHourlyLimit`](https://docs.renovatebot.com/configuration-options/#prhourlylimit) for details.

---

❓ Got questions? Check out Renovate's [Docs](https://docs.renovatebot.com/), particularly the Getting Started section.
If you need any further assistance then you can also [request help here](https://github.com/renovatebot/renovate/discussions).

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).

<!--renovate-config-hash:b90d3633c498120cf097b76d90e40f530a1210d84c00ad2dc3491f01a81cbdd8-->

Co-authored-by: KeatonTheBot <keaton@ryujinx.app>
Reviewed-on: https://git.ryujinx.app/projects/Kenji-NX/pulls/1
2026-05-20 16:58:32 +00:00
be405de436 Fix crash on Mac and Android caused by a buffer validation error fix
Fixes a bug introduced in e88fd327. The problematic commit did its work directly on the updater's own arrays, calling Auto.Get() on each entry as it went, and nulling entries out along the way. The problem is that Get() can call back into Commit (via ClearMirrors -> Rebind), and when it did, that reentrant Commit would read from the same arrays the outer call was still in the middle of processing, hit one of the entries the outer had already nulled, and throw an NullReferenceException. The fix is to have Commit start by copying everything it needs into local variables and resetting _count to zero, so a reentrant call sees a clean updater and operates on its own data. The outer call then writes its snapshot back into the native arrays just before recording the Vulkan bind.

Co-authored-by: AsperTheDog <guillerman0000@gmail.com>
Co-authored-by: Max <randomgirlisweird@gmail.com>
Co-authored-by: Babib3l <gab.chevanne@gmail.com>
2026-05-19 12:18:56 -05:00
AsperTheDogandAsperTheDog e88fd3273d Fix Vulkan validation errors
This PR fixes several validation errors caused by invalid Vulkan usage. These validation errors often end up invoking Undefined Behavior on the driver side, which can lead to artifacts or crashes which are driver specific and otherwise incredibly hard to track. I don't think it should have any impact on performance, but it would be good to test it with as many games as possible (maybe a bug in a game was fixed?).

Each commit fixes an error. I added to each a description with the validation error that was fixed and a small explanation on what was causing it and how I fixed it.

Co-authored-by: AsperTheDog <guillerman0000@gmail.com>
2026-05-15 17:22:21 -05:00
AsperTheDogandAsperTheDog 79f55b12bf Change non-uniform shader extension to be more conservative
The previous fix for Tomodachi Life (#91) included the extension to all shaders, independently on if it was needed or not. This PR fixes that by lazily adding the extension only when it is actually needed.

This change should not be noticed by anyone, but it avoids having to modify shaders that do not perform any type of dynamic indexing, which apparently is something some modders care about.

Co-authored-by: AsperTheDog <guillerman0000@gmail.com>
2026-05-15 17:22:21 -05:00
Max 0bc515e4ff [HLE] Stub ILibrarySelfAccessor:ExitAndReturn (10) 2026-05-15 17:22:21 -05:00
AsperTheDogandAsperTheDog 541fa63330 Add shader non-uniform indexing support
This PR marks ALL texture indexes as nonuniform to fix an issue with the paths in Tomodachi Life: Living the Dream on AMD cards. It should have a negligible impact on performance (and it should not have an impact at all on NVIDIA cards!)

It's caused by what is called 'implicit non-uniform sampler array indexing'. The idea is basically that some GPUs optimize texture lookups from indexed texture arrays, by assuming that you are never going to index different textures within a single workgroup. What this causes is that visual glitch where a subgroup is tasked with rendering a block of the screen, and in the boundaries some cores are indexing the wrong texture.

Co-authored-by: AsperTheDog <guillerman0000@gmail.com>
2026-05-14 08:52:04 -05:00
cookieso 55aded3a05 Input: Implement HD Rumble for compatible Nin devices
This PR addresses [this issue](https://github.com/Ryubing/Issues/issues/231) and implements HD Rumble for compatible Nin devices.
## New Features
- Add the option for Gamepads to implement HD Rumble
- Add the HD rumble capability to SDL3Gamepad and SDL3JoyCon when they meet certain requirements
2026-05-14 08:52:04 -05:00
Max 61e0aba325 Check if the Device is rendering before waiting on it
Fixes an issue where there were missed references and an ``OperationCancelled`` exception when exiting an application.
2026-05-14 08:49:51 -05:00
yell0wsuitandyell0wsuit 23fb4924e3 [HLE] Match hardware screenshot buffer size behavior for captures
## Description

~~Fixes a fatal CLR crash when `caps` screenshot saving receives an input buffer larger than `0x384000`.~~

~~Resolves a crash in Tomodachi Life: Living the Dream where saving the pictures to the system's album crashes with 0x80131506.~~

Follow up to #18. This PR adjusts the validation and copy behavior to better match real hardware, and adds logging to make invalid screenshot buffer cases easier to diagnose.

Real hardware accepts screenshot buffers with a size greater than or equal to `0x384000`, but only `0x384000` bytes are needed for the 1280x720 RGBA image.

This changes screenshot saving to:

- reject buffers smaller than `0x384000`
- accept buffers equal to or larger than `0x384000`
- copy only the first `0x384000` bytes into the 1280x720 bitmap

## Testing

Tested with a real Switch NRO using `capssuSaveScreenShotEx0`, `capssuSaveScreenShotEx1`, and `capssuSaveScreenShotEx2`.

Observed hardware behavior:

```text
0x384000     => OK
0x384000 - 1 => NullInputBuffer
0x384000 + 1 => OK
0x3C0000     => OK // Tomo life picture size
```

Co-authored-by: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com>
2026-05-11 14:30:04 -05:00
Babib3l 8fcc539ed9 Fix Windows fullscreen gap when toggling from maximized
This PR aims to Fix the Windows fullscreen gap when toggling from maximized state by using canonical Win32 fullscreen approach. When entering fullscreen, the window style is saved and replaced with WS_POPUP | WS_VISIBLE to remove all window chrome (title bar, borders), then SetWindowPos sizes the window to cover the full screen with SWP_FRAMECHANGED to force Win32 to recalculate the frame. On exit, the original window style is restored. This eliminates the few-pixel gap at the top that occurred because Avalonia's WindowState = FullScreen transition from a maximized state retained the title bar non-client area, leaving visible space at the top of the screen (Fullscreen resolution would be 1920 x 1072p on a 1080p monitor, it now correctly renders at 1920 x 1080p)
2026-05-11 14:30:04 -05:00
yell0wsuitandyell0wsuit 51e4323a73 [HLE] Fix StoreData layout and implement IDatabaseService.Append
- Fixes `StoreData` layout/update handling so `UpdateLatest` returns the stored Mii data correctly.

- Implements `IDatabaseService.Append` (https://switchbrew.org/wiki/Shared_Database_services#IDatabaseService)

Also adds regression tests for `UpdateLatest` and `Append`.

(Might) fix Mario Kart 8 Deluxe crashing on first boot due to failed Mii verification check (due to custom Mii from emulator), and potentially Tomodachi Life: Living the Dream for the "Import Mii from system" option.

Co-authored-by: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com>
2026-05-11 11:09:52 -05:00
Max fcd55edf93 [HLE] Renamed INotificationServicesForSystem and implemented a few commands and stubs
Should allow Ring Fit and other games that rely heavily on the notification system to get in-game (?), needs testing.
2026-05-11 11:09:02 -05:00
Frosch 44872f45e0 fix: gamepads have the same name
When connecting multiple controllers of the same model, the first device's name ends with (0), the second with (1), the third with (1), the fourth with (1), and so on. To ensure these names are truly unique, GetUniqueGamepadName is now called recursively.
2026-05-11 10:45:54 -05:00
Max 1950b34e39 [HLE] Implemented ILibraryAppletSelfAccessor:1
Needed for Tomodachi Life: Living the Dream (?)

based on [this](https://www.reddit.com/r/Ryubing/comments/1t4lfc9/comment/ok4e7tu/)
2026-05-11 10:45:19 -05:00
LotP 4aa8e249f1 fix nacp language buffer 2026-05-04 17:13:31 -05:00
KeatonTheBot 3c13bdb4af Revert "added skia native assets for windows, macOS and switched to no-depend for linux"
This reverts commit af6dd5b64c.
2026-05-04 02:27:43 -05:00
KeatonTheBot 7dec9a2f09 UI: RPC: Asset images 2026-05-04 01:50:21 -05:00
Max af6dd5b64c added skia native assets for windows, macOS and switched to no-depend for linux
im not really sure why these were missing, but theyre here now :woopernod:
2026-05-04 01:50:00 -05:00
Max c6fba938bb CPU: Increased base JIT cache size
@MaxLastBreath found that The Legend of Zelda: Tears of the Kingdom experiences inconsistent crashing with a limited JIT cache size. Increasing the cache size seems to help with this, and increasing it shouldn't degrade performance for other titles.

@LotP plans to look this over later, but for now, this should suffice as a fix for affected users.
2026-05-04 01:50:00 -05:00
Max 4b4fd560ed UI: LoadGuestApplication asynchronous cancellation
Fixed LoadGuestApplication hanging when cancelled.
Since startup procedure has technically changed, we should consider testing this with a variety of game formats to ensure regressions do not occur.
2026-05-04 01:48:31 -05:00
KeatonTheBot 7f99e32a0a Update Ryujinx.SDL3-CS to 2026.501.0
- Fixes upstream SDL issue: Crash on Windows when a controller is connected
2026-05-01 19:52:38 -05:00
KeatonTheBot 4b8c74be10 Update Ryujinx.SDL3-CS to 2026.430.0
- Should work better with Switch 2 Pro Controllers
2026-04-30 00:58:07 -05:00
KeatonTheBot 2af1bc1808 Update NuGet packages
- Avalonia to 11.3.14

- FluentAvalonia to 2.5.1

- Gommon to 2.8.1.2

- Microsoft.NET.Test.Sdk to 1.8.5.0

- SDL3-CS to 2026.426.0

- System.IO.Hashing to 10.0.7
2026-04-27 00:49:28 -05:00
KeatonTheBot 1d19b318c1 infra: Remove PDB files from Release builds
- Use DebugType=none in Directory.Build.props

- Remove files included in NuGet packages
2026-04-22 10:04:19 -05:00
KeatonTheBot 36767d7fce misc: Replace IntPtr/UIntPtr with nint/nuint 2026-04-21 16:26:47 -05:00
Xam 20a9ecaebf HLE: CaptureManager: SaveScreenShot: properly handle screenshot image data
no way this was working before, and if it did, just pure luck, unsafe blind copy of bytes as is and zero checks.

i only tested tomodachi, but should fix all games that were crashing on saving screenshots

the crash was happening because the screenshot buffer was bigger than the bitmap buffer, so marshall.copy() was raising an unhandhled expection crashing the emu.

on top of this, because the data was just copied as is, the result image was garbled.
2026-04-21 16:25:33 -05:00
LotP 77c947eb88 Fix Dual Joy-Con driver and InputView 2026-04-21 16:25:33 -05:00
KeatonTheBotandMaki 251b65771a Update SDL2 to SDL3
- Fix: Crash when connecting a JoyCon

- Fix: Make controller GUIDs match old SDL2 GUIDs

- Fix: Detect face button layout for gamepads

Co-authored-by: Maki <77-maki@users.noreply.git.ryujinx.app>
2026-04-14 22:13:05 -05:00
KeatonTheBot 7aa27b2ca5 Use Forgejo badges 2026-04-14 00:18:57 -05:00
KeatonTheBot 3a479a437d Update GitLab references to Forgejo 2026-04-13 23:49:54 -05:00
sh0inx 5359ab77e1 Update BiquadFilterEffectParameterTests.cs 2026-04-13 23:47:56 -05:00
KeatonTheBot 3d5682375e Add Color Space Passthrough to Headless config and MainWindow 2026-04-10 02:11:36 -05:00
KeatonTheBot bc777e1968 Avalonia: Restore Color Space Passthrough for Windows/Linux
Limiting to macOS is no longer needed. Windows and Linux can also utilize this.

This reverts commit f61b7818c3.
2026-04-09 17:25:04 -05:00
LotP e729014cfa Accurate Service Names
- Services now use their actual names when creating processes instead of the generic "Service".

- Services now use their names encapsulated in curly brackets for threads, e.g. {HID}, instead of the default "HLE.OsThread", making it easier to see what is actually happening behind the scenes. Client threads should use <> and host threads should use {}.

- Fixed a bug where initiating services would create extra unneeded servers.

This is part 1 of a series of service and Horizon changes i'm working on. More will follow at a later date.
2026-04-05 16:53:25 -05:00
KeatonTheBot 39b7242ef7 Update NuGet packages
* Avalonia to 11.3.13

* CommunityToolkit.Mvvm to 8.4.2

* Microsoft.IdentityModel.JsonWebTokens to 8.17.0
2026-04-01 16:24:15 -05:00
KeatonTheBot d55c0a702b Vulkan: Enable VK_EXT_memory_priority for Pageable Memory to work properly 2026-03-31 22:47:20 -05:00
KeatonTheBot f39b53982a VulkanInitialization: Move declarations closer to usage 2026-03-31 22:44:33 -05:00
KeatonTheBot 46a57538c6 Restore Ryujinx.LibHac to 0.21.0-alpha.128 2026-03-24 16:21:38 -05:00
KeatonTheBot 9b93b6fe18 Update NuGet packages
* Svg.Controls.Avalonia group to 11.3.9.5

* DynamicData to 9.4.31

* Humanizer to 3.0.10

* NUnit to 4.5.1

* NUnit3TestAdapter to 6.2.0

* Ryujinx.LibHac to 0.21.0-alpha.133

* System.IO.Hashing to 10.0.5
2026-03-24 15:21:36 -05:00
KeatonTheBot d207d43768 Optimize texture cache code 2026-03-24 15:21:33 -05:00
KeatonTheBot d7f90f9f1f Tweak feedback loop restriction logic 2026-03-18 18:23:37 -05:00
sh0inx 1b714ab1aa [HLE] Added "null" check for isAtRest
If an npad device was checking for if the device was at rest, we called `GetSixAxisSensorLifo()` -- if the npad was of type `None`, it triggered the `NotImplementedException` in that method because `None` doesn't have a gyroscope, and therefore no data attached to it.
2026-03-15 16:16:14 -05:00
Coxxs a6af70baa1 HLE: Implement CreateContextForSystem
Implement nn::ssl::sf::ISslServiceForSystem -> CreateContextForSystem (100)

Ryujinx implements both ISslService and ISslServiceForSystem in one class so we can just return new ISslContext.

Also fixed the incorrect parameter reading order. (CreateContextForSystem basically has same params as CreateContext)
2026-03-14 18:25:36 -05:00
KeatonTheBot 8c9cdfe9ce Clean up texture cache code for low-VRAM GPUs 2026-03-14 18:06:09 -05:00
KeatonTheBotandStossy11 5b3a620bb0 Vulkan: Add A8B8G8R8 texture format
Co-authored-by: Stossy11 <stossy11@stossy11.com>
2026-03-04 16:43:46 -06:00
KeatonTheBot d977208b19 Update NuGet packages
* Avalonia to 11.3.12

* Gommon to 2.8.1.1

* Microsoft.IdentityModel.JsonWebTokens to 8.16.0

* Microsoft.NET.Test.Sdk to 18.3.0

* NUnit to 4.5.0
2026-02-26 17:42:27 -06:00
KeatonTheBot 477be704bb Update SkiaSharp to 3.119.2
* Update deprecated SkiaSharp code
2026-02-26 17:42:27 -06:00
KeatonTheBot 5c8be1b927 Optimize application pool sizes for DRAM selections 2026-02-26 17:42:27 -06:00
BowedCascade adc8ed594a Add restart emulation command
- Add RestartEmulation() method to MainWindowViewModel

- Add 'Restart Emulation' menu item with Ctrl+R keybinding

- Add locale translations for all supported languages

- No confirmation dialog (faster restart experience)
2026-02-26 17:42:27 -06:00
Digote 9104a75a48 HLE: Return LastUrl for Web/Offline BrowserApplet exit reason
Fixes infinite loop on title screen for Ni no Kuni when no save file exists.
2026-02-26 17:42:27 -06:00
sunshineinabox c0ba4e64cf Vulkan: Buffer alignment 2026-02-26 17:42:27 -06:00
sunshineinabox 6cf0a413a0 Vulkan: Enable pageable device-local memory 2026-02-26 17:39:07 -06:00
sunshineinabox caed40d99a Vulkan: StorageImageExtendedFormats support 2026-02-26 17:39:07 -06:00
V380-Ori f764ae2d58 Shader: skip initialization of all clip distances on macOS. 2026-02-25 17:15:47 -06:00
V380-Ori b16f74ffd9 Gpu: exclude RGBA16Float texture format for fast DMA copy on Apple silicon.
* Store a boolean for if Fast DMA texture copy is supported instead of checking vendor every time
2026-02-25 17:15:47 -06:00
V380-Ori bd96f2f51f Avalonia: fix HiDPI/Retina scaling for embedded window on macOS. 2026-02-25 17:15:46 -06:00
KeatonTheBot 3bf8a17f01 Tweak GetCpuName code 2026-02-21 14:02:34 -06:00
KeatonTheBot d5bd8871a2 Windows ARM (win-arm64) build now launches with full trimming 2026-02-20 15:16:32 -06:00
BowedCascade dcafe32d5c Fix backslash key not mappable in controller settings
Fixes keyboard mapping for the backslash key (\) which was previously unmappable in controller button assignment.
2026-02-19 09:51:24 -06:00
KeatonTheBot 18bd84c463 Update NuGet packages
Silk.NET to official NuGet 2.23.0

System group to 10.0.3
2026-02-10 17:09:56 -06:00
Coxxs 9a684ff066 audio: Fix crash due to invalid Splitter size
Fix crash caused by reading incorrect size of Splitter data.

In most games the crash doesnt happen if you have nn::audio::AudioRendererParameter VoiceCount aligned to 2, as that causes splitter data to be aligned by 0x10, but otherwise, the alignment by 0x10 done in SplitterContext->Update may exceed SplitterSize (which was previously labeled as Unknown24), causing a crash.

(Crash can be replicated by doing AudioRendererParameter.voiceCount++; in any SDK 20.X game that works, which doesn't cause crash on actual hardware)

(This patch is from a friend who makes mods.)
2026-02-01 16:11:46 -06:00
GreemDev 60c867622e audio backend projects code cleanup 2026-01-31 02:25:45 -06:00
Stossy11andGreemDev 3cdae775b1 Add macOS native Audio Backend
Adds Ryujinx.Audio.Backends.Apple, which is a AudioToolbox based audio backend for macOS (and by extension iOS). Also added in MeloNX.

* Expose AudioToolkit in UI

Co-authored-by: GreemDev <greemdev@ryujinx.app>
2026-01-31 02:25:41 -06:00
sh0inx 061bfb4074 HLE: Stubbed IUserLocalCommuniationService SetProtocol (106)
Should fix Animal Crossing: New Horizons crashing on LDN connection and potentially other titles with Switch 2 updates.
2026-01-31 01:28:06 -06:00
KeatonTheBot 2b15dfc473 Update FluentAvalonia to 2.5.0 2026-01-30 12:16:22 -06:00
Coxxs a948308a2f HLE: Implement 10106 and 10107 in IPrepoService
In some games using newer SDK (e.g. Splatoon 3 11.0.0), when `nn::prepo::PlayReport::SetOptInCheckEnabled` is set to False, `nn::prepo::PlayReport::Save` will call `IPrepoService:10106` (SaveReport) and `IPrepoService:10107` (SaveReportWithUser) instead of 10104 (SaveReportOld) and 10105 (SaveReportWithUserOld).

A new param (optInCheckEnabled) is added in 10106/10107 compare to 10104/10105.

This should fix missing service error for Splatoon 3 11.0.0 and other games using newer SDK and has set `nn::prepo::PlayReport::SetOptInCheckEnabled` to False.
2026-01-29 20:56:00 -06:00
sh0inx a91f60b6ad HLE: Implement IHidServer IsSixAxisSensorAtRest
Fixes the actually insane amount of log spam in games that check for this, such as Luigi's Mansion 3.

Values in HidDevices.NpadDevices.isAtRest may need to be tuned to a better range for resting detection. I originally set them to 0, and my controller rests at definitely NOT 0.

Will need to be revisited when implementing functionality for the global SixAxisActive bool, IHidServer.StartSixAxisTracking, and IHidServer.StopSixAxisTracking.
2026-01-24 12:44:57 -06:00
KeatonTheBot 56eef239a4 Update OpenAL to 1.25.1 2026-01-20 17:02:52 -06:00
KeatonTheBot bef07155dc Update NuGet packages
* Avalonia to 11.3.11, Svg.Controls.Avalonia group to 11.3.9.2

* Gommon to 2.8.0.4

* NUnit3TestAdapter to 6.1.0

* Ryujinx.LibHac to 0.21.0-alpha.128

* System group to 10.0.2
2026-01-15 21:07:01 -06:00
KeatonTheBot 253f47c971 Linux: Fix file picker not launching from disabling core dumps
Core dumps are disabled by default on Linux, but this prevents access to the file picker due to security hardening. To work around this, core dumps are selectively enabled and disabled around the file picker tasks.
2026-01-14 17:05:32 -06:00
KeatonTheBotandGreemDev 7d0947cac6 Add CommunityToolkit.Mvvm
Use [ObservableProperty] attribute, which greatly reduces or eliminates boilerplate code needed to generate observable properties

Co-authored-by: GreemDev <greemdev@ryujinx.app>
2026-01-14 16:58:45 -06:00
KeatonTheBot 0d29b77a14 Fix MainWindow height calculation, now launches in Steam Deck's Gaming Mode 2026-01-09 22:03:39 -06:00
KeatonTheBotandGreemDev 2aecce018c chore: CI sh/py script changes
Co-authored-by: GreemDev <greemdev@ryujinx.app>
2026-01-09 16:13:44 -06:00
KeatonTheBot 8ac2b1e497 UI: Update Svg.Controls.Avalonia group to 11.3.9.1 2026-01-06 10:19:34 -06:00
KeatonTheBot 9a1d33dde5 UI: Restore FluentAvaloniaUI package, disable animations on app initialization
* Avalonia's built-in color picker is now used when selecting a firmware avatar
2026-01-04 02:40:05 -06:00
KeatonTheBot 899c99740d Linux: Fix file picker not launching 2026-01-03 23:33:28 -06:00
KeatonTheBot 1390fd02d7 Vulkan: Add ROG Xbox Ally device ID to feedback loop restriction 2026-01-02 22:54:46 -06:00
KeatonTheBot 5ecdd197cd Fix ComboBox alignment on texture format dropdown 2025-12-27 23:08:43 -06:00
KeatonTheBot 546082128f Update NuGet packages
* Avalonia to 11.3.10

* Gommon to 2.8.0.3

* Silk.NET.Shaderc to 2.23.0

* System group to 10.0.1
2025-12-27 20:41:12 -06:00
KeatonTheBot 2aae771ab3 Clean up heap adjustment code 2025-12-27 18:53:20 -06:00
V380-Ori a2c53ed6cf Use Ryujinx.MoltenVK 1.4.1
Vulkan: remove InvalidResource workaround, as it is no longer needed since macOS Sonoma.

Vulkan: enable textureGatherOffsets on MoltenVK.
2025-12-26 15:19:19 -06:00
V380-Ori fba786cd38 Replace shaderc.net with Silk.NET.Shaderc 2025-12-26 15:09:50 -06:00
Francesco Saltori 292d42d394 Update Italian translation 2025-12-26 15:04:56 -06:00
KeatonTheBot afa4782493 Heap adjustments/fixes
* Restore 6 GiB heap for 4 GiB DRAM selection

* Limit heap to 8 GiB for games that crash or won't load with extended heaps
2025-12-25 02:20:45 -06:00
GreemDev b6cd6770ff Removed TypedStringEnumConverter; it exists in .NET now.
As per the remark XMLdoc on the type: Get rid of this converter if dotnet supports similar functionality out of the box.
2025-12-23 08:18:10 -06:00
KeatonTheBot fecb02647d Update FFmpeg to 6.1.4 for Windows/Linux 2025-12-23 01:40:39 -06:00
KeatonTheBot bf12b601b0 Update OpenAL to 1.25.0 2025-12-22 18:02:32 -06:00
GreemDev 4a5729cc01 feature: macOS Liquid Glass dynamic icon
No more squircle jail! Thanks @transistor.exe in the Ryubing discord for dropping the asset files for this to happen.
2025-12-22 11:54:22 -06:00
Coxxs 5a16e24450 gdb: add monitor get mapping
This add the following commands to Gdb Stub:

monitor get mappings
monitor get mappings <address>
monitor get mapping <address>

This is the first time arguments are used in Rcmd, so FindRcmdDelegate is changed to CallRcmdDelegate, to allow it to handle arguments cleanly.

The reply format mimics the same command on Atmosphere.

The forced pagination of monitor get mappings in Atmosphere is not added, as I think it's not needed here.
2025-12-21 23:03:56 -06:00
KeatonTheBot 2dfa040d92 Attempt #1: Fix win-arm64 build not launching with full trimming 2025-12-21 15:17:16 -06:00
KeatonTheBot da6b58b9fa Update Silk.NET.Vulkan to 2.23.0
* Add GitLab package registry to nuget.config
2025-12-19 17:49:03 -06:00
KeatonTheBotandAaron Robinson ad516777d9 Enable full trimming
Fix trim errors by excluding full assemblies from trimming that use reflection

Co-authored-by: Aaron Robinson <aaronrobin1234@gmail.com>
2025-12-19 17:49:03 -06:00
gdkchanandKeatonTheBot 812cecd713 Initial texture replacement implementation
Unmerged PR #5632, originally by @gdkchan

* Add mod manager support - @KeatonTheBot

* Remove redundant code - @KeatonTheBot

* Optimize, modernize code to newer C# standards where appropriate - @KeatonTheBot

Co-authored-by: KeatonTheBot <keaton@ryujinx.app>
2025-12-19 17:49:02 -06:00
KeatonTheBot d00bda7e53 Migrate SLN to SLNX 2025-12-13 13:32:54 -06:00
KeatonTheBot c70f692324 misc: chore: Fix possible NullReferenceExceptions, suppress warnings 2025-12-13 13:32:49 -06:00
LotP 9920619ff6 fix pre-action crash
if a buffer is inherited, ignore it and remove it from the list.

fixes a crash when a buffer is inherited during a sync and the containing ranges have been modified to not fit in the old buffer.
2025-12-13 12:09:14 -06:00
LotP 2ba33ec2ef Fix kaddressarbiter crash
Fixes a crash when trying to access the thread count on a not (yet) existing list of threads.
2025-12-06 20:29:22 -06:00
LotP e404954f88 Memory Changes 3.2
Fixes a few crashes:
- fixes a crash related to waking threads (priorities were wrong).
- fixes a crash from reusing the SetRenderTargets texture array (left-over data causing issues).
- fixes a mistake and an oversight in the buffer system.
  - buffers were getting updated wrong causing bad data to be stored or some times cut.
  - modified ranges would extend past their old buffers, crashing on syncs. Old buffers are now skipped as the new buffers already sync instead.

Introduces pooling in a few more places to increase memory efficiency.

simplified RangeList item logic.
- removed RangeItem by making all the range objects use the I(NonOverlapping)Range interface.
- BufferCache class no longer locks its RangeList, as the list is only ever accessed synchronously.

Small change to how keyboard snapshots are stored.

Increase ThreadedRenderer SpanPool size to fit slightly more data (4MB -> 8MB).
2025-12-06 19:41:14 -06:00
LotP 6b383873e8 Update BiquadFilterEffectParameter2.cs
Fixes audio issues in Metroid Prime 4 and other games
2025-12-05 08:13:33 -06:00
KeatonTheBot 32d1653af9 Fix heap size for kernel check and DRAM selections 2025-12-04 20:17:52 -06:00
Princess Piplup 298e2cdefd Fix SaveCurrentScreenshot
This fixes SaveCurrentScreenshot so it correctly saves the screenshot into the screenshot folder, it's no longer a stub

I was going to add the capture button so all games worked but tbh I only care for spongebob

games tested
Pokemon Z-A: https://files.raychu.xyz/u/1FaUGV.png
Pokemon Violet: https://files.raychu.xyz/u/6swfVS.png
Pokemon Violet: https://files.raychu.xyz/u/JaBBX2.png
Spongebob The Cosmic Shake: https://files.raychu.xyz/u/8z5X2e.png
2025-12-04 20:17:51 -06:00
Alula 5a53d36992 Disable coredumps by default on Linux 2025-12-04 20:04:34 -06:00
KeatonTheBot 8c99b90926 nuget: bump packages
* Humanizer to 3.0.1

* Microsoft.IdentityModel.JsonWebTokensto 8.15.0

* Microsoft.NET.Test.Sdk to 18.0.1
2025-11-21 11:48:38 -06:00
KeatonTheBot e287c9fc85 Null-conditional assignments, continued 2025-11-19 20:33:06 -06:00
GreemDev e349ef72fb Use the new C# 14 null propagation setter 2025-11-19 20:09:08 -06:00
GreemDev b7c13715f1 Add .NET Runtime version in About window under Ryujinx version. 2025-11-17 09:14:04 -06:00
KeatonTheBot 139e18a8e1 feature: .NET 10 2025-11-17 09:14:04 -06:00
Coxxs 58a76a0b9f Stub IWriterForApplication: 0 (CreateContextRegistrar)
Fix games that uses ContextRegistrar (e.g. After the socket blocking issue is fixed, Splatoon 3 and other ModuleSystem games will call this when booting, to create a context for the error, after a connection attempt to the server failed.)
2025-11-17 08:42:37 -06:00
KeatonTheBot 6292192cc0 misc: chore: Remove unnecessary usings 2025-11-11 17:40:33 -06:00
LotP a926a31133 Memory changes 3.1
Fixes audio bug causing static noise to play in certain games.

Fixes inputs being dropped after a certain amount of playtime.
2025-11-11 16:05:45 -06:00
GreemDev 17b7eadb91 UI: App Library: automatically remove nonexistent autoload/game dirs from the configuration upon load. 2025-11-10 20:34:39 -06:00
KeatonTheBot 61a783e10a Add 43:18 aspect ratio (for 3440x1440 [WQHD], 6880×2880 [UW6K+] users) 2025-11-08 16:49:46 -06:00
GreemDevandcomex 9b8517caf3 Fix socket closing on shutdown
Previously, sockets were only ever closed when the game specifically requested it.

Thanks @comex on GitHub for the patch submitted via the [Ryubing] issues page.

Co-Authored-By: comex <47517+comex@users.noreply.github.com>
2025-11-05 08:21:54 -06:00
KeatonTheBot 457f62d773 nuget: bump packages
* Gommon to 2.8.0.1

* Microsoft.NET.Test.Sdk to 18.0.0

* Newtonsoft.Json to 13.0.4 (reduces trim warnings by 56)

* Ryujinx.LibHac to 0.21.0-alpha.126

* System group to 9.0.10

* UnicornEngine.Unicorn to 2.1.4-a40db6c
2025-11-02 20:42:23 -06:00
KeatonTheBot a6c0eabf49 misc: Tweak NullReferenceException fixes 2025-10-31 01:04:00 -05:00
LotP e3ee28605d Memory changes 3
General memory improvements to decrease GC pressure and frequency.

Pool big arrays and objects that are created and deleted often.

Skip data copies when they aren't needed.

Inline flag checks to skip unneeded allocations.

From my testing the performance is about the same, but the GC frequency is much lower and collection is faster causing less and smaller spikes.
2025-10-30 23:25:51 -05:00
KeatonTheBot 2c50fbcc1f misc: Use nint/nuint instead of IntPtr/UIntPtr 2025-10-29 14:54:07 -05:00
GreemDev 90cb9d42db hle: Throw a ServiceNotImplementedException instead of ArgumentException if any number arguments provided to ILibraryAppletAccessor are nonzero 2025-10-29 14:52:15 -05:00
LotP 1a3b407839 ILibraryAppletAccessor:90 tweak
Minor update to logic to make our work easier in the future.
2025-10-29 14:52:13 -05:00
sh0inx 46a0783293 HLE: Stub ILibraryAppletAccessor Unknown90
This lets games such as The Legend of Zelda: Tears of the Kingdom (v1.4.2) and other SDK 20+ games successfully circumvent a crash when calling an applet.

Example: No controller connected on boot -> calls Controller Applet -> no stub = crash.
2025-10-27 13:11:33 -05:00
KeatonTheBot 82ae055fe5 Code cleanup: Audio effects fix and audio object pooling
Commit cdbe5686
2025-10-26 17:33:51 -05:00
LotP f98af9e175 gpu allocation optimizations
ObjectPool now uses ConcurrentBag instead if ConcurrentStack, as it has a smaller memory footprint.

Fix compiler warnings related to Audio Command Pools.

Switch gpu command initialization to use pointers, that way skipping the allocation of the command which is unnecessary.

Skip byte array allocation in Ioctl2/3 if it isn't needed (if the source data is all continuous we don't need to copy it to make it continuous).
2025-10-26 16:46:55 -05:00
LotP cdbe568620 audio effects fix and audio object pooling
Revert and reimplement Float BiquadFilterEffect support, fixes infinite load issues in a few games like Splatoon 3.

Fix incorrect string check with the new thread naming system.

Implement object pooling for all Audio Commands and a few other audio related objects and use a growing error list for updating wave buffers instead of always allocating space for 8 errors.
2025-10-25 23:49:52 -05:00
KeatonTheBot 86f47b8333 Revert cleanup change in KScheduler.cs
From commit a7af26bc.
2025-10-25 17:57:31 -05:00
Coxxs 2993dba583 Fix application list loads slowly when RyuLDN is enabled
Currently, application list will not show until ApplicationLibrary_LdnGameDataReceived calls ViewModel.RefreshView();, forcing a refresh. This makes application list load slowly when RyuLDN is enabled.
2025-10-24 14:30:38 -05:00
GreemDev e720e4a87b gdb: YACC (yet another cleanup commit) 2025-10-24 09:47:08 -05:00
Coxxs f30d832847 Skip directories (and do not RecurseSubdirectories) when finding the icon fallback
Newer applications have a folder for ounce in the Control nca. This fixes Ryujinx trying to open a folder as a file, causing another exception, when trying to find the icon fallback.
2025-10-24 09:47:08 -05:00
Coxxs afa1ab95c2 Move ProcessInfo and Minidump to HleProcessDebugger
This allows developers to call them in the code for debugging.
2025-10-22 16:35:09 -05:00
GreemDev 52b6fcf1a4 gdb: some more cleanups 2025-10-22 15:25:33 -05:00
GreemDev 35449846d9 gdb: Make waiting for a process to start more forgiving (200ms per poll 10x -> 500ms) 2025-10-22 08:10:25 -05:00
Coxxs 5d68312b54 gdb: Abort if unable to start GDB server
When users enable GDB stub, we assume they intend to use it (it slows down the game a lot). If the server cannot start, we abort to save users' time troubleshooting why their GDB client can not connect.
2025-10-22 08:10:24 -05:00
GreemDev b8aaadac5f gdb: Catch SocketException from TcpListener#Start 2025-10-22 08:09:48 -05:00
KeatonTheBot a369b246a3 Fix Ori 2 not launching (revert Possible NullReferenceException change) 2025-10-21 16:43:03 -05:00
KeatonTheBot d96e93ef0d Missed application pool for 4 GiB DRAM 2025-10-21 13:29:57 -05:00
GreemDev 0bfd2ad3ef gpu: tweak: Do not log missing Votevtg implementation. 2025-10-21 13:25:32 -05:00
Coxxs df36c23652 gdb: fix IsProcess32Bit throws exception if called too early
For some reason, LLDB will call commands that use IsProcess32Bit earlier than GDB.
2025-10-20 21:53:26 -05:00
GreemDev 843a7113d1 chore: fix in-code typos 2025-10-20 21:53:26 -05:00
GreemDev 2d420ee561 gdb: dynamic rcmd system & more cleanups 2025-10-20 21:53:26 -05:00
Coxxs b958044e4e gdb: Support qAttached; Add missing ReplyOK when detach 2025-10-20 21:34:19 -05:00
Coxxs d659bec27a Implement IUserServiceCreator: 1 (CreateClientProcessMonitor)
This should fix nn::ldn::Initialize in games that use SDK 18 or higher.
2025-10-20 20:57:30 -05:00
Coxxs 107df58666 Update LoadIdTokenCache for 19.0.0+
This should stub nn::account::LoadNetworkServiceAccountIdTokenCache for games that use SDK 19 or higher.
2025-10-20 20:57:06 -05:00
KeatonTheBot 280461dc78 Update NUnit to 4.4.0
* NUnit3TestAdapter to 5.2.0

* Rename Assert class to ClassicAssert to align with NUnit 4.x changes
2025-10-19 23:01:06 -05:00
KeatonTheBot 1724149443 misc: chore: Remove unnecessary usings 2025-10-19 17:48:37 -05:00
Xam b44e2a87fd Fix duplicate volume and mode change events in AppHost 2025-10-19 17:47:12 -05:00
Xam b1f767b2d5 Input: AvaloniaMouseDriver: fix native touch inputs 2025-10-19 17:46:22 -05:00
Xam ec9713b111 Horizon: Audio: HwopusIpcServer: fix random crashes regression in Pokemon Quest 2025-10-19 17:45:43 -05:00
GreemDev a7af26bc1f gdb: More cleanup changes
- Move the message handler into its debugger class part,
- Move all message types into one file and collapse 3 of the ones with no data into a generic, stateless message with a single property being its type,
- Add an Fpscr helper property on IExecutionContext along with a comment about what Fpscr is (similar to the other registers in there)
- Moved the Rcmd helpers (such as GetRegisters, GetMinidump, etc) into a dedicated Debugger class part,
- Fixed the double-collection (ToArray being called twice) in GetThreadUids & GetThread in KProcess
2025-10-19 09:56:08 -05:00
GreemDev 91a5f69805 gdb: more cleanups
- convert GdbRegisters utilities into extensions on IExecutionContext

- add a Write/Read Register helper on Debugger that handles 32/64 bit instead of doing that for every usage of register reading/writing
2025-10-18 09:50:01 -05:00
GreemDev f908bfe150 gdb: Code cleanup pass #2
Moved the reply functionality into the command processor, move the main debugger thread into a dedicated class part, and more
2025-10-17 08:27:13 -05:00
Coxxs a2c494e216 gdb: Cleanup
Remove unused function and fix a bug.
2025-10-17 08:26:32 -05:00
GreemDev e489e0d19f gdb: Cleanup Debugger.cs
by moving the GDB command handlers and command processor out of the class and into their own
2025-10-17 08:23:54 -05:00
KeatonTheBot f362e33293 12 GiB heap crash workaround
Using resolution mods, heaps past 8 GiB work in some games (like LoZ: TotK) and not in others (like SMP Jamboree). Setting the heap to a hard limit of 8 GiB on the 10 & 12 GiB DRAM options seems to be the safe bet right now until a better solution is found.
2025-10-16 15:38:34 -05:00
GreemDevandCoxxs 1e2fd6f4c2 misc: Update Ryujinx.LibHac
Match the behavior with AMS: https://github.com/Atmosphere-NX/Atmosphere/blob/c8e39a54d257bf9875ac852fc1521f046c968339/libraries/libstratosphere/source/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp#L93

This should fix the error ResultFs.InvalidArgument (2002-6001) in some nca.

Co-authored-by: Coxxs <58-coxxs@users.noreply.git.ryujinx.app>
2025-10-16 13:40:52 -05:00
Coxxs 35a8116ae8 gdb: Do not skip CheckInterrupt when gdb stub is enabled
When GDB stub is enabled, CheckSynchronization is called too frequently because it skips _nativeContext.SetCounter(MinCountForCheck) (called in CheckInterrupt()), causing CheckSynchronization to be constantly called in JIT. This could cause performance issue.

It also skips the call to the KProcess.InterruptHandler, which causes some games to deadlock when GDB stub is enabled.

I'm not sure if this change will cause any side effects, but it seems GDB stub is still working correctly after this change.

This change will not affect regular users.
2025-10-16 11:07:05 -05:00
KeatonTheBot 41b8b6961c Restore original application pool sizes for DRAM selections 2025-10-15 21:52:24 -05:00
LotPandKeatonTheBot 42727fca07 12 GiB heap support
The heap was limited to 6 GiB no matter the memory setting, causing memory configurations above 8 GiB to not actually affect the heap size.

Now when the memory config is set to [10 or] 12 GiB the heap also allocates 12 GiB.

The SetHeapSize SysCall will now allow heap sizes up to 12 GiB (technically slightly less).

Co-authored-by: KeatonTheBot <keaton@ryujinx.app>
2025-10-15 21:49:11 -05:00
Coxxs f5822c16af Flush the error log before exit
Currently, some logs can be missing when a fatal error occurs (especially GuestBrokeExecutionException).

This MR attempts to flush logs to console and file before process exit.
2025-10-13 21:59:20 -05:00
GreemDev 66a5719e10 UI: Move IgnoreControllerApplet to the System config section object 2025-10-12 21:48:26 -05:00
KeatonTheBot cc2fb8f0b6 UI: Fix line breaks in Turbo Mode tooltips 2025-10-12 21:48:26 -05:00
Goodfeat c9c78841b9 feature: add the ability to skip profile select dialog when opening games that use it
the skip behavior is done by passing the user id of the profile you have selected in Options > Manage User Profiles
2025-10-12 21:48:25 -05:00
KeatonTheBot f26bd3d321 UI: Update FluentAvalonia.NoAnim to 2.4.0-build3 2025-10-12 18:31:34 -05:00
Coxxs b28f52387a gdb: Fix the crash that occurs when GDB is connected early
* "Suspend Application on Start" is on
2025-10-11 21:22:40 -05:00
Coxxs 83412689b7 gdb: Add monitor minidump command
This will dump the process information, stack trace, and registers from all threads to both the Ryujinx log and gdb.
2025-10-11 10:44:00 -05:00
LotP 0b5f312b20 Sync thread name on Schedule
After commit 51ca73cb, using a non-blocking socket (e.g. poll(..., timeout=0)) will still result in a blocking socket.

It appears the above commit inverted the behavior.
This merge request fixes the blocking flag: blocking will be set to false when the flag is 0x800.
2025-10-11 10:42:56 -05:00
LotP c0b7452cb5 SDK20 and REV15 support
* Fixed an issue where games would boot loop because of an incorrect HID state.

  * Turns out the SamplingNumber of the atomic input storage doesn't match the SamplingNumber of the input state held by the atomic storage, instead it is exactly double the value in the input state.

* Added new Condition struct to the HID Shared memory and populate it with dummy data to fix the no-controller crash (already merged).

* The audio renderer has been mostly updated to rev15, allowing rev15 games to launch.

  * Biquad filters now use floats.

  * Several structures have been renamed to match the SDK names, making it easier to compare functionality. A few names are still missing and will be changed at a later date.

  * The new commands from rev15 have been added to the CommandType enum, but they are still missing from the code itself.

    * Due to changes in the SDK layout, the time estimation functions are either missing or very well hidden (or Ghidra search functionality is useless). We can't fully implement the new commands until the timing data has been located.

  * A few minor tweaks to the code have been made to more accurately match the SDK.
2025-10-11 10:39:50 -05:00
Judas Drekonym 6ba8ae53f2 Add TitleID sort method
Adds an additional application list sorting method for the TitleID. A
bit of a niche choice for sorting but I think the TID is a relevant
enough piece of metadata that it should be there. (And I personally
would be using it)

- Using existing TitleId constant in ApplicationSort, implying this was
meant to be in the sorting options at some point?
- Reuses the "DlcManagerTableHeadingTitleIdLabel" locale for fulfilling
the need already, might be better to make a unique one for this in the
long run but this codebase is new to me so I wanted to make the changes
as unobtrusive as possible
- Using app.Id for the comparer seems to work fine, not sure if using
something else like IdString would be better?
2025-10-10 12:14:44 -05:00
Evan Husted d3bce3f361 UI: Only show DLC RomFS button under Extract Data when DLCs are available.
Also convert the constructor of DlcSelectViewModel to expect a normal title id and not one already converted to the base ID.
2025-10-09 17:18:50 -05:00
Evan Husted 2471bb8ede UI: Move DLC RomFS dumping under normal RomFS dumping.
Also removed it from DLC manager.
2025-10-09 17:18:50 -05:00
723 changed files with 18531 additions and 10210 deletions
+35
View File
@@ -0,0 +1,35 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"renovate/config"
],
"enabledManagers": ["nuget"],
"packageRules": [
{
// require approval for *all* NuGet package updates, not just major versions.
"matchDepTypes": "nuget",
"dependencyDashboardApproval": true
},
{
// Ignore Gommon for automatic updates. I make breaking changes on minor updates not infrequently.
"matchDepNames": "Gommon",
"matchDepTypes": "nuget",
"enabled": false
},
{
"description": "group Silk.NET packages",
"extends": ["renovate/config//groups/silkdotnet.json"],
"groupName": "Silk.NET"
},
{
"description": "group OpenTK packages",
"extends": ["renovate/config//groups/opentk.json"],
"groupName": "OpenTK"
},
{
"description": "group Svg.Controls packages",
"extends": ["renovate/config//groups/svgcontrols.json"],
"groupName": "Svg.Controls"
}
]
}
+4
View File
@@ -16,6 +16,10 @@ x64/
build/
[Bb]in/
[Oo]bj/
AppDir/
publish_appimage/
publish_ava/
publish_tmp_ava/
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
!packages/*/build/
+2 -1
View File
@@ -1,6 +1,7 @@
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<DebugType Condition="'$(Configuration)'=='Release'">none</DebugType>
</PropertyGroup>
</Project>
+31 -30
View File
@@ -3,52 +3,53 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia" Version="11.3.6" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.6" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.6" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.6" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.6" />
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.6.2" />
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.6.2" />
<PackageVersion Include="Avalonia" Version="11.3.16" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.16" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.16" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.16" />
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageVersion Include="Concentus" Version="2.2.2" />
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
<PackageVersion Include="DynamicData" Version="9.4.1" />
<PackageVersion Include="FluentAvaloniaUI.NoAnim" Version="2.4.0-build2" />
<PackageVersion Include="Gommon" Version="2.7.1.1" />
<PackageVersion Include="Humanizer" Version="2.14.1" />
<PackageVersion Include="DynamicData" Version="9.4.31" />
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.1" />
<PackageVersion Include="Gommon" Version="2.8.1.2" />
<PackageVersion Include="Humanizer" Version="3.0.10" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.14.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.18.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="NUnit" Version="4.6.1" />
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.9.4" />
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.24.3" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.3-build5" />
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.1" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.4-build6" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.3-build5" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.116" />
<PackageVersion Include="Ryujinx.SDL2-CS-Redux" Version="2.32.10" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.4-build6" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.2-ryujinx.3" />
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.501.0" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
<PackageVersion Include="SkiaSharp" Version="3.119.2" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.2" />
<PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="System.IO.Hashing" Version="9.0.9" />
<PackageVersion Include="System.Management" Version="9.0.9" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.3" />
<PackageVersion Include="System.IO.Hashing" Version="10.0.8" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.4-a40db6c" />
</ItemGroup>
</Project>
+18 -23
View File
@@ -1,31 +1,26 @@
<h1 align="center">
<br>
<img src="https://git.ryujinx.app/kenji-nx/ryujinx/-/raw/master/distribution/misc/Logo.png" alt="Kenji-NX">
<img src="https://git.ryujinx.app/projects/Kenji-NX/raw/branch/master/distribution/misc/Logo.png" alt="Kenji-NX">
<br>
<b>Kenji-NX</b>
<br>
<a href="https://github.com/Kenji-NX/Releases/releases/latest">
<img src="https://img.shields.io/github/v/release/Kenji-NX/Releases"
alt="Latest Release">
</a>
[![Latest Desktop Release](https://git.ryujinx.app/projects/Kenji-NX/badges/release.svg?label=desktop)](https://git.ryujinx.app/projects/Kenji-NX/releases/latest)
[![Latest Android Release](https://git.ryujinx.app/Kenji-NX/android/badges/release.svg?label=android)](https://git.ryujinx.app/Kenji-NX/android/releases/latest)
<br>
[![Discord](https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Kenji-NX&logo=discord&logoColor=white)](https://discord.gg/zBSAuZfKqe)
</h1>
<p>
Kenji-NX is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
It was written from scratch and development on the project began in September 2017.
Kenji-NX is available on GitHub under the <a href="https://git.ryujinx.app/kenji-nx/ryujinx/-/raw/master/LICENSE.txt" target="_blank">MIT license</a>.
<br><br>
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
<br><br>
This fork is not a Ryujinx revival project; it aims to be a middle ground between GreemDev's <a href="https://git.ryujinx.app/ryubing/ryujinx">Ryujinx</a> fork and the more preservative <a href="https://git.ryujinx.app/archive/ryujinx-mirror">ryujinx-mirror</a> fork.
It brings over many of the front-facing features from the aforementioned forks with <i>additional</i> contributions from KeatonTheBot and others.
<br>
</p>
Kenji-NX is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
It was written from scratch and development on the project began in September 2017.
Kenji-NX is available on GitHub under the [MIT license](LICENSE.txt).
<p>
<img src="docs/shell.png">
</p>
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
This fork is not a Ryujinx revival project; it aims to be a middle ground between GreemDev's [Ryujinx](https://git.ryujinx.app/projects/Ryubing) fork and the more preservative [ryujinx-mirror](https://git.ryujinx.app/archive/ryujinx-mirror) fork.
It brings over many of the front-facing features from the aforementioned forks with *additional* contributions from KeatonTheBot and others.
## Compatibility
@@ -58,12 +53,12 @@ If you wish to build the emulator yourself, follow these steps:
### Step 1
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
Install the [.NET 10.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/10.0).
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
### Step 2
Either use `git clone https://git.ryujinx.app/kenji-nx/ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
Either use `git clone https://git.ryujinx.app/projects/Kenji-NX` on the command line to clone the repository or use Code --> Download zip button to get the files.
### Step 3
@@ -125,7 +120,7 @@ See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY
## Credits
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
- [LibHac](https://git.ryujinx.app/projects/LibHac) is used for our file-system.
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
-253
View File
@@ -1,253 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Unicorn", "src\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj", "{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE", "src\Ryujinx.HLE\Ryujinx.HLE.csproj", "{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "src\Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Common", "src\Ryujinx.Common\Ryujinx.Common.csproj", "{5FD4E4F6-8928-4B3C-BE07-28A675C17226}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARMeilleure", "src\ARMeilleure\ARMeilleure.csproj", "{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Gpu", "src\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj", "{ADA7EA87-0D63-4D97-9433-922A2124401F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.GAL", "src\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj", "{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.OpenGL", "src\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj", "{9558FB96-075D-4219-8FFF-401979DC0B69}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Texture", "src\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj", "{E1B1AD28-289D-47B7-A106-326972240207}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Shader", "src\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj", "{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec", "src\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj", "{85A0FA56-DC01-4A42-8808-70DAC76BD66D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "src\Ryujinx.Audio\Ryujinx.Audio.csproj", "{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Directory.Packages.props = Directory.Packages.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Memory", "src\Ryujinx.Memory\Ryujinx.Memory.csproj", "{A5E6C691-9E22-4263-8F40-42F002CE66BE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Memory", "src\Ryujinx.Tests.Memory\Ryujinx.Tests.Memory.csproj", "{D1CC5322-7325-4F6B-9625-194B30BE1296}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Cpu", "src\Ryujinx.Cpu\Ryujinx.Cpu.csproj", "{3DF35E3D-D844-4399-A9A1-A9E923264C17}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Device", "src\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj", "{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Host1x", "src\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj", "{C35F1536-7DE5-4F9D-9604-B5B4E1561947}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.Vp9", "src\Ryujinx.Graphics.Nvdec.Vp9\Ryujinx.Graphics.Nvdec.Vp9.csproj", "{B9AECA11-E248-4886-A10B-81B631CAAF29}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vic", "src\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj", "{81BB2C11-9408-4EA3-822E-42987AF54429}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Video", "src\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj", "{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.OpenAL", "src\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj", "{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SoundIo", "src\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj", "{716364DE-B988-41A6-BAB4-327964266ECC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input", "src\Ryujinx.Input\Ryujinx.Input.csproj", "{C16F112F-38C3-40BC-9F5F-4791112063D6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL2", "src\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj", "{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj", "{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.LocaleGenerator", "src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryujinx.Horizon\Ryujinx.Horizon.csproj", "{AF34127A-3A92-43E5-8496-14960A50B1F1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.Build.0 = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.Build.0 = Release|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.Build.0 = Release|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.Build.0 = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
EndGlobalSection
EndGlobal
+47
View File
@@ -0,0 +1,47 @@
<Solution>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
<File Path="nuget.config" />
</Folder>
<Project Path="src/ARMeilleure/ARMeilleure.csproj" />
<Project Path="src/Ryujinx.Audio.Backends.Apple/Ryujinx.Audio.Backends.Apple.csproj" />
<Project Path="src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj" />
<Project Path="src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj" />
<Project Path="src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj" />
<Project Path="src/Ryujinx.Audio/Ryujinx.Audio.csproj" />
<Project Path="src/Ryujinx.Common/Ryujinx.Common.csproj" />
<Project Path="src/Ryujinx.Cpu/Ryujinx.Cpu.csproj" />
<Project Path="src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj" />
<Project Path="src/Ryujinx.Graphics.GAL/Ryujinx.Graphics.GAL.csproj" />
<Project Path="src/Ryujinx.Graphics.Gpu/Ryujinx.Graphics.Gpu.csproj" />
<Project Path="src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj" />
<Project Path="src/Ryujinx.Graphics.Nvdec.FFmpeg/Ryujinx.Graphics.Nvdec.FFmpeg.csproj" />
<Project Path="src/Ryujinx.Graphics.Nvdec.Vp9/Ryujinx.Graphics.Nvdec.Vp9.csproj" />
<Project Path="src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj" />
<Project Path="src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj" />
<Project Path="src/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj" />
<Project Path="src/Ryujinx.Graphics.Texture/Ryujinx.Graphics.Texture.csproj" />
<Project Path="src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj" />
<Project Path="src/Ryujinx.Graphics.Video/Ryujinx.Graphics.Video.csproj" />
<Project Path="src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj" />
<Project Path="src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj" />
<Project Path="src/Ryujinx.HLE/Ryujinx.HLE.csproj" />
<Project Path="src/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj" />
<Project Path="src/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj" />
<Project Path="src/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj" />
<Project Path="src/Ryujinx.Horizon/Ryujinx.Horizon.csproj" />
<Project Path="src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj" />
<Project Path="src/Ryujinx.Input/Ryujinx.Input.csproj" />
<Project Path="src/Ryujinx.Memory/Ryujinx.Memory.csproj" />
<Project Path="src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj" />
<Project Path="src/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj" />
<Project Path="src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj" />
<Project Path="src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj" />
<Project Path="src/Ryujinx.Tests/Ryujinx.Tests.csproj" />
<Project Path="src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj" />
<Project Path="src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj" />
<Project Path="src/Ryujinx/Ryujinx.csproj" />
<Project Path="src/Spv.Generator/Spv.Generator.csproj" />
</Solution>
-4
View File
@@ -2,10 +2,6 @@
SCRIPT_DIR=$(dirname "$(realpath "$0")")
if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then
RYUJINX_BIN="Ryujinx.Headless.SDL2"
fi
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
RYUJINX_BIN="Ryujinx"
fi
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
CURRENTDIR="$(readlink -f "$(dirname "$0")")"
exec "$CURRENTDIR"/usr/bin/Ryujinx.sh "$@"
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
set -eu
ROOTDIR="$(readlink -f "$(dirname "$0")")"/../../../
cd "$ROOTDIR"
BUILDDIR=${BUILDDIR:-publish}
OUTDIR=${OUTDIR:-publish_appimage}
rm -rf AppDir
mkdir -p AppDir/usr/bin
cp distribution/linux/Ryujinx.desktop AppDir/Ryujinx.desktop
cp distribution/linux/appimage/AppRun AppDir/AppRun
cp src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png AppDir/Ryujinx.svg
cp -r "$BUILDDIR"/* AppDir/usr/bin/
# Ensure necessary bins are set as executable
chmod +x AppDir/AppRun AppDir/usr/bin/Ryujinx*
mkdir -p "$OUTDIR"
appimagetool -n --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
AppDir "$OUTDIR"/Ryujinx.AppImage
Binary file not shown.
+5 -3
View File
@@ -10,6 +10,8 @@
<string>Ryujinx</string>
<key>CFBundleIconFile</key>
<string>Ryujinx.icns</string>
<key>CFBundleIconName</key>
<string>Ryujinx</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
@@ -40,17 +42,17 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.1</string>
<string>2.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.1.0</string>
<string>2.0.0</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
<string>Copyright © 2018 - 2024 Ryujinx Team and Contributors. Copyright © 2024 - 2025 Kenji-NX and Contributors.</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key>
Binary file not shown.
+20 -17
View File
@@ -19,7 +19,7 @@ if platform.system() == "Darwin":
else:
OTOOL = shutil.which("llvm-otool")
if OTOOL is None:
for llvm_ver in [15, 14, 13]:
for llvm_ver in [17, 16, 15, 14, 13]:
otool_path = shutil.which(f"llvm-otool-{llvm_ver}")
if otool_path is not None:
OTOOL = otool_path
@@ -562,26 +562,29 @@ search_path = [
for path in content_directory.rglob("**/*.dylib"):
current_search_path = [path.parent]
current_search_path.extend(search_path)
if not path.name.startswith("._"):
current_search_path = [path.parent]
current_search_path.extend(search_path)
fixup_dylib(
path,
get_path_related_to_target_exec(content_directory, path),
current_search_path,
content_directory,
)
print(f"Fixing path '{path}' using search path of '{current_search_path}' for context of '{content_directory}'.")
fixup_dylib(
path,
get_path_related_to_target_exec(content_directory, path),
current_search_path,
content_directory,
)
for path in content_directory.rglob("**/*.so"):
current_search_path = [path.parent]
current_search_path.extend(search_path)
if not path.name.startswith("._"):
current_search_path = [path.parent]
current_search_path.extend(search_path)
fixup_dylib(
path,
get_path_related_to_target_exec(content_directory, path),
current_search_path,
content_directory,
)
fixup_dylib(
path,
get_path_related_to_target_exec(content_directory, path),
current_search_path,
content_directory,
)
with open(executable_path, "rb") as input:
+13 -14
View File
@@ -26,7 +26,7 @@ else:
LIPO = shutil.which("llvm-lipo")
if LIPO is None:
for llvm_ver in [15, 14, 13]:
for llvm_ver in [17, 16, 15, 14, 13]:
lipo_path = shutil.which(f"llvm-lipo-{llvm_ver}")
if lipo_path is not None:
LIPO = lipo_path
@@ -47,14 +47,12 @@ def get_new_name(
input_component = str(input_dylib_path).replace(str(input_directory), "")[1:]
return Path(os.path.join(output_directory, input_component))
def is_fat_file(dylib_path: Path) -> str:
res = subprocess.check_output([LIPO, "-info", str(dylib_path.absolute())]).decode(
"utf-8"
)
return not res.split("\n")[0].startswith("Non-fat file")
def get_archs(dylib_path: Path) -> list[str]:
res = subprocess.check_output([LIPO, "-info", str(dylib_path)]).decode("utf-8")
if res.startswith("Non-fat file"):
return [res.split(":")[-1].strip()]
else:
return res.split("are:")[-1].strip().split()
def construct_universal_dylib(
arm64_input_dylib_path: Path, x86_64_input_dylib_path: Path, output_dylib_path: Path
@@ -69,11 +67,12 @@ def construct_universal_dylib(
os.path.basename(arm64_input_dylib_path.resolve()), output_dylib_path
)
else:
if is_fat_file(arm64_input_dylib_path) or not x86_64_input_dylib_path.exists():
with open(output_dylib_path, "wb") as dst:
with open(arm64_input_dylib_path, "rb") as src:
dst.write(src.read())
else:
arm64_archs = get_archs(arm64_input_dylib_path)
x86_64_archs = get_archs(x86_64_input_dylib_path) if x86_64_input_dylib_path.exists() else []
if "arm64" in arm64_archs and "x86_64" in arm64_archs:
shutil.copy2(arm64_input_dylib_path, output_dylib_path)
elif x86_64_archs:
subprocess.check_call(
[
LIPO,
+20 -5
View File
@@ -25,26 +25,41 @@ cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
cp Assets.car "$APP_BUNDLE_DIRECTORY/Contents/Resources/Assets.car"
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
# Fixup libraries and executable
echo "Running bundle fix up python script"
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
# Resign all dyplib files as ad-hoc after changing them
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec codesign --force --sign - {} \;
# Now sign it
echo "Starting signing process"
if ! [ -x "$(command -v codesign)" ];
then
if ! [ -x "$(command -v rcodesign)" ];
then
echo "Cannot find rcodesign on your system, please install rcodesign."
echo "Cannot find rcodesign on your system, please install rcodesign and ensure it is in your search path."
exit 1
fi
# cargo install apple-codesign
echo "Usign rcodesign for ad-hoc signing"
echo "Using rcodesign for ad-hoc signing"
echo "Resigning all frameworks dylib files as ad-hoc"
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec rcodesign sign {} \;
echo "Signing app bundle as ad-hoc"
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
else
echo "Usign codesign for ad-hoc signing"
echo "Using codesign for ad-hoc signing"
echo "Resigning all frameworks dylib files as ad-hoc"
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec codesign --force --sign - {} \;
echo "Signing app bundle as ad-hoc"
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$APP_BUNDLE_DIRECTORY"
fi
fi
+16 -10
View File
@@ -20,7 +20,19 @@ SOURCE_REVISION_ID=$6
CONFIGURATION=$7
EXTRA_ARGS=$8
if [ "$VERSION" == "1.1.0" ];
if [[ "$(uname)" == "Darwin" ]]; then
echo "Clearing xattr on all dot underscore files"
find "$BASE_DIR" -type f -name "._*" -exec sh -c '
for f; do
dir=$(dirname "$f")
base=$(basename "$f")
orig="$dir/${base#._}"
[ -f "$orig" ] && xattr -c "$orig" || true
done
' sh {} +
fi
if [ "$VERSION" == "2.0.0" ];
then
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
else
@@ -66,11 +78,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_
if ! [ -x "$(command -v lipo)" ];
then
if ! [ -x "$(command -v llvm-lipo-14)" ];
if ! [ -x "$(command -v llvm-lipo-17)" ];
then
LIPO=llvm-lipo
else
LIPO=llvm-lipo-14
LIPO=llvm-lipo-17
fi
else
LIPO=lipo
@@ -109,12 +121,6 @@ python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
# Create legacy update package for Avalonia to not left behind old testers.
if [ "$VERSION" != "1.1.0" ];
then
cp $RELEASE_TAR_FILE_NAME.gz test-ava-ryujinx-$VERSION-macos_universal.app.tar.gz
fi
popd
echo "Done"
echo "Done"
@@ -1,111 +0,0 @@
#!/bin/bash
set -e
if [ "$#" -lt 7 ]; then
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION> <EXTRA_ARGS>"
exit 1
fi
mkdir -p "$1"
mkdir -p "$2"
mkdir -p "$3"
BASE_DIR=$(readlink -f "$1")
TEMP_DIRECTORY=$(readlink -f "$2")
OUTPUT_DIRECTORY=$(readlink -f "$3")
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
VERSION=$5
SOURCE_REVISION_ID=$6
CONFIGURATION=$7
EXTRA_ARGS=$8
if [ "$VERSION" == "1.1.0" ];
then
RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar
else
RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$VERSION-macos_universal.tar
fi
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL2
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
dotnet restore
dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL2
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
# Get rid of libsoundio from arm64 builds as we don't have a arm64 variant
# TODO: remove this once done
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
rm -rf "$OUTPUT_DIRECTORY"
mkdir -p "$OUTPUT_DIRECTORY"
# Let's copy one of the two different outputs and remove the executable
cp -R "$ARM64_OUTPUT/" "$UNIVERSAL_OUTPUT"
rm "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH"
# Make it libraries universal
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTPUT" "$X64_OUTPUT" "$UNIVERSAL_OUTPUT" "**/*.dylib"
if ! [ -x "$(command -v lipo)" ];
then
if ! [ -x "$(command -v llvm-lipo-14)" ];
then
LIPO=llvm-lipo
else
LIPO=llvm-lipo-14
fi
else
LIPO=lipo
fi
# Make the executable universal
$LIPO "$ARM64_OUTPUT/$EXECUTABLE_SUB_PATH" "$X64_OUTPUT/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH" -create
# Now sign it
if ! [ -x "$(command -v codesign)" ];
then
if ! [ -x "$(command -v rcodesign)" ];
then
echo "Cannot find rcodesign on your system, please install rcodesign."
exit 1
fi
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
echo "Using rcodesign for ad-hoc signing"
for FILE in "$UNIVERSAL_OUTPUT"/*; do
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$FILE"
fi
done
else
echo "Using codesign for ad-hoc signing"
for FILE in "$UNIVERSAL_OUTPUT"/*; do
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$FILE"
fi
done
fi
echo "Creating archive"
pushd "$OUTPUT_DIRECTORY"
tar --exclude "publish/Ryujinx.Headless.SDL2" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
popd
echo "Done"
+1 -1
View File
@@ -8,7 +8,7 @@ Intro to Kenji-NX
Kenji-NX is an open-source Nintendo Switch emulator written in C#. It is based on Ryujinx, which was originally created by gdkchan.
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
* 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.
* Audio output is entirely supported via C# wrappers for SDL2, with OpenAL & libsoundio as fallbacks.
* Audio output is entirely supported via C# wrappers for SDL3, with OpenAL & libsoundio as fallbacks.
Getting Started
===============
+1 -1
View File
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.100",
"version": "10.0.100",
"rollForward": "latestFeature"
}
}
+5 -1
View File
@@ -4,7 +4,8 @@
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- Only needed when using pre-release versions of Ryujinx.LibHac. -->
<add key="LibHacAlpha" value="https://git.ryujinx.app/api/v4/projects/17/packages/nuget/index.json" />
<add key="LibHacAlpha" value="https://git.ryujinx.app/api/packages/projects/nuget/index.json" />
<!--<add key="Silk.NET" value="https://gitlab.com/api/v4/projects/51457475/packages/nuget/index.json" />-->
</packageSources>
<packageSourceMapping>
<!-- key value for <packageSource> should match key values from <packageSources> element -->
@@ -15,5 +16,8 @@
<packageSource key="LibHacAlpha">
<package pattern="Ryujinx.LibHac" />
</packageSource>
<!--<packageSource key="Silk.NET">
<package pattern="Silk.*" />
</packageSource>-->
</packageSourceMapping>
</configuration>
@@ -127,13 +127,13 @@ namespace ARMeilleure.CodeGen.Arm64
#region macOS
[LibraryImport("libSystem.dylib", SetLastError = true)]
private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, nint newValue, ulong newValueSize);
[SupportedOSPlatform("macos")]
private static bool CheckSysctlName(string name)
{
ulong size = sizeof(int);
if (sysctlbyname(name, out int val, ref size, IntPtr.Zero, 0) == 0 && size == sizeof(int))
if (sysctlbyname(name, out int val, ref size, nint.Zero, 0) == 0 && size == sizeof(int))
{
return val != 0;
}
+1 -2
View File
@@ -1,7 +1,6 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Translation.Cache;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.CodeGen
@@ -58,7 +57,7 @@ namespace ARMeilleure.CodeGen
/// <typeparam name="T">Type of delegate</typeparam>
/// <param name="codePointer">Pointer to the function code in memory</param>
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
public T MapWithPointer<T>(out IntPtr codePointer)
public T MapWithPointer<T>(out nint codePointer)
{
codePointer = JitCache.Map(this);
@@ -387,7 +387,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public override int GetHashCode()
{
return HashCode.Combine((IntPtr)_data);
return HashCode.Combine((nint)_data);
}
public override string ToString()
@@ -63,7 +63,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public override int GetHashCode()
{
return HashCode.Combine((IntPtr)_data);
return HashCode.Combine((nint)_data);
}
public override string ToString()
+3 -3
View File
@@ -1106,17 +1106,17 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
if (flags.HasFlag(InstructionFlags.Prefix66))
if ((flags & InstructionFlags.Prefix66) != 0)
{
WriteByte(0x66);
}
if (flags.HasFlag(InstructionFlags.PrefixF2))
if ((flags & InstructionFlags.PrefixF2) != 0f)
{
WriteByte(0xf2);
}
if (flags.HasFlag(InstructionFlags.PrefixF3))
if ((flags & InstructionFlags.PrefixF3) != 0f)
{
WriteByte(0xf3);
}
+4 -4
View File
@@ -20,7 +20,7 @@ namespace ARMeilleure.Common
private List<PageInfo> _pages;
private readonly ulong _pageSize;
private readonly uint _pageCount;
private readonly List<IntPtr> _extras;
private readonly List<nint> _extras;
public ArenaAllocator(uint pageSize, uint pageCount)
{
@@ -64,7 +64,7 @@ namespace ARMeilleure.Common
{
void* extra = NativeAllocator.Instance.Allocate(size);
_extras.Add((IntPtr)extra);
_extras.Add((nint)extra);
return extra;
}
@@ -114,7 +114,7 @@ namespace ARMeilleure.Common
}
// Free extra blocks that are not page-sized
foreach (IntPtr ptr in _extras)
foreach (nint ptr in _extras)
{
NativeAllocator.Instance.Free((void*)ptr);
}
@@ -173,7 +173,7 @@ namespace ARMeilleure.Common
NativeAllocator.Instance.Free(info.Pointer);
}
foreach (IntPtr ptr in _extras)
foreach (nint ptr in _extras)
{
NativeAllocator.Instance.Free((void*)ptr);
}
+4 -4
View File
@@ -15,7 +15,7 @@ namespace ARMeilleure.Common
private int _freeHint;
private readonly int _pageCapacity; // Number of entries per page.
private readonly int _pageLogCapacity;
private readonly Dictionary<int, IntPtr> _pages;
private readonly Dictionary<int, nint> _pages;
private readonly BitMap _allocated;
/// <summary>
@@ -41,7 +41,7 @@ namespace ARMeilleure.Common
}
_allocated = new BitMap(NativeAllocator.Instance);
_pages = new Dictionary<int, IntPtr>();
_pages = new Dictionary<int, nint>();
_pageLogCapacity = BitOperations.Log2((uint)(pageSize / sizeof(TEntry)));
_pageCapacity = 1 << _pageLogCapacity;
}
@@ -138,9 +138,9 @@ namespace ARMeilleure.Common
{
var pageIndex = (int)((uint)(index & ~(_pageCapacity - 1)) >> _pageLogCapacity);
if (!_pages.TryGetValue(pageIndex, out IntPtr page))
if (!_pages.TryGetValue(pageIndex, out nint page))
{
page = (IntPtr)NativeAllocator.Instance.Allocate((uint)sizeof(TEntry) * (uint)_pageCapacity);
page = (nint)NativeAllocator.Instance.Allocate((uint)sizeof(TEntry) * (uint)_pageCapacity);
_pages.Add(pageIndex, page);
}
+2 -2
View File
@@ -9,7 +9,7 @@ namespace ARMeilleure.Common
public override void* Allocate(ulong size)
{
void* result = (void*)Marshal.AllocHGlobal((IntPtr)size);
void* result = (void*)Marshal.AllocHGlobal((nint)size);
if (result == null)
{
@@ -21,7 +21,7 @@ namespace ARMeilleure.Common
public override void Free(void* block)
{
Marshal.FreeHGlobal((IntPtr)block);
Marshal.FreeHGlobal((nint)block);
}
}
}
@@ -200,11 +200,7 @@ namespace ARMeilleure.Instructions
ExecutionContext context = GetContext();
// If debugging, we'll handle interrupts outside
if (!Optimizations.EnableDebugging)
{
context.CheckInterrupt();
}
context.CheckInterrupt();
Statistics.ResumeTimer();
@@ -32,7 +32,7 @@ namespace ARMeilleure.IntermediateRepresentation
/// <exception cref="ArgumentException"><typeparamref name="T"/> is not pointer sized.</exception>
public IntrusiveList()
{
if (Unsafe.SizeOf<T>() != IntPtr.Size)
if (Unsafe.SizeOf<T>() != nint.Size)
{
throw new ArgumentException("T must be a reference type or a pointer sized struct.");
}
@@ -1,4 +1,3 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@@ -24,7 +23,7 @@ namespace ARMeilleure.IntermediateRepresentation
{
Debug.Assert(operand.Kind == OperandKind.Memory);
_data = (Data*)Unsafe.As<Operand, IntPtr>(ref operand);
_data = (Data*)Unsafe.As<Operand, nint>(ref operand);
}
public Operand BaseAddress
@@ -228,7 +228,7 @@ namespace ARMeilleure.IntermediateRepresentation
public readonly override int GetHashCode()
{
return HashCode.Combine((IntPtr)_data);
return HashCode.Combine((nint)_data);
}
public static bool operator ==(Operation a, Operation b)
+1 -1
View File
@@ -4,7 +4,7 @@ namespace ARMeilleure.Memory
{
public interface IJitMemoryBlock : IDisposable
{
IntPtr Pointer { get; }
nint Pointer { get; }
void Commit(ulong offset, ulong size);
+1 -1
View File
@@ -6,7 +6,7 @@ namespace ARMeilleure.Memory
{
int AddressSpaceBits { get; }
IntPtr PageTablePointer { get; }
nint PageTablePointer { get; }
MemoryManagerType Type { get; }
+1 -1
View File
@@ -9,7 +9,7 @@ namespace ARMeilleure.Memory
public IJitMemoryBlock Block { get; }
public IJitMemoryAllocator Allocator { get; }
public IntPtr Pointer => Block.Pointer;
public nint Pointer => Block.Pointer;
private readonly ulong _maxSize;
private readonly ulong _sizeGranularity;
+1 -2
View File
@@ -1,4 +1,3 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
@@ -8,6 +7,6 @@ namespace ARMeilleure.Native
static partial class JitSupportDarwin
{
[LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")]
public static partial void Copy(IntPtr dst, IntPtr src, ulong n);
public static partial void Copy(nint dst, nint src, ulong n);
}
}
@@ -21,7 +21,7 @@ namespace ARMeilleure.Signal
private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize)
private static Operand EmitGenericRegionCheck(EmitterContext context, nint signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize)
{
Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
context.Copy(inRegionLocal, Const(0));
@@ -155,7 +155,7 @@ namespace ARMeilleure.Signal
throw new PlatformNotSupportedException();
}
public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize)
public static byte[] GenerateUnixSignalHandler(nint signalStructPtr, int rangeStructSize)
{
EmitterContext context = new();
@@ -203,7 +203,7 @@ namespace ARMeilleure.Signal
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
}
public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize)
public static byte[] GenerateWindowsSignalHandler(nint signalStructPtr, int rangeStructSize)
{
EmitterContext context = new();
+2 -3
View File
@@ -1,6 +1,5 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Runtime.InteropServices;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
@@ -16,7 +15,7 @@ namespace ARMeilleure.Signal
{
public delegate bool DebugPartialUnmap();
public delegate int DebugThreadLocalMapGetOrReserve(int threadId, int initialState);
public delegate void DebugNativeWriteLoop(IntPtr nativeWriteLoopPtr, IntPtr writePtr);
public delegate void DebugNativeWriteLoop(nint nativeWriteLoopPtr, nint writePtr);
public static DebugPartialUnmap GenerateDebugPartialUnmap()
{
@@ -35,7 +34,7 @@ namespace ARMeilleure.Signal
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugPartialUnmap>();
}
public static DebugThreadLocalMapGetOrReserve GenerateDebugThreadLocalMapGetOrReserve(IntPtr structPtr)
public static DebugThreadLocalMapGetOrReserve GenerateDebugThreadLocalMapGetOrReserve(nint structPtr)
{
EmitterContext context = new();
@@ -1,7 +1,6 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using Ryujinx.Common.Memory.PartialUnmaps;
using System;
using System.Runtime.InteropServices;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
@@ -13,18 +12,18 @@ namespace ARMeilleure.Signal
internal static partial class WindowsPartialUnmapHandler
{
[LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
private static partial nint LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
[LibraryImport("kernel32.dll", SetLastError = true)]
private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
private static partial nint GetProcAddress(nint hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
private static IntPtr _getCurrentThreadIdPtr;
private static nint _getCurrentThreadIdPtr;
public static IntPtr GetCurrentThreadIdFunc()
public static nint GetCurrentThreadIdFunc()
{
if (_getCurrentThreadIdPtr == IntPtr.Zero)
if (_getCurrentThreadIdPtr == nint.Zero)
{
IntPtr handle = LoadLibrary("kernel32.dll");
nint handle = LoadLibrary("kernel32.dll");
_getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
}
@@ -34,13 +33,13 @@ namespace ARMeilleure.Signal
public static Operand EmitRetryFromAccessViolation(EmitterContext context)
{
IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState;
IntPtr localCountsPtr = IntPtr.Add(partialRemapStatePtr, PartialUnmapState.LocalCountsOffset);
nint partialRemapStatePtr = PartialUnmapState.GlobalState;
nint localCountsPtr = nint.Add(partialRemapStatePtr, PartialUnmapState.LocalCountsOffset);
// Get the lock first.
EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
EmitNativeReaderLockAcquire(context, nint.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
IntPtr getCurrentThreadId = GetCurrentThreadIdFunc();
nint getCurrentThreadId = GetCurrentThreadIdFunc();
Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32);
Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0));
@@ -58,7 +57,7 @@ namespace ARMeilleure.Signal
Operand threadLocalPartialUnmapsPtr = EmitThreadLocalMapIntGetValuePtr(context, localCountsPtr, threadIndex);
Operand threadLocalPartialUnmaps = context.Load(OperandType.I32, threadLocalPartialUnmapsPtr);
Operand partialUnmapsCount = context.Load(OperandType.I32, Const((ulong)IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapsCountOffset)));
Operand partialUnmapsCount = context.Load(OperandType.I32, Const((ulong)nint.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapsCountOffset)));
context.Copy(retry, context.ICompareNotEqual(threadLocalPartialUnmaps, partialUnmapsCount));
@@ -79,14 +78,14 @@ namespace ARMeilleure.Signal
context.MarkLabel(endLabel);
// Finally, release the lock and return the retry value.
EmitNativeReaderLockRelease(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
EmitNativeReaderLockRelease(context, nint.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
return retry;
}
public static Operand EmitThreadLocalMapIntGetOrReserve(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand initialState)
public static Operand EmitThreadLocalMapIntGetOrReserve(EmitterContext context, nint threadLocalMapPtr, Operand threadId, Operand initialState)
{
Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.ThreadIdsOffset));
Operand idsPtr = Const((ulong)nint.Add(threadLocalMapPtr, ThreadLocalMap<int>.ThreadIdsOffset));
Operand i = context.AllocateLocal(OperandType.I32);
@@ -130,7 +129,7 @@ namespace ARMeilleure.Signal
// If it was 0, then we need to initialize the struct entry and return i.
context.BranchIfFalse(idNot0Label, context.ICompareEqual(existingId2, Const(0)));
Operand structsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
Operand structsPtr = Const((ulong)nint.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
Operand structPtr = context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset2));
context.Store(structPtr, initialState);
@@ -149,10 +148,10 @@ namespace ARMeilleure.Signal
return context.Copy(i);
}
private static Operand EmitThreadLocalMapIntGetValuePtr(EmitterContext context, IntPtr threadLocalMapPtr, Operand index)
private static Operand EmitThreadLocalMapIntGetValuePtr(EmitterContext context, nint threadLocalMapPtr, Operand index)
{
Operand offset = context.Multiply(index, Const(sizeof(int)));
Operand structsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
Operand structsPtr = Const((ulong)nint.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset));
}
@@ -170,9 +169,9 @@ namespace ARMeilleure.Signal
context.BranchIfFalse(loop, context.ICompareEqual(initial, replaced));
}
private static void EmitNativeReaderLockAcquire(EmitterContext context, IntPtr nativeReaderLockPtr)
private static void EmitNativeReaderLockAcquire(EmitterContext context, nint nativeReaderLockPtr)
{
Operand writeLockPtr = Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.WriteLockOffset));
Operand writeLockPtr = Const((ulong)nint.Add(nativeReaderLockPtr, NativeReaderWriterLock.WriteLockOffset));
// Spin until we can acquire the write lock.
Operand spinLabel = Label();
@@ -182,16 +181,16 @@ namespace ARMeilleure.Signal
context.BranchIfTrue(spinLabel, context.CompareAndSwap(writeLockPtr, Const(0), Const(1)));
// Increment reader count.
EmitAtomicAddI32(context, Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(1));
EmitAtomicAddI32(context, Const((ulong)nint.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(1));
// Release write lock.
context.CompareAndSwap(writeLockPtr, Const(1), Const(0));
}
private static void EmitNativeReaderLockRelease(EmitterContext context, IntPtr nativeReaderLockPtr)
private static void EmitNativeReaderLockRelease(EmitterContext context, nint nativeReaderLockPtr)
{
// Decrement reader count.
EmitAtomicAddI32(context, Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(-1));
EmitAtomicAddI32(context, Const((ulong)nint.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(-1));
}
}
}
+1 -2
View File
@@ -1,5 +1,4 @@
using ARMeilleure.Memory;
using System;
using System.Threading;
namespace ARMeilleure.State
@@ -10,7 +9,7 @@ namespace ARMeilleure.State
private readonly NativeContext _nativeContext;
internal IntPtr NativeContextPtr => _nativeContext.BasePtr;
internal nint NativeContextPtr => _nativeContext.BasePtr;
internal bool Interrupted { get; private set; }
+1 -1
View File
@@ -35,7 +35,7 @@ namespace ARMeilleure.State
private readonly IJitMemoryBlock _block;
public IntPtr BasePtr => _block.Pointer;
public nint BasePtr => _block.Pointer;
public NativeContext(IJitMemoryAllocator allocator)
{
@@ -6,7 +6,6 @@ using ARMeilleure.Instructions;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Memory;
using ARMeilleure.State;
using System;
using System.Collections.Generic;
using System.Reflection;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
@@ -95,7 +94,7 @@ namespace ARMeilleure.Translation
else
{
int index = Delegates.GetDelegateIndex(info);
IntPtr funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
nint funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
OperandType returnType = GetOperandType(info.ReturnType);
@@ -36,7 +36,7 @@ namespace ARMeilleure.Translation.Cache
[SupportedOSPlatform("windows")]
[LibraryImport("kernel32.dll", SetLastError = true)]
public static partial IntPtr FlushInstructionCache(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize);
public static partial nint FlushInstructionCache(nint hProcess, nint lpAddress, nuint dwSize);
public static void Initialize(IJitMemoryAllocator allocator)
{
@@ -85,7 +85,7 @@ namespace ARMeilleure.Translation.Cache
}
}
public static IntPtr Map(CompiledFunction func)
public static nint Map(CompiledFunction func)
{
byte[] code = func.Code;
@@ -95,7 +95,7 @@ namespace ARMeilleure.Translation.Cache
int funcOffset = Allocate(code.Length);
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
IntPtr funcPtr = targetRegion.Pointer + funcOffset;
nint funcPtr = targetRegion.Pointer + funcOffset;
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
@@ -103,7 +103,7 @@ namespace ARMeilleure.Translation.Cache
{
fixed (byte* codePtr = code)
{
JitSupportDarwin.Copy(funcPtr, (IntPtr)codePtr, (ulong)code.Length);
JitSupportDarwin.Copy(funcPtr, (nint)codePtr, (ulong)code.Length);
}
}
}
@@ -115,7 +115,7 @@ namespace ARMeilleure.Translation.Cache
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
FlushInstructionCache(Process.GetCurrentProcess().Handle, funcPtr, (UIntPtr)code.Length);
FlushInstructionCache(Process.GetCurrentProcess().Handle, funcPtr, (nuint)code.Length);
}
else
{
@@ -129,7 +129,7 @@ namespace ARMeilleure.Translation.Cache
}
}
public static void Unmap(IntPtr pointer)
public static void Unmap(nint pointer)
{
lock (_lock)
{
@@ -1,5 +1,4 @@
using ARMeilleure.Memory;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Translation.Cache
@@ -68,7 +67,7 @@ namespace ARMeilleure.Translation.Cache
}
}
public void Invalidate(IntPtr basePointer, ulong size)
public void Invalidate(nint basePointer, ulong size)
{
if (_needsInvalidation)
{
@@ -40,7 +40,7 @@ namespace ARMeilleure.Translation.Cache
PushMachframe = 10,
}
private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, IntPtr context);
private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, nint context);
[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
@@ -49,7 +49,7 @@ namespace ARMeilleure.Translation.Cache
ulong baseAddress,
uint length,
GetRuntimeFunctionCallback callback,
IntPtr context,
nint context,
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
[LibraryImport("kernel32.dll")]
@@ -65,7 +65,7 @@ namespace ARMeilleure.Translation.Cache
private unsafe static UnwindInfo* _unwindInfo;
public static void InstallFunctionTableHandler(IntPtr codeCachePointer, uint codeCacheLength, IntPtr workBufferPtr)
public static void InstallFunctionTableHandler(nint codeCachePointer, uint codeCacheLength, nint workBufferPtr)
{
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
@@ -96,7 +96,7 @@ namespace ARMeilleure.Translation.Cache
}
}
public static void RemoveFunctionTableHandler(IntPtr codeCachePointer)
public static void RemoveFunctionTableHandler(nint codeCachePointer)
{
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
@@ -113,7 +113,7 @@ namespace ARMeilleure.Translation.Cache
}
}
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, IntPtr context)
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
{
int offset = (int)((long)controlPc - context.ToInt64());
+2 -4
View File
@@ -1,12 +1,10 @@
using System;
namespace ARMeilleure.Translation
{
class DelegateInfo
{
public IntPtr FuncPtr { get; }
public nint FuncPtr { get; }
public DelegateInfo(IntPtr funcPtr)
public DelegateInfo(nint funcPtr)
{
FuncPtr = funcPtr;
}
+2 -2
View File
@@ -7,7 +7,7 @@ namespace ARMeilleure.Translation
{
static class Delegates
{
public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr)
public static bool TryGetDelegateFuncPtrByIndex(int index, out nint funcPtr)
{
if (index >= 0 && index < _delegates.Count)
{
@@ -23,7 +23,7 @@ namespace ARMeilleure.Translation
}
}
public static IntPtr GetDelegateFuncPtrByIndex(int index)
public static nint GetDelegateFuncPtrByIndex(int index)
{
if (index < 0 || index >= _delegates.Count)
{
@@ -1,7 +1,5 @@
using System;
namespace ARMeilleure.Translation
{
delegate void DispatcherFunction(IntPtr nativeContext, ulong startAddress);
delegate ulong WrapperFunction(IntPtr nativeContext, ulong startAddress);
delegate void DispatcherFunction(nint nativeContext, ulong startAddress);
delegate ulong WrapperFunction(nint nativeContext, ulong startAddress);
}
@@ -97,7 +97,7 @@ namespace ARMeilleure.Translation
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
{
IntPtr funcPtr = info.MethodHandle.GetFunctionPointer();
nint funcPtr = info.MethodHandle.GetFunctionPointer();
OperandType returnType = GetOperandType(info.ReturnType);
+1 -3
View File
@@ -1,6 +1,4 @@
using System;
namespace ARMeilleure.Translation
{
delegate ulong GuestFunction(IntPtr nativeContextPtr);
delegate ulong GuestFunction(nint nativeContextPtr);
}
+5 -17
View File
@@ -316,7 +316,7 @@ namespace ARMeilleure.Translation
{
_root = newNode;
}
else if (start.CompareTo(parent.Start) < 0)
else if (start.CompareTo(parent!.Start) < 0)
{
parent.Left = newNode;
}
@@ -359,10 +359,7 @@ namespace ARMeilleure.Translation
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
if (tmp != null)
{
tmp.Parent = ParentOf(replacementNode);
}
tmp?.Parent = ParentOf(replacementNode);
if (ParentOf(replacementNode) == null)
{
@@ -570,10 +567,7 @@ namespace ARMeilleure.Translation
{
IntervalTreeNode<TK, TV> right = RightOf(node);
node.Right = LeftOf(right);
if (node.Right != null)
{
node.Right.Parent = node;
}
node.Right?.Parent = node;
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
right.Parent = nodeParent;
if (nodeParent == null)
@@ -601,10 +595,7 @@ namespace ARMeilleure.Translation
{
IntervalTreeNode<TK, TV> left = LeftOf(node);
node.Left = RightOf(left);
if (node.Left != null)
{
node.Left.Parent = node;
}
node.Left?.Parent = node;
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
left.Parent = nodeParent;
if (nodeParent == null)
@@ -651,10 +642,7 @@ namespace ARMeilleure.Translation
/// <param name="color">Color (Boolean)</param>
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
{
if (node != null)
{
node.Color = color;
}
node?.Color = color;
}
/// <summary>
+12 -14
View File
@@ -107,7 +107,7 @@ namespace ARMeilleure.Translation.PTC
Profiler.Wait();
Profiler.ClearEntries();
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache v{InternalVersion}\n\t\t (title: {titleIdText}, version: '{displayVersion}', selector: '{cacheSelector}', enabled: {enabled}).");
if (!enabled || string.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault)
{
@@ -126,8 +126,6 @@ namespace ARMeilleure.Translation.PTC
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
_memoryMode = memoryMode;
Logger.Info?.Print(LogClass.Ptc, $"PPTC (v{InternalVersion}) Profile: {DisplayVersion}-{cacheSelector}");
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
@@ -259,11 +257,11 @@ namespace ARMeilleure.Translation.PTC
return false;
}
IntPtr intPtr = IntPtr.Zero;
nint intPtr = nint.Zero;
try
{
intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize));
intPtr = Marshal.AllocHGlobal(new nint(outerHeader.UncompressedStreamSize));
using UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite);
try
@@ -357,7 +355,7 @@ namespace ARMeilleure.Translation.PTC
}
finally
{
if (intPtr != IntPtr.Zero)
if (intPtr != nint.Zero)
{
Marshal.FreeHGlobal(intPtr);
}
@@ -440,11 +438,11 @@ namespace ARMeilleure.Translation.PTC
outerHeader.SetHeaderHash();
IntPtr intPtr = IntPtr.Zero;
nint intPtr = nint.Zero;
try
{
intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize));
intPtr = Marshal.AllocHGlobal(new nint(outerHeader.UncompressedStreamSize));
using UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite);
stream.Seek((long)Unsafe.SizeOf<InnerHeader>(), SeekOrigin.Begin);
@@ -498,7 +496,7 @@ namespace ARMeilleure.Translation.PTC
}
finally
{
if (intPtr != IntPtr.Zero)
if (intPtr != nint.Zero)
{
Marshal.FreeHGlobal(intPtr);
}
@@ -650,7 +648,7 @@ namespace ARMeilleure.Translation.PTC
foreach (RelocEntry relocEntry in relocEntries)
{
IntPtr? imm = null;
nint? imm = null;
Symbol symbol = relocEntry.Symbol;
if (symbol.Type == SymbolType.FunctionTable)
@@ -661,7 +659,7 @@ namespace ARMeilleure.Translation.PTC
{
unsafe
{
imm = (IntPtr)Unsafe.AsPointer(ref translator.FunctionTable.GetValue(guestAddress));
imm = (nint)Unsafe.AsPointer(ref translator.FunctionTable.GetValue(guestAddress));
}
}
}
@@ -669,7 +667,7 @@ namespace ARMeilleure.Translation.PTC
{
int index = (int)symbol.Value;
if (Delegates.TryGetDelegateFuncPtrByIndex(index, out IntPtr funcPtr))
if (Delegates.TryGetDelegateFuncPtrByIndex(index, out nint funcPtr))
{
imm = funcPtr;
}
@@ -684,7 +682,7 @@ namespace ARMeilleure.Translation.PTC
unsafe
{
imm = (IntPtr)Unsafe.AsPointer(ref callCounter.Value);
imm = (nint)Unsafe.AsPointer(ref callCounter.Value);
}
}
else if (symbol == DispatchStubSymbol)
@@ -734,7 +732,7 @@ namespace ARMeilleure.Translation.PTC
bool highCq)
{
var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer);
var gFunc = cFunc.MapWithPointer<GuestFunction>(out nint gFuncPointer);
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
}
@@ -1,5 +1,4 @@
using ARMeilleure.Common;
using System;
namespace ARMeilleure.Translation
{
@@ -7,12 +6,12 @@ namespace ARMeilleure.Translation
{
private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
public IntPtr FuncPointer { get; }
public nint FuncPointer { get; }
public Counter<uint> CallCounter { get; }
public ulong GuestSize { get; }
public bool HighCq { get; }
public TranslatedFunction(GuestFunction func, IntPtr funcPointer, Counter<uint> callCounter, ulong guestSize, bool highCq)
public TranslatedFunction(GuestFunction func, nint funcPointer, Counter<uint> callCounter, ulong guestSize, bool highCq)
{
_func = func;
FuncPointer = funcPointer;
+1 -1
View File
@@ -305,7 +305,7 @@ namespace ARMeilleure.Translation
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
}
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer);
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out nint funcPointer);
Allocators.ResetAll();
@@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
/// </summary>
class TranslatorStubs : IDisposable
{
private readonly Lazy<IntPtr> _slowDispatchStub;
private readonly Lazy<nint> _slowDispatchStub;
private bool _disposed;
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation
/// Gets the dispatch stub.
/// </summary>
/// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
public IntPtr DispatchStub
public nint DispatchStub
{
get
{
@@ -41,7 +41,7 @@ namespace ARMeilleure.Translation
/// Gets the slow dispatch stub.
/// </summary>
/// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
public IntPtr SlowDispatchStub
public nint SlowDispatchStub
{
get
{
@@ -139,7 +139,7 @@ namespace ARMeilleure.Translation
/// Generates a <see cref="DispatchStub"/>.
/// </summary>
/// <returns>Generated <see cref="DispatchStub"/></returns>
private IntPtr GenerateDispatchStub()
private nint GenerateDispatchStub()
{
var context = new EmitterContext();
@@ -197,7 +197,7 @@ namespace ARMeilleure.Translation
/// Generates a <see cref="SlowDispatchStub"/>.
/// </summary>
/// <returns>Generated <see cref="SlowDispatchStub"/></returns>
private IntPtr GenerateSlowDispatchStub()
private nint GenerateSlowDispatchStub()
{
var context = new EmitterContext();
@@ -9,7 +9,7 @@ namespace ARMeilleure.Translation
{
public static class TranslatorTestMethods
{
public delegate int FpFlagsPInvokeTest(IntPtr managedMethod);
public delegate int FpFlagsPInvokeTest(nint managedMethod);
private static bool SetPlatformFtz(EmitterContext context, bool ftz)
{
@@ -0,0 +1,16 @@
namespace Ryujinx.Audio.Backends.Apple
{
class AppleAudioBuffer
{
public readonly ulong DriverIdentifier;
public readonly ulong SampleCount;
public ulong SamplePlayed;
public AppleAudioBuffer(ulong driverIdentifier, ulong sampleCount)
{
DriverIdentifier = driverIdentifier;
SampleCount = sampleCount;
SamplePlayed = 0;
}
}
}
@@ -0,0 +1,194 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using static Ryujinx.Audio.Backends.Apple.Native.AudioToolbox;
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
namespace Ryujinx.Audio.Backends.Apple
{
[SupportedOSPlatform("macos")]
[SupportedOSPlatform("ios")]
public sealed class AppleHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
private readonly ConcurrentDictionary<AppleHardwareDeviceSession, byte> _sessions;
private readonly bool _supportSurroundConfiguration;
public float Volume { get; set; }
public AppleHardwareDeviceDriver()
{
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
_sessions = new ConcurrentDictionary<AppleHardwareDeviceSession, byte>();
_supportSurroundConfiguration = TestSurroundSupport();
Volume = 1f;
}
private bool TestSurroundSupport()
{
try
{
AudioStreamBasicDescription format =
GetAudioFormat(SampleFormat.PcmFloat, Constants.TargetSampleRate, 6);
int result = AudioQueueNewOutput(
ref format,
nint.Zero,
nint.Zero,
nint.Zero,
nint.Zero,
0,
out nint testQueue);
if (result == 0)
{
AudioChannelLayout layout = new AudioChannelLayout
{
AudioChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_1_A,
AudioChannelBitmap = 0,
NumberChannelDescriptions = 0
};
int layoutResult = AudioQueueSetProperty(
testQueue,
kAudioQueueProperty_ChannelLayout,
ref layout,
(uint)Marshal.SizeOf<AudioChannelLayout>());
if (layoutResult == 0)
{
AudioQueueDispose(testQueue, true);
return true;
}
AudioQueueDispose(testQueue, true);
}
return false;
}
catch
{
return false;
}
}
public static bool IsSupported => OperatingSystem.IsMacOSVersionAtLeast(10, 5);
public ManualResetEvent GetUpdateRequiredEvent()
=> _updateRequiredEvent;
public ManualResetEvent GetPauseEvent()
=> _pauseEvent;
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager,
SampleFormat sampleFormat, uint sampleRate, uint channelCount)
{
if (channelCount == 0)
{
channelCount = 2;
}
if (sampleRate == 0)
{
sampleRate = Constants.TargetSampleRate;
}
if (direction != Direction.Output)
{
throw new NotImplementedException("Input direction is currently not implemented on Apple backend!");
}
AppleHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
_sessions.TryAdd(session, 0);
return session;
}
internal bool Unregister(AppleHardwareDeviceSession session)
=> _sessions.TryRemove(session, out _);
internal static AudioStreamBasicDescription GetAudioFormat(SampleFormat sampleFormat, uint sampleRate,
uint channelCount)
{
uint formatFlags;
uint bitsPerChannel;
switch (sampleFormat)
{
case SampleFormat.PcmInt8:
formatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
bitsPerChannel = 8;
break;
case SampleFormat.PcmInt16:
formatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
bitsPerChannel = 16;
break;
case SampleFormat.PcmInt32:
formatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
bitsPerChannel = 32;
break;
case SampleFormat.PcmFloat:
formatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
bitsPerChannel = 32;
break;
default:
throw new ArgumentException($"Unsupported sample format {sampleFormat}");
}
uint bytesPerFrame = (bitsPerChannel / 8) * channelCount;
return new AudioStreamBasicDescription
{
SampleRate = sampleRate,
FormatID = kAudioFormatLinearPCM,
FormatFlags = formatFlags,
BytesPerPacket = bytesPerFrame,
FramesPerPacket = 1,
BytesPerFrame = bytesPerFrame,
ChannelsPerFrame = channelCount,
BitsPerChannel = bitsPerChannel,
Reserved = 0
};
}
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
private void Dispose(bool disposing)
{
if (disposing)
{
foreach (AppleHardwareDeviceSession session in _sessions.Keys)
{
session.Dispose();
}
_pauseEvent.Dispose();
}
}
public bool SupportsDirection(Direction direction)
=> direction != Direction.Input;
public bool SupportsSampleRate(uint sampleRate) => true;
public bool SupportsSampleFormat(SampleFormat sampleFormat)
=> sampleFormat != SampleFormat.PcmInt24;
public bool SupportsChannelCount(uint channelCount)
=> channelCount != 6 || _supportSurroundConfiguration;
}
}
@@ -0,0 +1,285 @@
using Ryujinx.Audio.Backends.Common;
using Ryujinx.Audio.Common;
using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading;
using System.Runtime.Versioning;
using static Ryujinx.Audio.Backends.Apple.Native.AudioToolbox;
namespace Ryujinx.Audio.Backends.Apple
{
[SupportedOSPlatform("macos")]
[SupportedOSPlatform("ios")]
class AppleHardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private const int NumBuffers = 3;
private readonly AppleHardwareDeviceDriver _driver;
private readonly ConcurrentQueue<AppleAudioBuffer> _queuedBuffers = new();
private readonly DynamicRingBuffer _ringBuffer = new();
private readonly ManualResetEvent _updateRequiredEvent;
private readonly AudioQueueOutputCallback _callbackDelegate;
private readonly GCHandle _gcHandle;
private nint _audioQueue;
private readonly nint[] _audioQueueBuffers = new nint[NumBuffers];
private readonly int[] _bufferBytesFilled = new int[NumBuffers];
private readonly int _bytesPerFrame;
private ulong _playedSampleCount;
private bool _started;
private float _volume = 1f;
private readonly object _lock = new();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void AudioQueueOutputCallback(
nint userData,
nint audioQueue,
nint buffer);
public AppleHardwareDeviceSession(
AppleHardwareDeviceDriver driver,
IVirtualMemoryManager memoryManager,
SampleFormat requestedSampleFormat,
uint requestedSampleRate,
uint requestedChannelCount)
: base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
{
_driver = driver;
_updateRequiredEvent = driver.GetUpdateRequiredEvent();
_callbackDelegate = OutputCallback;
_bytesPerFrame = BackendHelper.GetSampleSize(requestedSampleFormat) * (int)requestedChannelCount;
_gcHandle = GCHandle.Alloc(this, GCHandleType.Normal);
SetupAudioQueue();
}
private void SetupAudioQueue()
{
lock (_lock)
{
AudioStreamBasicDescription format = AppleHardwareDeviceDriver.GetAudioFormat(
RequestedSampleFormat,
RequestedSampleRate,
RequestedChannelCount);
nint callbackPtr = Marshal.GetFunctionPointerForDelegate(_callbackDelegate);
nint userData = GCHandle.ToIntPtr(_gcHandle);
int result = AudioQueueNewOutput(
ref format,
callbackPtr,
userData,
nint.Zero,
nint.Zero,
0,
out _audioQueue);
if (result != 0)
{
throw new InvalidOperationException($"AudioQueueNewOutput failed: {result}");
}
uint framesPerBuffer = RequestedSampleRate / 100;
uint bufferSize = framesPerBuffer * (uint)_bytesPerFrame;
for (int i = 0; i < NumBuffers; i++)
{
AudioQueueAllocateBuffer(_audioQueue, bufferSize, out _audioQueueBuffers[i]);
_bufferBytesFilled[i] = 0;
PrimeBuffer(_audioQueueBuffers[i], i);
}
}
}
private unsafe void PrimeBuffer(nint bufferPtr, int bufferIndex)
{
AudioQueueBuffer* buffer = (AudioQueueBuffer*)bufferPtr;
int capacityBytes = (int)buffer->AudioDataBytesCapacity;
int framesPerBuffer = capacityBytes / _bytesPerFrame;
int availableFrames = _ringBuffer.Length / _bytesPerFrame;
int framesToRead = Math.Min(availableFrames, framesPerBuffer);
int bytesToRead = framesToRead * _bytesPerFrame;
Span<byte> dst = new((void*)buffer->AudioData, capacityBytes);
dst.Clear();
if (bytesToRead > 0)
{
Span<byte> audio = dst.Slice(0, bytesToRead);
_ringBuffer.Read(audio, 0, bytesToRead);
ApplyVolume(buffer->AudioData, bytesToRead);
}
buffer->AudioDataByteSize = (uint)capacityBytes;
_bufferBytesFilled[bufferIndex] = bytesToRead;
AudioQueueEnqueueBuffer(_audioQueue, bufferPtr, 0, nint.Zero);
}
private void OutputCallback(nint userData, nint audioQueue, nint bufferPtr)
{
if (!_started || bufferPtr == nint.Zero)
return;
int bufferIndex = Array.IndexOf(_audioQueueBuffers, bufferPtr);
if (bufferIndex < 0)
return;
int bytesPlayed = _bufferBytesFilled[bufferIndex];
if (bytesPlayed > 0)
{
ProcessPlayedSamples(bytesPlayed);
}
PrimeBuffer(bufferPtr, bufferIndex);
}
private void ProcessPlayedSamples(int bytesPlayed)
{
ulong samplesPlayed = GetSampleCount(bytesPlayed);
ulong remaining = samplesPlayed;
bool needUpdate = false;
while (remaining > 0 && _queuedBuffers.TryPeek(out AppleAudioBuffer buffer))
{
ulong needed = buffer.SampleCount - Interlocked.Read(ref buffer.SamplePlayed);
ulong take = Math.Min(needed, remaining);
ulong played = Interlocked.Add(ref buffer.SamplePlayed, take);
remaining -= take;
if (played == buffer.SampleCount)
{
_queuedBuffers.TryDequeue(out _);
needUpdate = true;
}
Interlocked.Add(ref _playedSampleCount, take);
}
if (needUpdate)
{
_updateRequiredEvent.Set();
}
}
private unsafe void ApplyVolume(nint dataPtr, int byteSize)
{
float volume = Math.Clamp(_volume * _driver.Volume, 0f, 1f);
if (volume >= 0.999f)
return;
int sampleCount = byteSize / BackendHelper.GetSampleSize(RequestedSampleFormat);
switch (RequestedSampleFormat)
{
case SampleFormat.PcmInt16:
short* s16 = (short*)dataPtr;
for (int i = 0; i < sampleCount; i++)
s16[i] = (short)(s16[i] * volume);
break;
case SampleFormat.PcmFloat:
float* f32 = (float*)dataPtr;
for (int i = 0; i < sampleCount; i++)
f32[i] *= volume;
break;
case SampleFormat.PcmInt32:
int* s32 = (int*)dataPtr;
for (int i = 0; i < sampleCount; i++)
s32[i] = (int)(s32[i] * volume);
break;
case SampleFormat.PcmInt8:
sbyte* s8 = (sbyte*)dataPtr;
for (int i = 0; i < sampleCount; i++)
s8[i] = (sbyte)(s8[i] * volume);
break;
}
}
public override void QueueBuffer(AudioBuffer buffer)
{
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
_queuedBuffers.Enqueue(new AppleAudioBuffer(buffer.DataPointer, GetSampleCount(buffer)));
}
public override void Start()
{
lock (_lock)
{
if (_started)
return;
_started = true;
AudioQueueStart(_audioQueue, nint.Zero);
}
}
public override void Stop()
{
lock (_lock)
{
if (!_started)
return;
_started = false;
AudioQueuePause(_audioQueue);
}
}
public override ulong GetPlayedSampleCount()
=> Interlocked.Read(ref _playedSampleCount);
public override float GetVolume() => _volume;
public override void SetVolume(float volume) => _volume = volume;
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
{
if (!_queuedBuffers.TryPeek(out AppleAudioBuffer driverBuffer))
return true;
return driverBuffer.DriverIdentifier != buffer.DataPointer;
}
public override void PrepareToClose() { }
public override void UnregisterBuffer(AudioBuffer buffer) { }
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Stop();
if (_audioQueue != nint.Zero)
{
AudioQueueStop(_audioQueue, true);
AudioQueueDispose(_audioQueue, true);
_audioQueue = nint.Zero;
}
if (_gcHandle.IsAllocated)
{
_gcHandle.Free();
}
}
}
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
@@ -0,0 +1,102 @@
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace Ryujinx.Audio.Backends.Apple.Native
{
public static partial class AudioToolbox
{
[StructLayout(LayoutKind.Sequential)]
internal struct AudioStreamBasicDescription
{
public double SampleRate;
public uint FormatID;
public uint FormatFlags;
public uint BytesPerPacket;
public uint FramesPerPacket;
public uint BytesPerFrame;
public uint ChannelsPerFrame;
public uint BitsPerChannel;
public uint Reserved;
}
[StructLayout(LayoutKind.Sequential)]
internal struct AudioChannelLayout
{
public uint AudioChannelLayoutTag;
public uint AudioChannelBitmap;
public uint NumberChannelDescriptions;
}
internal const uint kAudioFormatLinearPCM = 0x6C70636D;
internal const uint kAudioQueueProperty_ChannelLayout = 0x6171636c;
internal const uint kAudioChannelLayoutTag_MPEG_5_1_A = 0x650006;
internal const uint kAudioFormatFlagIsFloat = (1 << 0);
internal const uint kAudioFormatFlagIsSignedInteger = (1 << 2);
internal const uint kAudioFormatFlagIsPacked = (1 << 3);
internal const uint kAudioFormatFlagIsBigEndian = (1 << 1);
internal const uint kAudioFormatFlagIsAlignedHigh = (1 << 4);
internal const uint kAudioFormatFlagIsNonInterleaved = (1 << 5);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueNewOutput(
ref AudioStreamBasicDescription format,
nint callback,
nint userData,
nint callbackRunLoop,
nint callbackRunLoopMode,
uint flags,
out nint audioQueue);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueSetProperty(
nint audioQueue,
uint propertyID,
ref AudioChannelLayout layout,
uint layoutSize);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueDispose(nint audioQueue, [MarshalAs(UnmanagedType.I1)] bool immediate);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueAllocateBuffer(
nint audioQueue,
uint bufferByteSize,
out nint buffer);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueStart(nint audioQueue, nint startTime);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueuePause(nint audioQueue);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueStop(nint audioQueue, [MarshalAs(UnmanagedType.I1)] bool immediate);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueSetParameter(
nint audioQueue,
uint parameterID,
float value);
[LibraryImport("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")]
internal static partial int AudioQueueEnqueueBuffer(
nint audioQueue,
nint buffer,
uint numPacketDescs,
nint packetDescs);
[StructLayout(LayoutKind.Sequential)]
internal struct AudioQueueBuffer
{
public uint AudioDataBytesCapacity;
public nint AudioData;
public uint AudioDataByteSize;
public nint UserData;
public uint PacketDescriptionCapacity;
public nint PacketDescriptions;
public uint PacketDescriptionCount;
}
internal const uint kAudioQueueParam_Volume = 1;
}
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
</ItemGroup>
</Project>
@@ -10,7 +10,8 @@ using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
namespace Ryujinx.Audio.Backends.OpenAL
{
public class OpenALHardwareDeviceDriver : IHardwareDeviceDriver
// ReSharper disable once InconsistentNaming
public sealed class OpenALHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ALDevice _device;
private readonly ALContext _context;
@@ -148,7 +149,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
Dispose(true);
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing)
{
@@ -9,7 +9,8 @@ using System.Threading;
namespace Ryujinx.Audio.Backends.OpenAL
{
class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase
// ReSharper disable once InconsistentNaming
sealed class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private readonly OpenALHardwareDeviceDriver _driver;
private readonly int _sourceId;
@@ -190,7 +191,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
}
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing && _driver.Unregister(this))
{
@@ -7,7 +7,7 @@
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
<ProjectReference Include="..\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj" />
<ProjectReference Include="..\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj" />
</ItemGroup>
</Project>
@@ -1,12 +1,12 @@
namespace Ryujinx.Audio.Backends.SDL2
namespace Ryujinx.Audio.Backends.SDL3
{
class SDL2AudioBuffer
class SDL3AudioBuffer
{
public readonly ulong DriverIdentifier;
public readonly ulong SampleCount;
public ulong SamplePlayed;
public SDL2AudioBuffer(ulong driverIdentifier, ulong sampleCount)
public SDL3AudioBuffer(ulong driverIdentifier, ulong sampleCount)
{
DriverIdentifier = driverIdentifier;
SampleCount = sampleCount;
@@ -2,44 +2,41 @@ using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Common.Logging;
using Ryujinx.Memory;
using Ryujinx.SDL2.Common;
using Ryujinx.SDL3.Common;
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading;
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
using static SDL2.SDL;
using SDL;
using static SDL.SDL3;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Backends.SDL2
namespace Ryujinx.Audio.Backends.SDL3
{
public class SDL2HardwareDeviceDriver : IHardwareDeviceDriver
using unsafe SDL_AudioStreamCallbackPointer = delegate* unmanaged[Cdecl]<nint, SDL_AudioStream*, int, int, void>;
public sealed class SDL3HardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
private readonly ConcurrentDictionary<SDL2HardwareDeviceSession, byte> _sessions;
private readonly ConcurrentDictionary<SDL3HardwareDeviceSession, byte> _sessions;
private readonly bool _supportSurroundConfiguration;
public float Volume { get; set; }
// TODO: Add this to SDL2-CS
// NOTE: We use a DllImport here because of marshaling issue for spec.
#pragma warning disable SYSLIB1054
[DllImport("SDL2")]
private static extern int SDL_GetDefaultAudioInfo(IntPtr name, out SDL_AudioSpec spec, int isCapture);
#pragma warning restore SYSLIB1054
public SDL2HardwareDeviceDriver()
public unsafe SDL3HardwareDeviceDriver()
{
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
_sessions = new ConcurrentDictionary<SDL2HardwareDeviceSession, byte>();
_sessions = new ConcurrentDictionary<SDL3HardwareDeviceSession, byte>();
SDL2Driver.Instance.Initialize();
SDL3Driver.Instance.Initialize();
int res = SDL_GetDefaultAudioInfo(IntPtr.Zero, out var spec, 0);
if (res != 0)
SDL_AudioSpec spec;
if (!SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, null))
{
Logger.Error?.Print(LogClass.Application,
$"SDL_GetDefaultAudioInfo failed with error \"{SDL_GetError()}\"");
@@ -56,16 +53,16 @@ namespace Ryujinx.Audio.Backends.SDL2
public static bool IsSupported => IsSupportedInternal();
private static bool IsSupportedInternal()
private unsafe static bool IsSupportedInternal()
{
uint device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, Constants.TargetSampleCount, null);
SDL_AudioStream* device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, Constants.TargetSampleCount, null);
if (device != 0)
if (device != null)
{
SDL_CloseAudioDevice(device);
SDL_DestroyAudioStream(device);
}
return device != 0;
return device != null;
}
public ManualResetEvent GetUpdateRequiredEvent()
@@ -92,67 +89,68 @@ namespace Ryujinx.Audio.Backends.SDL2
if (direction != Direction.Output)
{
throw new NotImplementedException("Input direction is currently not implemented on SDL2 backend!");
throw new NotImplementedException("Input direction is currently not implemented on SDL3 backend!");
}
SDL2HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
SDL3HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
_sessions.TryAdd(session, 0);
return session;
}
internal bool Unregister(SDL2HardwareDeviceSession session)
internal bool Unregister(SDL3HardwareDeviceSession session)
{
return _sessions.TryRemove(session, out _);
}
private static SDL_AudioSpec GetSDL2Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount)
private static SDL_AudioSpec GetSDL3Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount)
{
return new SDL_AudioSpec
{
channels = (byte)requestedChannelCount,
format = GetSDL2Format(requestedSampleFormat),
format = GetSDL3Format(requestedSampleFormat),
freq = (int)requestedSampleRate,
samples = (ushort)sampleCount,
};
}
internal static ushort GetSDL2Format(SampleFormat format)
internal static SDL_AudioFormat GetSDL3Format(SampleFormat format)
{
return format switch
{
SampleFormat.PcmInt8 => AUDIO_S8,
SampleFormat.PcmInt16 => AUDIO_S16,
SampleFormat.PcmInt32 => AUDIO_S32,
SampleFormat.PcmFloat => AUDIO_F32,
SampleFormat.PcmInt8 => SDL_AudioFormat.SDL_AUDIO_S8,
SampleFormat.PcmInt16 => SDL_AudioFormat.SDL_AUDIO_S16LE,
SampleFormat.PcmInt32 => SDL_AudioFormat.SDL_AUDIO_S32LE,
SampleFormat.PcmFloat => SDL_AudioFormat.SDL_AUDIO_F32LE,
_ => throw new ArgumentException($"Unsupported sample format {format}"),
};
}
internal static uint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount, SDL_AudioCallback callback)
internal unsafe static SDL_AudioStream* OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount, SDL3HardwareDeviceSession.SDL_AudioStreamCallback callback)
{
SDL_AudioSpec desired = GetSDL2Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount, sampleCount);
SDL_AudioSpec desired = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount);
SDL_AudioSpec got = desired;
var pCallback = callback != null ? (SDL_AudioStreamCallbackPointer)Marshal.GetFunctionPointerForDelegate(callback) : null;
desired.callback = callback;
// From SDL 3 and on, SDL requires us to set this as a hint
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, $"{sampleCount}");
SDL_AudioStream* device = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &got, pCallback, 0);
uint device = SDL_OpenAudioDevice(IntPtr.Zero, 0, ref desired, out SDL_AudioSpec got, 0);
if (device == 0)
if (device == null)
{
Logger.Error?.Print(LogClass.Application, $"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
Logger.Error?.Print(LogClass.Application, $"SDL3 open audio device initialization failed with error \"{SDL_GetError()}\"");
return 0;
return null;
}
bool isValid = got.format == desired.format && got.freq == desired.freq && got.channels == desired.channels;
if (!isValid)
{
Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
SDL_CloseAudioDevice(device);
Logger.Error?.Print(LogClass.Application, "SDL3 open audio device is not valid");
SDL_DestroyAudioStream(device);
return 0;
return null;
}
return device;
@@ -164,16 +162,16 @@ namespace Ryujinx.Audio.Backends.SDL2
Dispose(true);
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing)
{
foreach (SDL2HardwareDeviceSession session in _sessions.Keys)
foreach (SDL3HardwareDeviceSession session in _sessions.Keys)
{
session.Dispose();
}
SDL2Driver.Instance.Dispose();
SDL3Driver.Instance.Dispose();
_pauseEvent.Dispose();
}
@@ -6,36 +6,40 @@ using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
using System.Threading;
using SDL;
using static SDL.SDL3;
using System.Runtime.InteropServices;
using static SDL2.SDL;
namespace Ryujinx.Audio.Backends.SDL2
namespace Ryujinx.Audio.Backends.SDL3
{
class SDL2HardwareDeviceSession : HardwareDeviceSessionOutputBase
unsafe sealed class SDL3HardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private readonly SDL2HardwareDeviceDriver _driver;
private readonly ConcurrentQueue<SDL2AudioBuffer> _queuedBuffers;
private readonly SDL3HardwareDeviceDriver _driver;
private readonly ConcurrentQueue<SDL3AudioBuffer> _queuedBuffers;
private readonly DynamicRingBuffer _ringBuffer;
private ulong _playedSampleCount;
private readonly ManualResetEvent _updateRequiredEvent;
private uint _outputStream;
private SDL_AudioStream* _outputStream;
private bool _hasSetupError;
private readonly SDL_AudioCallback _callbackDelegate;
private readonly SDL_AudioStreamCallback _callbackDelegate;
private readonly int _bytesPerFrame;
private uint _sampleCount;
private bool _started;
private float _volume;
private readonly ushort _nativeSampleFormat;
private readonly SDL_AudioFormat _nativeSampleFormat;
public SDL2HardwareDeviceSession(SDL2HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SDL_AudioStreamCallback(nint session, SDL_AudioStream* stream, int stream_count, int device_count);
public SDL3HardwareDeviceSession(SDL3HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
{
_driver = driver;
_updateRequiredEvent = _driver.GetUpdateRequiredEvent();
_queuedBuffers = new ConcurrentQueue<SDL2AudioBuffer>();
_queuedBuffers = new ConcurrentQueue<SDL3AudioBuffer>();
_ringBuffer = new DynamicRingBuffer();
_callbackDelegate = Update;
_bytesPerFrame = BackendHelper.GetSampleSize(RequestedSampleFormat) * (int)RequestedChannelCount;
_nativeSampleFormat = SDL2HardwareDeviceDriver.GetSDL2Format(RequestedSampleFormat);
_nativeSampleFormat = SDL3HardwareDeviceDriver.GetSDL3Format(RequestedSampleFormat);
_sampleCount = uint.MaxValue;
_started = false;
_volume = 1f;
@@ -44,45 +48,51 @@ namespace Ryujinx.Audio.Backends.SDL2
private void EnsureAudioStreamSetup(AudioBuffer buffer)
{
uint bufferSampleCount = (uint)GetSampleCount(buffer);
bool needAudioSetup = (_outputStream == 0 && !_hasSetupError) ||
bool needAudioSetup = (_outputStream == null && !_hasSetupError) ||
(bufferSampleCount >= Constants.TargetSampleCount && bufferSampleCount < _sampleCount);
if (needAudioSetup)
{
_sampleCount = Math.Max(Constants.TargetSampleCount, bufferSampleCount);
uint newOutputStream = SDL2HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
SDL_AudioStream* newOutputStream = SDL3HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
_hasSetupError = newOutputStream == 0;
_hasSetupError = newOutputStream == null;
if (!_hasSetupError)
{
if (_outputStream != 0)
if (_outputStream != null)
{
SDL_CloseAudioDevice(_outputStream);
SDL_DestroyAudioStream(_outputStream);
}
_outputStream = newOutputStream;
SDL_PauseAudioDevice(_outputStream, _started ? 0 : 1);
if (_started) {
SDL_ResumeAudioStreamDevice(_outputStream);
} else {
SDL_PauseAudioStreamDevice(_outputStream);
}
Logger.Info?.Print(LogClass.Audio, $"New audio stream setup with a target sample count of {_sampleCount}");
}
}
}
private unsafe void Update(IntPtr userdata, IntPtr stream, int streamLength)
private void Update(nint userdata, SDL_AudioStream* streamDevice, int additionalAmount, int totalAmmount)
{
Span<byte> streamSpan = new((void*)stream, streamLength);
using SpanOwner<byte> stream = SpanOwner<byte>.Rent(additionalAmount);
Span<byte> streamSpan = stream.Span;
int maxFrameCount = (int)GetSampleCount(streamLength);
int maxFrameCount = (int)GetSampleCount(additionalAmount);
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
int frameCount = Math.Min(bufferedFrames, maxFrameCount);
if (frameCount == 0)
{
// SDL2 left the responsibility to the user to clear the buffer.
// SDL3 left the responsibility to the user to clear the buffer.
streamSpan.Clear();
return;
@@ -94,15 +104,17 @@ namespace Ryujinx.Audio.Backends.SDL2
_ringBuffer.Read(samples, 0, samples.Length);
fixed (byte* p = samples)
{
IntPtr pStreamSrc = (IntPtr)p;
// Zero the dest buffer
streamSpan.Clear();
// Zero the dest buffer
streamSpan.Clear();
fixed (byte* pStreamDst = streamSpan) {
fixed (byte* pStreamSrc = samples)
{
// Apply volume to written data
SDL_MixAudioFormat(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, (int)(_driver.Volume * _volume * SDL_MIX_MAXVOLUME));
// Apply volume to written data
SDL_MixAudio(pStreamDst, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, _driver.Volume * _volume);
SDL_PutAudioStreamData(streamDevice, (nint)pStreamDst, additionalAmount);
}
}
ulong sampleCount = GetSampleCount(samples.Length);
@@ -111,7 +123,7 @@ namespace Ryujinx.Audio.Backends.SDL2
bool needUpdate = false;
while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL2AudioBuffer driverBuffer))
while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
{
ulong sampleStillNeeded = driverBuffer.SampleCount - Interlocked.Read(ref driverBuffer.SamplePlayed);
ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
@@ -152,9 +164,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
EnsureAudioStreamSetup(buffer);
if (_outputStream != 0)
if (_outputStream != null)
{
SDL2AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
SDL3AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
@@ -177,9 +189,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
if (!_started)
{
if (_outputStream != 0)
if (_outputStream != null)
{
SDL_PauseAudioDevice(_outputStream, 0);
SDL_ResumeAudioStreamDevice(_outputStream);
}
_started = true;
@@ -190,9 +202,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
if (_started)
{
if (_outputStream != 0)
if (_outputStream != null)
{
SDL_PauseAudioDevice(_outputStream, 1);
SDL_PauseAudioStreamDevice(_outputStream);
}
_started = false;
@@ -203,7 +215,7 @@ namespace Ryujinx.Audio.Backends.SDL2
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
{
if (!_queuedBuffers.TryPeek(out SDL2AudioBuffer driverBuffer))
if (!_queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
{
return true;
}
@@ -211,16 +223,16 @@ namespace Ryujinx.Audio.Backends.SDL2
return driverBuffer.DriverIdentifier != buffer.DataPointer;
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing && _driver.Unregister(this))
{
PrepareToClose();
Stop();
if (_outputStream != 0)
if (_outputStream != null)
{
SDL_CloseAudioDevice(_outputStream);
SDL_DestroyAudioStream(_outputStream);
}
}
}
@@ -1,5 +1,4 @@
using Ryujinx.Common.Memory;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -10,41 +9,41 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
private const string LibraryName = "libsoundio";
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void OnDeviceChangeNativeDelegate(IntPtr ctx);
public delegate void OnDeviceChangeNativeDelegate(nint ctx);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void OnBackendDisconnectedDelegate(IntPtr ctx, SoundIoError err);
public delegate void OnBackendDisconnectedDelegate(nint ctx, SoundIoError err);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void OnEventsSignalDelegate(IntPtr ctx);
public delegate void OnEventsSignalDelegate(nint ctx);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void EmitRtPrioWarningDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void JackCallbackDelegate(IntPtr msg);
public delegate void JackCallbackDelegate(nint msg);
[StructLayout(LayoutKind.Sequential)]
public struct SoundIoStruct
{
public IntPtr UserData;
public IntPtr OnDeviceChange;
public IntPtr OnBackendDisconnected;
public IntPtr OnEventsSignal;
public nint UserData;
public nint OnDeviceChange;
public nint OnBackendDisconnected;
public nint OnEventsSignal;
public SoundIoBackend CurrentBackend;
public IntPtr ApplicationName;
public IntPtr EmitRtPrioWarning;
public IntPtr JackInfoCallback;
public IntPtr JackErrorCallback;
public nint ApplicationName;
public nint EmitRtPrioWarning;
public nint JackInfoCallback;
public nint JackErrorCallback;
}
public struct SoundIoChannelLayout
{
public IntPtr Name;
public nint Name;
public int ChannelCount;
public Array24<SoundIoChannelId> Channels;
public static IntPtr GetDefault(int channelCount)
public static nint GetDefault(int channelCount)
{
return soundio_channel_layout_get_default(channelCount);
}
@@ -63,17 +62,17 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
public struct SoundIoDevice
{
public IntPtr SoundIo;
public IntPtr Id;
public IntPtr Name;
public nint SoundIo;
public nint Id;
public nint Name;
public SoundIoDeviceAim Aim;
public IntPtr Layouts;
public nint Layouts;
public int LayoutCount;
public SoundIoChannelLayout CurrentLayout;
public IntPtr Formats;
public nint Formats;
public int FormatCount;
public SoundIoFormat CurrentFormat;
public IntPtr SampleRates;
public nint SampleRates;
public int SampleRateCount;
public int SampleRateCurrent;
public double SoftwareLatencyMin;
@@ -86,17 +85,17 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
public struct SoundIoOutStream
{
public IntPtr Device;
public nint Device;
public SoundIoFormat Format;
public int SampleRate;
public SoundIoChannelLayout Layout;
public double SoftwareLatency;
public float Volume;
public IntPtr UserData;
public IntPtr WriteCallback;
public IntPtr UnderflowCallback;
public IntPtr ErrorCallback;
public IntPtr Name;
public nint UserData;
public nint WriteCallback;
public nint UnderflowCallback;
public nint ErrorCallback;
public nint Name;
public bool NonTerminalHint;
public int BytesPerFrame;
public int BytesPerSample;
@@ -105,74 +104,74 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
public struct SoundIoChannelArea
{
public IntPtr Pointer;
public nint Pointer;
public int Step;
}
[LibraryImport(LibraryName)]
internal static partial IntPtr soundio_create();
internal static partial nint soundio_create();
[LibraryImport(LibraryName)]
internal static partial SoundIoError soundio_connect(IntPtr ctx);
internal static partial SoundIoError soundio_connect(nint ctx);
[LibraryImport(LibraryName)]
internal static partial void soundio_disconnect(IntPtr ctx);
internal static partial void soundio_disconnect(nint ctx);
[LibraryImport(LibraryName)]
internal static partial void soundio_flush_events(IntPtr ctx);
internal static partial void soundio_flush_events(nint ctx);
[LibraryImport(LibraryName)]
internal static partial int soundio_output_device_count(IntPtr ctx);
internal static partial int soundio_output_device_count(nint ctx);
[LibraryImport(LibraryName)]
internal static partial int soundio_default_output_device_index(IntPtr ctx);
internal static partial int soundio_default_output_device_index(nint ctx);
[LibraryImport(LibraryName)]
internal static partial IntPtr soundio_get_output_device(IntPtr ctx, int index);
internal static partial nint soundio_get_output_device(nint ctx, int index);
[LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool soundio_device_supports_format(IntPtr devCtx, SoundIoFormat format);
internal static partial bool soundio_device_supports_format(nint devCtx, SoundIoFormat format);
[LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool soundio_device_supports_layout(IntPtr devCtx, IntPtr layout);
internal static partial bool soundio_device_supports_layout(nint devCtx, nint layout);
[LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool soundio_device_supports_sample_rate(IntPtr devCtx, int sampleRate);
internal static partial bool soundio_device_supports_sample_rate(nint devCtx, int sampleRate);
[LibraryImport(LibraryName)]
internal static partial IntPtr soundio_outstream_create(IntPtr devCtx);
internal static partial nint soundio_outstream_create(nint devCtx);
[LibraryImport(LibraryName)]
internal static partial SoundIoError soundio_outstream_open(IntPtr outStreamCtx);
internal static partial SoundIoError soundio_outstream_open(nint outStreamCtx);
[LibraryImport(LibraryName)]
internal static partial SoundIoError soundio_outstream_start(IntPtr outStreamCtx);
internal static partial SoundIoError soundio_outstream_start(nint outStreamCtx);
[LibraryImport(LibraryName)]
internal static partial SoundIoError soundio_outstream_begin_write(IntPtr outStreamCtx, IntPtr areas, IntPtr frameCount);
internal static partial SoundIoError soundio_outstream_begin_write(nint outStreamCtx, nint areas, nint frameCount);
[LibraryImport(LibraryName)]
internal static partial SoundIoError soundio_outstream_end_write(IntPtr outStreamCtx);
internal static partial SoundIoError soundio_outstream_end_write(nint outStreamCtx);
[LibraryImport(LibraryName)]
internal static partial SoundIoError soundio_outstream_pause(IntPtr devCtx, [MarshalAs(UnmanagedType.Bool)] bool pause);
internal static partial SoundIoError soundio_outstream_pause(nint devCtx, [MarshalAs(UnmanagedType.Bool)] bool pause);
[LibraryImport(LibraryName)]
internal static partial SoundIoError soundio_outstream_set_volume(IntPtr devCtx, double volume);
internal static partial SoundIoError soundio_outstream_set_volume(nint devCtx, double volume);
[LibraryImport(LibraryName)]
internal static partial void soundio_outstream_destroy(IntPtr streamCtx);
internal static partial void soundio_outstream_destroy(nint streamCtx);
[LibraryImport(LibraryName)]
internal static partial void soundio_destroy(IntPtr ctx);
internal static partial void soundio_destroy(nint ctx);
[LibraryImport(LibraryName)]
internal static partial IntPtr soundio_channel_layout_get_default(int channelCount);
internal static partial nint soundio_channel_layout_get_default(int channelCount);
[LibraryImport(LibraryName)]
internal static partial IntPtr soundio_strerror(SoundIoError err);
internal static partial nint soundio_strerror(SoundIoError err);
}
}
@@ -8,13 +8,13 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public class SoundIoContext : IDisposable
{
private IntPtr _context;
private nint _context;
private Action<SoundIoError> _onBackendDisconnect;
private OnBackendDisconnectedDelegate _onBackendDisconnectNative;
public IntPtr Context => _context;
public nint Context => _context;
internal SoundIoContext(IntPtr context)
internal SoundIoContext(nint context)
{
_context = context;
_onBackendDisconnect = null;
@@ -60,9 +60,9 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
public SoundIoDeviceContext GetOutputDevice(int index)
{
IntPtr deviceContext = soundio_get_output_device(_context, index);
nint deviceContext = soundio_get_output_device(_context, index);
if (deviceContext == IntPtr.Zero)
if (deviceContext == nint.Zero)
{
return null;
}
@@ -72,9 +72,9 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
public static SoundIoContext Create()
{
IntPtr context = soundio_create();
nint context = soundio_create();
if (context == IntPtr.Zero)
if (context == nint.Zero)
{
return null;
}
@@ -84,9 +84,9 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
protected virtual void Dispose(bool disposing)
{
IntPtr currentContext = Interlocked.Exchange(ref _context, IntPtr.Zero);
nint currentContext = Interlocked.Exchange(ref _context, nint.Zero);
if (currentContext != IntPtr.Zero)
if (currentContext != nint.Zero)
{
soundio_destroy(currentContext);
}
@@ -1,4 +1,3 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
@@ -7,11 +6,11 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public class SoundIoDeviceContext
{
private readonly IntPtr _context;
private readonly nint _context;
public IntPtr Context => _context;
public nint Context => _context;
internal SoundIoDeviceContext(IntPtr context)
internal SoundIoDeviceContext(nint context)
{
_context = context;
}
@@ -36,9 +35,9 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
public SoundIoOutStreamContext CreateOutStream()
{
IntPtr context = soundio_outstream_create(_context);
nint context = soundio_outstream_create(_context);
if (context == IntPtr.Zero)
if (context == nint.Zero)
{
return null;
}
@@ -8,19 +8,19 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
public class SoundIoOutStreamContext : IDisposable
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private unsafe delegate void WriteCallbackDelegate(IntPtr ctx, int frameCountMin, int frameCountMax);
private unsafe delegate void WriteCallbackDelegate(nint ctx, int frameCountMin, int frameCountMax);
private IntPtr _context;
private IntPtr _nameStored;
private nint _context;
private nint _nameStored;
private Action<int, int> _writeCallback;
private WriteCallbackDelegate _writeCallbackNative;
public IntPtr Context => _context;
public nint Context => _context;
internal SoundIoOutStreamContext(IntPtr context)
internal SoundIoOutStreamContext(nint context)
{
_context = context;
_nameStored = IntPtr.Zero;
_nameStored = nint.Zero;
_writeCallback = null;
_writeCallbackNative = null;
}
@@ -40,7 +40,7 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
{
var context = GetOutContext();
if (_nameStored != IntPtr.Zero && context.Name == _nameStored)
if (_nameStored != nint.Zero && context.Name == _nameStored)
{
Marshal.FreeHGlobal(_nameStored);
}
@@ -124,14 +124,14 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
public Span<SoundIoChannelArea> BeginWrite(ref int frameCount)
{
IntPtr arenas = default;
nint arenas = default;
int nativeFrameCount = frameCount;
unsafe
{
var frameCountPtr = &nativeFrameCount;
var arenasPtr = &arenas;
CheckError(soundio_outstream_begin_write(_context, (IntPtr)arenasPtr, (IntPtr)frameCountPtr));
CheckError(soundio_outstream_begin_write(_context, (nint)arenasPtr, (nint)frameCountPtr));
frameCount = *frameCountPtr;
@@ -143,10 +143,10 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
protected virtual void Dispose(bool disposing)
{
if (_context != IntPtr.Zero)
if (_context != nint.Zero)
{
soundio_outstream_destroy(_context);
_context = IntPtr.Zero;
_context = nint.Zero;
}
}
@@ -10,7 +10,7 @@ using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
namespace Ryujinx.Audio.Backends.SoundIo
{
public class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver
public sealed class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly SoundIoContext _audioContext;
private readonly SoundIoDeviceContext _audioDevice;
@@ -227,7 +227,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
}
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing)
{
@@ -11,7 +11,7 @@ using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
namespace Ryujinx.Audio.Backends.SoundIo
{
class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
sealed class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private readonly SoundIoHardwareDeviceDriver _driver;
private readonly ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
@@ -143,7 +143,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
{
for (int frame = 0; frame < frameCount; frame++)
{
((byte*)area.Pointer)[0] = srcptr[frame * bytesPerFrame];
(((byte*)area.Pointer)!)[0] = srcptr[frame * bytesPerFrame];
area.Pointer += area.Step;
}
@@ -152,7 +152,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
{
for (int frame = 0; frame < frameCount; frame++)
{
((short*)area.Pointer)[0] = ((short*)srcptr)[frame * bytesPerFrame >> 1];
(((short*)area.Pointer)!)[0] = ((short*)srcptr)[frame * bytesPerFrame >> 1];
area.Pointer += area.Step;
}
@@ -161,7 +161,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
{
for (int frame = 0; frame < frameCount; frame++)
{
((int*)area.Pointer)[0] = ((int*)srcptr)[frame * bytesPerFrame >> 2];
(((int*)area.Pointer)!)[0] = ((int*)srcptr)[frame * bytesPerFrame >> 2];
area.Pointer += area.Step;
}
@@ -190,10 +190,10 @@ namespace Ryujinx.Audio.Backends.SoundIo
for (int frame = 0; frame < frameCount; frame++)
{
// Channel 1
((byte*)area1.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 0];
(((byte*)area1.Pointer)!)[0] = srcptr[(frame * bytesPerFrame) + 0];
// Channel 2
((byte*)area2.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 1];
(((byte*)area2.Pointer)!)[0] = srcptr[(frame * bytesPerFrame) + 1];
area1.Pointer += area1.Step;
area2.Pointer += area2.Step;
@@ -204,10 +204,10 @@ namespace Ryujinx.Audio.Backends.SoundIo
for (int frame = 0; frame < frameCount; frame++)
{
// Channel 1
((short*)area1.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 0];
(((short*)area1.Pointer)!)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 0];
// Channel 2
((short*)area2.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 1];
(((short*)area2.Pointer)!)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 1];
area1.Pointer += area1.Step;
area2.Pointer += area2.Step;
@@ -218,10 +218,10 @@ namespace Ryujinx.Audio.Backends.SoundIo
for (int frame = 0; frame < frameCount; frame++)
{
// Channel 1
((int*)area1.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 0];
(((int*)area1.Pointer)!)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 0];
// Channel 2
((int*)area2.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 1];
(((int*)area2.Pointer)!)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 1];
area1.Pointer += area1.Step;
area2.Pointer += area2.Step;
@@ -260,22 +260,22 @@ namespace Ryujinx.Audio.Backends.SoundIo
for (int frame = 0; frame < frameCount; frame++)
{
// Channel 1
((byte*)area1.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 0];
(((byte*)area1.Pointer)!)[0] = srcptr[(frame * bytesPerFrame) + 0];
// Channel 2
((byte*)area2.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 1];
(((byte*)area2.Pointer)!)[0] = srcptr[(frame * bytesPerFrame) + 1];
// Channel 3
((byte*)area3.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 2];
(((byte*)area3.Pointer)!)[0] = srcptr[(frame * bytesPerFrame) + 2];
// Channel 4
((byte*)area4.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 3];
(((byte*)area4.Pointer)!)[0] = srcptr[(frame * bytesPerFrame) + 3];
// Channel 5
((byte*)area5.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 4];
(((byte*)area5.Pointer)!)[0] = srcptr[(frame * bytesPerFrame) + 4];
// Channel 6
((byte*)area6.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 5];
(((byte*)area6.Pointer)!)[0] = srcptr[(frame * bytesPerFrame) + 5];
area1.Pointer += area1.Step;
area2.Pointer += area2.Step;
@@ -290,22 +290,22 @@ namespace Ryujinx.Audio.Backends.SoundIo
for (int frame = 0; frame < frameCount; frame++)
{
// Channel 1
((short*)area1.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 0];
(((short*)area1.Pointer)!)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 0];
// Channel 2
((short*)area2.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 1];
(((short*)area2.Pointer)!)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 1];
// Channel 3
((short*)area3.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 2];
(((short*)area3.Pointer)!)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 2];
// Channel 4
((short*)area4.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 3];
(((short*)area4.Pointer)!)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 3];
// Channel 5
((short*)area5.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 4];
(((short*)area5.Pointer)!)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 4];
// Channel 6
((short*)area6.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 5];
(((short*)area6.Pointer)!)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 5];
area1.Pointer += area1.Step;
area2.Pointer += area2.Step;
@@ -320,22 +320,22 @@ namespace Ryujinx.Audio.Backends.SoundIo
for (int frame = 0; frame < frameCount; frame++)
{
// Channel 1
((int*)area1.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 0];
(((int*)area1.Pointer)!)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 0];
// Channel 2
((int*)area2.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 1];
(((int*)area2.Pointer)!)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 1];
// Channel 3
((int*)area3.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 2];
(((int*)area3.Pointer)!)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 2];
// Channel 4
((int*)area4.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 3];
(((int*)area4.Pointer)!)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 3];
// Channel 5
((int*)area5.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 4];
(((int*)area5.Pointer)!)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 4];
// Channel 6
((int*)area6.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 5];
(((int*)area6.Pointer)!)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 5];
area1.Pointer += area1.Step;
area2.Pointer += area2.Step;
@@ -428,7 +428,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
}
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing && _driver.Unregister(this))
{
@@ -58,16 +58,16 @@ namespace Ryujinx.Audio.Backends.CompatLayer
switch (realSampleFormat)
{
case SampleFormat.PcmInt8:
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(new Span<byte>(convertedSamples)), samples);
break;
case SampleFormat.PcmInt24:
PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
break;
case SampleFormat.PcmInt32:
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(new Span<byte>(convertedSamples)), samples);
break;
case SampleFormat.PcmFloat:
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(new Span<byte>(convertedSamples)), samples);
break;
default:
throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");
@@ -27,7 +27,7 @@ namespace Ryujinx.Audio.Integration
public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount)
{
data.CopyTo(MemoryMarshal.Cast<byte, short>(_buffer));
data.CopyTo(MemoryMarshal.Cast<byte, short>(new Span<byte>(_buffer)));
_session.QueueBuffer(new AudioBuffer
{
@@ -1,9 +1,11 @@
using Ryujinx.Audio.Renderer.Server;
using Ryujinx.Audio.Renderer.Server.MemoryPool;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Common
{
/// <summary>
/// Represents the input parameter for <see cref="Server.BehaviourContext"/>.
/// Represents the input parameter for <see cref="BehaviourInfo"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BehaviourParameter
@@ -21,7 +23,7 @@ namespace Ryujinx.Audio.Renderer.Common
/// <summary>
/// The flags given controlling behaviour of the audio renderer
/// </summary>
/// <remarks>See <see cref="Server.BehaviourContext.UpdateFlags(ulong)"/> and <see cref="Server.BehaviourContext.IsMemoryPoolForceMappingEnabled"/>.</remarks>
/// <remarks>See <see cref="BehaviourInfo.UpdateFlags(ulong)"/> and <see cref="BehaviourInfo.IsMemoryPoolForceMappingEnabled"/>.</remarks>
public ulong Flags;
/// <summary>
@@ -43,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Common
/// <summary>
/// Extra information given with the <see cref="ResultCode"/>
/// </summary>
/// <remarks>This is usually used to report a faulting cpu address when a <see cref="Server.MemoryPool.MemoryPoolState"/> mapping fail.</remarks>
/// <remarks>This is usually used to report a faulting cpu address when a <see cref="MemoryPoolInfo"/> mapping fail.</remarks>
public ulong ExtraErrorInfo;
}
}
@@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Common
public uint MixesSize;
public uint SinksSize;
public uint PerformanceBufferSize;
public uint Unknown24;
public uint SplitterSize;
public uint RenderInfoSize;
#pragma warning disable IDE0051, CS0169 // Remove unused field
@@ -1,4 +1,5 @@
using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using System;
@@ -11,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Common
/// </summary>
/// <remarks>This is shared between the server and audio processor.</remarks>
[StructLayout(LayoutKind.Sequential, Pack = Align)]
public struct VoiceUpdateState
public struct VoiceState
{
public const int Align = 0x10;
public const int BiquadStateOffset = 0x0;
@@ -25,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Common
/// The total amount of samples that was played.
/// </summary>
/// <remarks>This is reset to 0 when a <see cref="WaveBuffer"/> finishes playing and <see cref="WaveBuffer.IsEndOfStream"/> is set.</remarks>
/// <remarks>This is reset to 0 when looping while <see cref="Parameter.VoiceInParameter.DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
/// <remarks>This is reset to 0 when looping while <see cref="VoiceInParameter1.DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
public ulong PlayedSampleCount;
/// <summary>
@@ -1,5 +1,7 @@
using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Audio.Renderer.Parameter.Effect;
using Ryujinx.Common.Memory;
using System;
using System.Runtime.CompilerServices;
@@ -9,6 +11,112 @@ namespace Ryujinx.Audio.Renderer.Dsp
{
private const int FixedPointPrecisionForParameter = 14;
public static BiquadFilterParameter1 ToBiquadFilterParameter1(BiquadFilterParameter2 parameter)
{
BiquadFilterParameter1 result = new()
{
Enable = parameter.Enable, Numerator = new Array3<short>(), Denominator = new Array2<short>()
};
Span<short> resultNumeratorSpan = result.Numerator.AsSpan();
Span<short> resultDenominatorSpan = result.Denominator.AsSpan();
Span<float> parameterNumeratorSpan = parameter.Numerator.AsSpan();
Span<float> parameterDenominatorSpan = parameter.Denominator.AsSpan();
resultNumeratorSpan[0] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[0], FixedPointPrecisionForParameter);
resultNumeratorSpan[1] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[1], FixedPointPrecisionForParameter);
resultNumeratorSpan[2] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[2], FixedPointPrecisionForParameter);
resultDenominatorSpan[0] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[0], FixedPointPrecisionForParameter);
resultDenominatorSpan[1] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[1], FixedPointPrecisionForParameter);
return result;
}
public static BiquadFilterParameter2 ToBiquadFilterParameter2(BiquadFilterParameter1 parameter)
{
BiquadFilterParameter2 result = new()
{
Enable = parameter.Enable, Numerator = new Array3<float>(), Denominator = new Array2<float>()
};
Span<float> resultNumeratorSpan = result.Numerator.AsSpan();
Span<float> resultDenominatorSpan = result.Denominator.AsSpan();
Span<short> parameterNumeratorSpan = parameter.Numerator.AsSpan();
Span<short> parameterDenominatorSpan = parameter.Denominator.AsSpan();
resultNumeratorSpan[0] = FixedPointHelper.ToFloat(parameterNumeratorSpan[0], FixedPointPrecisionForParameter);
resultNumeratorSpan[1] = FixedPointHelper.ToFloat(parameterNumeratorSpan[1], FixedPointPrecisionForParameter);
resultNumeratorSpan[2] = FixedPointHelper.ToFloat(parameterNumeratorSpan[2], FixedPointPrecisionForParameter);
resultDenominatorSpan[0] = FixedPointHelper.ToFloat(parameterDenominatorSpan[0], FixedPointPrecisionForParameter);
resultDenominatorSpan[1] = FixedPointHelper.ToFloat(parameterDenominatorSpan[1], FixedPointPrecisionForParameter);
return result;
}
public static BiquadFilterEffectParameter1 ToBiquadFilterEffectParameter1(BiquadFilterEffectParameter2 parameter)
{
BiquadFilterEffectParameter1 result = new()
{
Input = parameter.Input,
Output = parameter.Output,
Numerator = new Array3<short>(),
Denominator = new Array2<short>(),
ChannelCount = parameter.ChannelCount,
Status = parameter.Status,
};
Span<short> resultNumeratorSpan = result.Numerator.AsSpan();
Span<short> resultDenominatorSpan = result.Denominator.AsSpan();
Span<float> parameterNumeratorSpan = parameter.Numerator.AsSpan();
Span<float> parameterDenominatorSpan = parameter.Denominator.AsSpan();
resultNumeratorSpan[0] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[0], FixedPointPrecisionForParameter);
resultNumeratorSpan[1] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[1], FixedPointPrecisionForParameter);
resultNumeratorSpan[2] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[2], FixedPointPrecisionForParameter);
resultDenominatorSpan[0] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[0], FixedPointPrecisionForParameter);
resultDenominatorSpan[1] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[1], FixedPointPrecisionForParameter);
return result;
}
public static BiquadFilterEffectParameter2 ToBiquadFilterEffectParameter2(BiquadFilterEffectParameter1 parameter)
{
BiquadFilterEffectParameter2 result = new()
{
Input = parameter.Input,
Output = parameter.Output,
Numerator = new Array3<float>(),
Denominator = new Array2<float>(),
ChannelCount = parameter.ChannelCount,
Status = parameter.Status,
};
Span<float> resultNumeratorSpan = result.Numerator.AsSpan();
Span<float> resultDenominatorSpan = result.Denominator.AsSpan();
Span<short> parameterNumeratorSpan = parameter.Numerator.AsSpan();
Span<short> parameterDenominatorSpan = parameter.Denominator.AsSpan();
resultNumeratorSpan[0] = FixedPointHelper.ToFloat(parameterNumeratorSpan[0], FixedPointPrecisionForParameter);
resultNumeratorSpan[1] = FixedPointHelper.ToFloat(parameterNumeratorSpan[1], FixedPointPrecisionForParameter);
resultNumeratorSpan[2] = FixedPointHelper.ToFloat(parameterNumeratorSpan[2], FixedPointPrecisionForParameter);
resultDenominatorSpan[0] = FixedPointHelper.ToFloat(parameterDenominatorSpan[0], FixedPointPrecisionForParameter);
resultDenominatorSpan[1] = FixedPointHelper.ToFloat(parameterDenominatorSpan[1], FixedPointPrecisionForParameter);
return result;
}
/// <summary>
/// Apply a single biquad filter.
/// </summary>
@@ -20,21 +128,21 @@ namespace Ryujinx.Audio.Renderer.Dsp
/// <param name="sampleCount">The count of samples to process</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ProcessBiquadFilter(
ref BiquadFilterParameter parameter,
ref BiquadFilterParameter2 parameter,
ref BiquadFilterState state,
Span<float> outputBuffer,
ReadOnlySpan<float> inputBuffer,
uint sampleCount)
{
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
Span<float> numeratorSpan = parameter.Numerator.AsSpan();
Span<float> denominatorSpan = parameter.Denominator.AsSpan();
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
float a0 = numeratorSpan[0];
float a1 = numeratorSpan[1];
float a2 = numeratorSpan[2];
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
float b1 = denominatorSpan[0];
float b2 = denominatorSpan[1];
for (int i = 0; i < sampleCount; i++)
{
@@ -60,22 +168,22 @@ namespace Ryujinx.Audio.Renderer.Dsp
/// <param name="volume">Mix volume</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ProcessBiquadFilterAndMix(
ref BiquadFilterParameter parameter,
ref BiquadFilterParameter2 parameter,
ref BiquadFilterState state,
Span<float> outputBuffer,
ReadOnlySpan<float> inputBuffer,
uint sampleCount,
float volume)
{
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
Span<float> numeratorSpan = parameter.Numerator.AsSpan();
Span<float> denominatorSpan = parameter.Denominator.AsSpan();
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
float a0 = numeratorSpan[0];
float a1 = numeratorSpan[1];
float a2 = numeratorSpan[2];
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
float b1 = denominatorSpan[0];
float b2 = denominatorSpan[1];
for (int i = 0; i < sampleCount; i++)
{
@@ -105,7 +213,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
/// <returns>Last filtered sample value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float ProcessBiquadFilterAndMixRamp(
ref BiquadFilterParameter parameter,
ref BiquadFilterParameter2 parameter,
ref BiquadFilterState state,
Span<float> outputBuffer,
ReadOnlySpan<float> inputBuffer,
@@ -113,15 +221,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
float volume,
float ramp)
{
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
Span<float> numeratorSpan = parameter.Numerator.AsSpan();
Span<float> denominatorSpan = parameter.Denominator.AsSpan();
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
float a0 = numeratorSpan[0];
float a1 = numeratorSpan[1];
float a2 = numeratorSpan[2];
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
float b1 = denominatorSpan[0];
float b2 = denominatorSpan[1];
float mixState = 0f;
@@ -155,7 +263,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
/// <param name="sampleCount">The count of samples to process</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ProcessBiquadFilter(
ReadOnlySpan<BiquadFilterParameter> parameters,
ReadOnlySpan<BiquadFilterParameter2> parameters,
Span<BiquadFilterState> states,
Span<float> outputBuffer,
ReadOnlySpan<float> inputBuffer,
@@ -163,19 +271,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
{
for (int stageIndex = 0; stageIndex < parameters.Length; stageIndex++)
{
BiquadFilterParameter parameter = parameters[stageIndex];
BiquadFilterParameter2 parameter = parameters[stageIndex];
ref BiquadFilterState state = ref states[stageIndex];
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
Span<float> numeratorSpan = parameter.Numerator.AsSpan();
Span<float> denominatorSpan = parameter.Denominator.AsSpan();
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
float a0 = numeratorSpan[0];
float a1 = numeratorSpan[1];
float a2 = numeratorSpan[2];
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
float b1 = denominatorSpan[0];
float b2 = denominatorSpan[1];
for (int i = 0; i < sampleCount; i++)
{
@@ -204,8 +312,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
/// <param name="volume">Mix volume</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ProcessDoubleBiquadFilterAndMix(
ref BiquadFilterParameter parameter0,
ref BiquadFilterParameter parameter1,
ref BiquadFilterParameter2 parameter0,
ref BiquadFilterParameter2 parameter1,
ref BiquadFilterState state0,
ref BiquadFilterState state1,
Span<float> outputBuffer,
@@ -213,25 +321,25 @@ namespace Ryujinx.Audio.Renderer.Dsp
uint sampleCount,
float volume)
{
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
Span<float> numerator0Span = parameter0.Numerator.AsSpan();
Span<float> numerator1Span = parameter1.Numerator.AsSpan();
Span<float> denominator0Span = parameter0.Denominator.AsSpan();
Span<float> denominator1Span = parameter1.Denominator.AsSpan();
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
float a00 = numerator0Span[0];
float a10 = numerator0Span[1];
float a20 = numerator0Span[2];
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
float b10 = denominator0Span[0];
float b20 = denominator0Span[1];
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
float a01 = numerator1Span[0];
float a11 = numerator1Span[1];
float a21 = numerator1Span[2];
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
float b11 = denominator1Span[0];
float b21 = denominator1Span[1];
for (int i = 0; i < sampleCount; i++)
{
@@ -269,8 +377,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
/// <returns>Last filtered sample value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float ProcessDoubleBiquadFilterAndMixRamp(
ref BiquadFilterParameter parameter0,
ref BiquadFilterParameter parameter1,
ref BiquadFilterParameter2 parameter0,
ref BiquadFilterParameter2 parameter1,
ref BiquadFilterState state0,
ref BiquadFilterState state1,
Span<float> outputBuffer,
@@ -279,24 +387,24 @@ namespace Ryujinx.Audio.Renderer.Dsp
float volume,
float ramp)
{
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
Span<float> numerator0Span = parameter0.Numerator.AsSpan();
Span<float> numerator1Span = parameter1.Numerator.AsSpan();
Span<float> denominator0Span = parameter0.Denominator.AsSpan();
Span<float> denominator1Span = parameter1.Denominator.AsSpan();
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
float a00 = numerator0Span[0];
float a10 = numerator0Span[1];
float a20 = numerator0Span[2];
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
float b10 = denominator0Span[0];
float b20 = denominator0Span[1];
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
float a01 = numerator1Span[0];
float a11 = numerator1Span[1];
float a21 = numerator1Span[2];
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
float b11 = denominator1Span[0];
float b21 = denominator1Span[1];
float mixState = 0f;
@@ -2,7 +2,7 @@ using Ryujinx.Audio.Common;
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Server.Voice;
using System;
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
using Ryujinx.Audio.Renderer.Parameter;
using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer;
namespace Ryujinx.Audio.Renderer.Dsp.Command
@@ -11,38 +11,41 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }
public ushort OutputBufferIndex { get; private set; }
public uint SampleRate { get; private set; }
public float Pitch { get; }
public float Pitch { get; private set; }
public WaveBuffer[] WaveBuffers { get; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public ulong AdpcmParameter { get; }
public ulong AdpcmParameterSize { get; }
public ulong AdpcmParameter { get; private set; }
public ulong AdpcmParameterSize { get; private set; }
public DecodingBehaviour DecodingBehaviour { get; }
public DecodingBehaviour DecodingBehaviour { get; private set; }
public AdpcmDataSourceCommandVersion1(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, int nodeId)
public AdpcmDataSourceCommandVersion1()
{
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
}
public AdpcmDataSourceCommandVersion1 Initialize(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, int nodeId)
{
Enabled = true;
NodeId = nodeId;
OutputBufferIndex = outputBufferIndex;
SampleRate = serverState.SampleRate;
Pitch = serverState.Pitch;
SampleRate = serverInfo.SampleRate;
Pitch = serverInfo.Pitch;
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverInfo.WaveBuffers.AsSpan();
for (int i = 0; i < WaveBuffers.Length; i++)
{
@@ -51,10 +54,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
}
AdpcmParameter = serverState.DataSourceStateAddressInfo.GetReference(true);
AdpcmParameterSize = serverState.DataSourceStateAddressInfo.Size;
AdpcmParameter = serverInfo.DataSourceStateAddressInfo.GetReference(true);
AdpcmParameterSize = serverInfo.DataSourceStateAddressInfo.Size;
State = state;
DecodingBehaviour = serverState.DecodingBehaviour;
DecodingBehaviour = serverInfo.DecodingBehaviour;
return this;
}
public void Process(CommandList context)
@@ -12,26 +12,26 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.AuxiliaryBuffer;
public uint EstimatedProcessingTime { get; set; }
public uint InputBufferIndex { get; }
public uint OutputBufferIndex { get; }
public uint InputBufferIndex { get; private set; }
public uint OutputBufferIndex { get; private set; }
public AuxiliaryBufferAddresses BufferInfo { get; }
public AuxiliaryBufferAddresses BufferInfo { get; private set; }
public CpuAddress InputBuffer { get; }
public CpuAddress OutputBuffer { get; }
public uint CountMax { get; }
public uint UpdateCount { get; }
public uint WriteOffset { get; }
public CpuAddress InputBuffer { get; private set; }
public CpuAddress OutputBuffer { get; private set; }
public uint CountMax { get; private set; }
public uint UpdateCount { get; private set; }
public uint WriteOffset { get; private set; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
public AuxiliaryBufferCommand(
public AuxiliaryBufferCommand Initialize(
uint bufferOffset,
byte inputBufferOffset,
byte outputBufferOffset,
@@ -55,6 +55,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
UpdateCount = updateCount;
WriteOffset = writeOffset;
IsEffectEnabled = isEnabled;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -9,39 +9,39 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.BiquadFilterAndMix;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
private BiquadFilterParameter _parameter;
private BiquadFilterParameter2 _parameter;
public Memory<BiquadFilterState> BiquadFilterState { get; }
public Memory<BiquadFilterState> PreviousBiquadFilterState { get; }
public Memory<BiquadFilterState> BiquadFilterState { get; private set; }
public Memory<BiquadFilterState> PreviousBiquadFilterState { get; private set; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public int LastSampleIndex { get; }
public int LastSampleIndex { get; private set; }
public float Volume0 { get; }
public float Volume1 { get; }
public float Volume0 { get; private set; }
public float Volume1 { get; private set; }
public bool NeedInitialization { get; }
public bool HasVolumeRamp { get; }
public bool IsFirstMixBuffer { get; }
public bool NeedInitialization { get; private set; }
public bool HasVolumeRamp { get; private set; }
public bool IsFirstMixBuffer { get; private set; }
public BiquadFilterAndMixCommand(
public BiquadFilterAndMixCommand Initialize(
float volume0,
float volume1,
uint inputBufferIndex,
uint outputBufferIndex,
int lastSampleIndex,
Memory<VoiceUpdateState> state,
ref BiquadFilterParameter filter,
Memory<VoiceState> state,
ref BiquadFilterParameter2 filter,
Memory<BiquadFilterState> biquadFilterState,
Memory<BiquadFilterState> previousBiquadFilterState,
bool needInitialization,
@@ -68,6 +68,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
NeedInitialization = needInitialization;
HasVolumeRamp = hasVolumeRamp;
IsFirstMixBuffer = isFirstMixBuffer;
return this;
}
public void Process(CommandList context)
@@ -8,22 +8,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.BiquadFilter;
public uint EstimatedProcessingTime { get; set; }
public Memory<BiquadFilterState> BiquadFilterState { get; }
public int InputBufferIndex { get; }
public int OutputBufferIndex { get; }
public bool NeedInitialization { get; }
public Memory<BiquadFilterState> BiquadFilterState { get; private set; }
public int InputBufferIndex { get; private set; }
public int OutputBufferIndex { get; private set; }
public bool NeedInitialization { get; private set; }
private BiquadFilterParameter _parameter;
private BiquadFilterParameter2 _parameter;
public BiquadFilterCommand(
public BiquadFilterCommand Initialize(
int baseIndex,
ref BiquadFilterParameter filter,
ref BiquadFilterParameter2 filter,
Memory<BiquadFilterState> biquadFilterStateMemory,
int inputBufferOffset,
int outputBufferOffset,
@@ -38,6 +38,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
Enabled = true;
NodeId = nodeId;
return this;
}
public void Process(CommandList context)
@@ -12,25 +12,25 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.CaptureBuffer;
public uint EstimatedProcessingTime { get; set; }
public uint InputBufferIndex { get; }
public uint InputBufferIndex { get; private set; }
public ulong CpuBufferInfoAddress { get; }
public ulong DspBufferInfoAddress { get; }
public ulong CpuBufferInfoAddress { get; private set; }
public ulong DspBufferInfoAddress { get; private set; }
public CpuAddress OutputBuffer { get; }
public uint CountMax { get; }
public uint UpdateCount { get; }
public uint WriteOffset { get; }
public CpuAddress OutputBuffer { get; private set; }
public uint CountMax { get; private set; }
public uint UpdateCount { get; private set; }
public uint WriteOffset { get; private set; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
public CaptureBufferCommand(uint bufferOffset, byte inputBufferOffset, ulong sendBufferInfo, bool isEnabled,
public CaptureBufferCommand Initialize(uint bufferOffset, byte inputBufferOffset, ulong sendBufferInfo, bool isEnabled,
uint countMax, CpuAddress outputBuffer, uint updateCount, uint writeOffset, int nodeId)
{
Enabled = true;
@@ -43,6 +43,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
UpdateCount = updateCount;
WriteOffset = writeOffset;
IsEffectEnabled = isEnabled;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -9,25 +9,29 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.CircularBufferSink;
public uint EstimatedProcessingTime { get; set; }
public ushort[] Input { get; }
public uint InputCount { get; }
public uint InputCount { get; private set; }
public ulong CircularBuffer { get; }
public ulong CircularBufferSize { get; }
public ulong CurrentOffset { get; }
public ulong CircularBuffer { get; private set; }
public ulong CircularBufferSize { get; private set; }
public ulong CurrentOffset { get; private set; }
public CircularBufferSinkCommand(uint bufferOffset, ref CircularBufferParameter parameter, ref AddressInfo circularBufferAddressInfo, uint currentOffset, int nodeId)
public CircularBufferSinkCommand()
{
Input = new ushort[Constants.ChannelCountMax];
}
public CircularBufferSinkCommand Initialize(uint bufferOffset, ref CircularBufferParameter parameter, ref AddressInfo circularBufferAddressInfo, uint currentOffset, int nodeId)
{
Enabled = true;
NodeId = nodeId;
Input = new ushort[Constants.ChannelCountMax];
InputCount = parameter.InputCount;
Span<byte> inputSpan = parameter.Input.AsSpan();
@@ -42,6 +46,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
CurrentOffset = currentOffset;
Debug.Assert(CircularBuffer != 0);
return this;
}
public void Process(CommandList context)
@@ -4,16 +4,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.ClearMixBuffer;
public uint EstimatedProcessingTime { get; set; }
public ClearMixBufferCommand(int nodeId)
public ClearMixBufferCommand Initialize(int nodeId)
{
Enabled = true;
NodeId = nodeId;
return this;
}
public void Process(CommandList context)
@@ -20,6 +20,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public Memory<float> Buffers { get; }
public uint BufferCount { get; }
private readonly static ObjectPool<List<ICommand>> CommandsListPool = new(() => new List<ICommand>(256));
public List<ICommand> Commands { get; }
public IVirtualMemoryManager MemoryManager { get; }
@@ -46,7 +47,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
SampleRate = sampleRate;
BufferCount = mixBufferCount + voiceChannelCountMax;
Buffers = mixBuffer;
Commands = [];
Commands = CommandsListPool.Allocate();
MemoryManager = memoryManager;
_buffersEntryCount = Buffers.Length;
@@ -64,11 +65,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe IntPtr GetBufferPointer(int index)
public unsafe nint GetBufferPointer(int index)
{
if (index >= 0 && index < _buffersEntryCount)
{
return (IntPtr)((float*)_buffersMemoryHandle.Pointer + index * _sampleCount);
return (nint)((float*)_buffersMemoryHandle.Pointer + index * _sampleCount);
}
throw new ArgumentOutOfRangeException(nameof(index), index, null);
@@ -129,7 +130,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
startTime = PerformanceCounter.ElapsedNanoseconds;
}
command.Process(this);
if (shouldMeter)
@@ -142,6 +143,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
}
}
CommandBuffer.ReleaseCommand(command);
}
EndTime = (ulong)PerformanceCounter.ElapsedNanoseconds;
@@ -149,6 +152,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public void Dispose()
{
Commands.Clear();
CommandsListPool.Release(Commands);
GC.SuppressFinalize(this);
_buffersMemoryHandle.Dispose();
}
@@ -12,6 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
Volume,
VolumeRamp,
BiquadFilter,
BiquadFilterFloatCoeff, // new
Mix,
MixRamp,
MixRampGrouped,
@@ -31,9 +32,17 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
LimiterVersion1,
LimiterVersion2,
MultiTapBiquadFilter,
MultiTapBiquadFilterFloatCoeff, // new
CaptureBuffer,
Compressor,
BiquadFilterAndMix,
BiquadFilterAndMixFloatCoeff, // new
MultiTapBiquadFilterAndMix,
MultiTapBiquadFilterAndMixFloatCoef, // new
AuxiliaryBufferGrouped, // new
FillMixBuffer, // new
BiquadFilterCrossFade, // new
MultiTapBiquadFilterCrossFade, // new
FillBuffer, // new
}
}
@@ -15,22 +15,28 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Compressor;
public uint EstimatedProcessingTime { get; set; }
public CompressorParameter Parameter => _parameter;
public Memory<CompressorState> State { get; }
public Memory<EffectResultState> ResultState { get; }
public Memory<CompressorState> State { get; private set; }
public Memory<EffectResultState> ResultState { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private CompressorParameter _parameter;
public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> resultState, bool isEnabled, int nodeId)
public CompressorCommand()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public CompressorCommand Initialize(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> resultState, bool isEnabled, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -39,9 +45,6 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
ResultState = resultState;
IsEffectEnabled = isEnabled;
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
Span<byte> inputSpan = _parameter.Input.AsSpan();
Span<byte> outputSpan = _parameter.Output.AsSpan();
@@ -51,6 +54,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
}
return this;
}
public void Process(CommandList context)
@@ -85,8 +90,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
statistics.Reset(_parameter.ChannelCount);
}
Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
Span<nint> inputBuffers = stackalloc nint[_parameter.ChannelCount];
Span<nint> outputBuffers = stackalloc nint[_parameter.ChannelCount];
Span<float> channelInput = stackalloc float[_parameter.ChannelCount];
ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage;
float unknown4 = state.Unknown4;
@@ -4,22 +4,24 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.CopyMixBuffer;
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }
public ushort InputBufferIndex { get; private set; }
public ushort OutputBufferIndex { get; private set; }
public CopyMixBufferCommand(uint inputBufferIndex, uint outputBufferIndex, int nodeId)
public CopyMixBufferCommand Initialize(uint inputBufferIndex, uint outputBufferIndex, int nodeId)
{
Enabled = true;
NodeId = nodeId;
InputBufferIndex = (ushort)inputBufferIndex;
OutputBufferIndex = (ushort)outputBufferIndex;
return this;
}
public void Process(CommandList context)
@@ -2,7 +2,7 @@ using Ryujinx.Audio.Common;
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Server.Voice;
using System;
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
using Ryujinx.Audio.Renderer.Parameter;
using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer;
namespace Ryujinx.Audio.Renderer.Dsp.Command
@@ -11,51 +11,54 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType { get; }
public CommandType CommandType { get; private set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }
public ushort OutputBufferIndex { get; private set; }
public uint SampleRate { get; private set; }
public float Pitch { get; }
public float Pitch { get; private set; }
public WaveBuffer[] WaveBuffers { get; }
public Memory<VoiceUpdateState> State { get; }
public Memory<VoiceState> State { get; private set; }
public ulong ExtraParameter { get; }
public ulong ExtraParameterSize { get; }
public ulong ExtraParameter { get; private set; }
public ulong ExtraParameterSize { get; private set; }
public uint ChannelIndex { get; }
public uint ChannelIndex { get; private set; }
public uint ChannelCount { get; }
public uint ChannelCount { get; private set; }
public DecodingBehaviour DecodingBehaviour { get; }
public DecodingBehaviour DecodingBehaviour { get; private set; }
public SampleFormat SampleFormat { get; }
public SampleFormat SampleFormat { get; private set; }
public SampleRateConversionQuality SrcQuality { get; }
public SampleRateConversionQuality SrcQuality { get; private set; }
public DataSourceVersion2Command(ref VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
public DataSourceVersion2Command()
{
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
}
public DataSourceVersion2Command Initialize(ref VoiceInfo serverInfo, Memory<VoiceState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId)
{
Enabled = true;
NodeId = nodeId;
ChannelIndex = channelIndex;
ChannelCount = serverState.ChannelsCount;
SampleFormat = serverState.SampleFormat;
SrcQuality = serverState.SrcQuality;
ChannelCount = serverInfo.ChannelsCount;
SampleFormat = serverInfo.SampleFormat;
SrcQuality = serverInfo.SrcQuality;
CommandType = GetCommandTypeBySampleFormat(SampleFormat);
OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex);
SampleRate = serverState.SampleRate;
Pitch = serverState.Pitch;
SampleRate = serverInfo.SampleRate;
Pitch = serverInfo.Pitch;
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverInfo.WaveBuffers.AsSpan();
for (int i = 0; i < WaveBuffers.Length; i++)
{
@@ -66,12 +69,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (SampleFormat == SampleFormat.Adpcm)
{
ExtraParameter = serverState.DataSourceStateAddressInfo.GetReference(true);
ExtraParameterSize = serverState.DataSourceStateAddressInfo.Size;
ExtraParameter = serverInfo.DataSourceStateAddressInfo.GetReference(true);
ExtraParameterSize = serverInfo.DataSourceStateAddressInfo.Size;
}
State = state;
DecodingBehaviour = serverState.DecodingBehaviour;
DecodingBehaviour = serverInfo.DecodingBehaviour;
return this;
}
private static CommandType GetCommandTypeBySampleFormat(SampleFormat sampleFormat)
@@ -13,24 +13,30 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.Delay;
public uint EstimatedProcessingTime { get; set; }
public DelayParameter Parameter => _parameter;
public Memory<DelayState> State { get; }
public ulong WorkBuffer { get; }
public Memory<DelayState> State { get; private set; }
public ulong WorkBuffer { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private DelayParameter _parameter;
private const int FixedPointPrecision = 14;
public DelayCommand(uint bufferOffset, DelayParameter parameter, Memory<DelayState> state, bool isEnabled, ulong workBuffer, int nodeId, bool newEffectChannelMappingSupported)
public DelayCommand()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public DelayCommand Initialize(uint bufferOffset, DelayParameter parameter, Memory<DelayState> state, bool isEnabled, ulong workBuffer, int nodeId, bool newEffectChannelMappingSupported)
{
Enabled = true;
NodeId = nodeId;
@@ -39,9 +45,6 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
WorkBuffer = workBuffer;
IsEffectEnabled = isEnabled;
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
Span<byte> inputSpan = Parameter.Input.AsSpan();
Span<byte> outputSpan = Parameter.Output.AsSpan();
@@ -54,6 +57,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices, Parameter.ChannelCount);
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
@@ -80,7 +85,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private unsafe void ProcessDelayStereo(ref DelayState state, Span<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
private unsafe void ProcessDelayStereo(ref DelayState state, Span<nint> outputBuffers, ReadOnlySpan<nint> inputBuffers, uint sampleCount)
{
const ushort ChannelCount = 2;
@@ -117,7 +122,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private unsafe void ProcessDelayQuadraphonic(ref DelayState state, Span<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
private unsafe void ProcessDelayQuadraphonic(ref DelayState state, Span<nint> outputBuffers, ReadOnlySpan<nint> inputBuffers, uint sampleCount)
{
const ushort ChannelCount = 4;
@@ -163,7 +168,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private unsafe void ProcessDelaySurround(ref DelayState state, Span<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
private unsafe void ProcessDelaySurround(ref DelayState state, Span<nint> outputBuffers, ReadOnlySpan<nint> inputBuffers, uint sampleCount)
{
const ushort ChannelCount = 6;
@@ -222,8 +227,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled && Parameter.IsChannelCountValid())
{
Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
Span<nint> inputBuffers = stackalloc nint[Parameter.ChannelCount];
Span<nint> outputBuffers = stackalloc nint[Parameter.ChannelCount];
for (int i = 0; i < Parameter.ChannelCount; i++)
{
@@ -7,21 +7,21 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.DepopForMixBuffers;
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferOffset { get; }
public uint MixBufferOffset { get; private set; }
public uint MixBufferCount { get; }
public uint MixBufferCount { get; private set; }
public float Decay { get; }
public float Decay { get; private set; }
public Memory<float> DepopBuffer { get; }
public Memory<float> DepopBuffer { get; private set; }
public DepopForMixBuffersCommand(Memory<float> depopBuffer, uint bufferOffset, uint mixBufferCount, int nodeId, uint sampleRate)
public DepopForMixBuffersCommand Initialize(Memory<float> depopBuffer, uint bufferOffset, uint mixBufferCount, int nodeId, uint sampleRate)
{
Enabled = true;
NodeId = nodeId;
@@ -37,6 +37,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
Decay = 0.943695f;
}
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -7,27 +7,30 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.DepopPrepare;
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferCount { get; }
public uint MixBufferCount { get; private set; }
public ushort[] OutputBufferIndices { get; }
public Memory<VoiceUpdateState> State { get; }
public Memory<float> DepopBuffer { get; }
public Memory<VoiceState> State { get; private set; }
public Memory<float> DepopBuffer { get; private set; }
public DepopPrepareCommand(Memory<VoiceUpdateState> state, Memory<float> depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled)
public DepopPrepareCommand()
{
OutputBufferIndices = new ushort[Constants.MixBufferCountMax];
}
public DepopPrepareCommand Initialize(Memory<VoiceState> state, Memory<float> depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled)
{
Enabled = enabled;
NodeId = nodeId;
MixBufferCount = mixBufferCount;
OutputBufferIndices = new ushort[Constants.MixBufferCountMax];
for (int i = 0; i < Constants.MixBufferCountMax; i++)
{
OutputBufferIndices[i] = (ushort)(bufferOffset + i);
@@ -35,11 +38,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
State = state;
DepopBuffer = depopBuffer;
return this;
}
public void Process(CommandList context)
{
ref VoiceUpdateState state = ref State.Span[0];
ref VoiceState state = ref State.Span[0];
Span<float> depopBuffer = DepopBuffer.Span;
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
@@ -1,8 +1,8 @@
using Ryujinx.Audio.Integration;
using Ryujinx.Audio.Renderer.Server.Sink;
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Text;
namespace Ryujinx.Audio.Renderer.Dsp.Command
{
@@ -10,27 +10,29 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.DeviceSink;
public uint EstimatedProcessingTime { get; set; }
public string DeviceName { get; }
public string DeviceName { get; private set; }
public int SessionId { get; }
public int SessionId { get; private set; }
public uint InputCount { get; }
public ushort[] InputBufferIndices { get; }
public uint InputCount { get; private set; }
public ushort[] InputBufferIndices { get; private set; }
public Memory<float> Buffers { get; }
public Memory<float> Buffers { get; private set; }
public DeviceSinkCommand(uint bufferOffset, DeviceSink sink, int sessionId, Memory<float> buffers, int nodeId)
public DeviceSinkCommand Initialize(uint bufferOffset, DeviceSink sink, int sessionId, Memory<float> buffers, int nodeId)
{
Enabled = true;
NodeId = nodeId;
DeviceName = Encoding.ASCII.GetString(sink.Parameter.DeviceName).TrimEnd('\0');
// Unused and wasting time and memory, re-add if needed
// DeviceName = Encoding.ASCII.GetString(sink.Parameter.DeviceName).TrimEnd('\0');
SessionId = sessionId;
InputCount = sink.Parameter.InputCount;
InputBufferIndices = new ushort[InputCount];
@@ -42,14 +44,16 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
}
if (sink.UpsamplerState != null)
if (sink.UpsamplerInfo != null)
{
Buffers = sink.UpsamplerState.OutputBuffer;
Buffers = sink.UpsamplerInfo.OutputBuffer;
}
else
{
Buffers = buffers;
}
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -81,7 +85,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
inputCount = bufferCount;
}
short[] outputBuffer = new short[inputCount * SampleCount];
short[] outputBuffer = ArrayPool<short>.Shared.Rent((int)inputCount * SampleCount);
Array.Fill(outputBuffer, (short)0, 0, (int)inputCount * SampleCount);
for (int i = 0; i < bufferCount; i++)
{
@@ -93,7 +98,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
}
device.AppendBuffer(outputBuffer, inputCount);
device.AppendBuffer(outputBuffer.AsSpan(..((int)inputCount * SampleCount)), inputCount);
ArrayPool<short>.Shared.Return(outputBuffer);
}
else
{
@@ -7,7 +7,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
@@ -16,16 +16,19 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public ushort[] InputBufferIndices { get; }
public ushort[] OutputBufferIndices { get; }
public float[] Coefficients { get; }
public float[] Coefficients { get; private set; }
public DownMixSurroundToStereoCommand(uint bufferOffset, Span<byte> inputBufferOffset, Span<byte> outputBufferOffset, float[] downMixParameter, int nodeId)
public DownMixSurroundToStereoCommand()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public DownMixSurroundToStereoCommand Initialize(uint bufferOffset, Span<byte> inputBufferOffset, Span<byte> outputBufferOffset, float[] downMixParameter, int nodeId)
{
Enabled = true;
NodeId = nodeId;
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
for (int i = 0; i < Constants.VoiceChannelCountMax; i++)
{
InputBufferIndices[i] = (ushort)(bufferOffset + inputBufferOffset[i]);
@@ -33,6 +36,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
Coefficients = downMixParameter;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -0,0 +1,68 @@
using Ryujinx.Audio.Renderer.Server.Splitter;
using System.Runtime.CompilerServices;
namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public class FillBufferCommand : ICommand
{
public bool Enabled { get; set; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.FillBuffer;
public uint EstimatedProcessingTime { get; set; }
public SplitterDestinationVersion1 Destination1 { get; private set; }
public SplitterDestinationVersion2 Destination2 { get; private set; }
public bool IsV2 { get; private set; }
public int Length { get; private set; }
public float Value { get; private set; }
public FillBufferCommand Initialize(SplitterDestination destination, int length, float value, int nodeId)
{
Enabled = true;
NodeId = nodeId;
if (Unsafe.IsNullRef(ref destination.GetV2RefOrNull()))
{
Destination1 = destination.GetV1RefOrNull();
IsV2 = false;
}
else
{
Destination2 = destination.GetV2RefOrNull();
IsV2 = true;
}
Length = length;
Value = value;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessFillBuffer()
{
if (IsV2)
{
for (int i = 0; i < Length; i++)
{
Destination2.PreviousMixBufferVolume[i] = Value;
}
}
else
{
for (int i = 0; i < Length; i++)
{
Destination1.PreviousMixBufferVolume[i] = Value;
}
}
}
public void Process(CommandList context)
{
ProcessFillBuffer();
}
}
}
@@ -10,22 +10,28 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{
public bool Enabled { get; set; }
public int NodeId { get; }
public int NodeId { get; private set; }
public CommandType CommandType => CommandType.LimiterVersion1;
public uint EstimatedProcessingTime { get; set; }
public LimiterParameter Parameter => _parameter;
public Memory<LimiterState> State { get; }
public ulong WorkBuffer { get; }
public Memory<LimiterState> State { get; private set; }
public ulong WorkBuffer { get; private set; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
public bool IsEffectEnabled { get; private set; }
private LimiterParameter _parameter;
public LimiterCommandVersion1(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, bool isEnabled, ulong workBuffer, int nodeId)
public LimiterCommandVersion1()
{
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
}
public LimiterCommandVersion1 Initialize(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, bool isEnabled, ulong workBuffer, int nodeId)
{
Enabled = true;
NodeId = nodeId;
@@ -35,9 +41,6 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
IsEffectEnabled = isEnabled;
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
Span<byte> inputSpan = _parameter.Input.AsSpan();
Span<byte> outputSpan = _parameter.Output.AsSpan();
@@ -46,6 +49,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
}
return this;
}
public void Process(CommandList context)
@@ -73,8 +78,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled && _parameter.IsChannelCountValid())
{
Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
Span<nint> inputBuffers = stackalloc nint[_parameter.ChannelCount];
Span<nint> outputBuffers = stackalloc nint[_parameter.ChannelCount];
for (int i = 0; i < _parameter.ChannelCount; i++)
{

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