Compare commits

...

44 Commits

Author SHA1 Message Date
37d27c4c99 Some minor cleanups and optimizations (#4174)
* Replace Array.Clear(x, 0, x.Length) with Array.Clear(x)

* Use DateTime.UnixEpoch field

* Replace SHA256.ComputeHash calls with static SHA256.HashData call

More performant and avoids the need to initialize a SHA256 instance.
2022-12-24 14:30:39 -03:00
f906eb06c2 Implement a software ETC2 texture decoder (#4121)
* Implement a software ETC2 texture decoder

* Fix output size calculation for non-2D textures

* Address PR feedback
2022-12-21 20:39:58 -03:00
219f63ff4e Fix CPU FCVTN instruction implementation (slow path) (#4159)
* Fix CPU FCVTN instruction implementation (slow path)

* PPTC version bump
2022-12-21 23:05:58 +00:00
1cca3e99ab GPU: Force rebind when pool changes (#4129) 2022-12-21 17:35:28 -03:00
Ccl
55a23e5ec8 make UI display correct content in Chinese (#4155) 2022-12-21 17:20:37 -03:00
479d1fd8b0 hle: Handle GPU profiler and debugger device path correctly (#4138)
This fix a warning on "慟哭そして…" by handling correctly the debug mode
flag.

When debug mode isn't enabled, opening /dev/nvhost-dbg-gpu or /dev/nvhost-prof-gpu should fail with a not implemented error code.

This implement this behaviour and also define stubbed interfaces for
completness.
2022-12-21 18:23:11 +00:00
cb70e7bb30 Fix DrawArrays vertex buffer size (#4141) 2022-12-21 19:08:12 +01:00
c200a7b7c6 ARMeilleure: Hash _data pointer instead of value for Operand (#4156)
I noticed a weirdly high cost for dictionary accesses from MarkLabel etc. Turns out that the hash code was always the same for labels, so the whole point of having a dictionary was missed and it was putting everything in the same bucket. I made it always hash the _data pointer as that's a good source of identifiable and "random" data.
2022-12-21 02:28:18 +01:00
6268170a10 fix sw kbd row collision (#4144) 2022-12-19 15:09:36 -03:00
ee0f9b03a4 Eliminate zero-extension moves in more cases on 32-bit games (#4140)
* Eliminate zero-extension moves in more cases on 32-bit games

* PPTC version bump

* Revert X86Optimizer changes
2022-12-19 14:45:58 -03:00
f93c5f006a Revert "ARMeilleure: Add initial support for AVX512(EVEX encoding) (#3663)" (#4145)
This reverts commit 295fbd0542.
2022-12-18 20:21:10 -03:00
295fbd0542 ARMeilleure: Add initial support for AVX512(EVEX encoding) (#3663)
* ARMeilleure: Add AVX512{F,VL,DQ,BW} detection

Add `UseAvx512Ortho` and `UseAvx512OrthoFloat` optimization flags as
short-hands for `F+VL` and `F+VL+DQ`.

* ARMeilleure: Add initial support for EVEX instruction encoding

Does not implement rounding, or exception controls.

* ARMeilleure: Add `X86Vpternlogd`

Accelerates the vector-`Not` instruction.

* ARMeilleure: Add check for `OSXSAVE` for AVX{2,512}

* ARMeilleure: Add check for `XCR0` flags

Add XCR0 register checks for AVX and AVX512F, following the guidelines
from section 14.3 and 15.2 from the Intel Architecture Software
Developer's Manual.

* ARMeilleure: Increment InternalVersion

* ARMeilleure: Remove redundant `ReProtect` and `Dispose`, formatting

* ARMeilleure: Move XCR0 procedure to GetXcr0Eax

* ARMeilleure: Add `XCR0` to `FeatureInfo` structure

* ARMeilleure: Utilize `ReadOnlySpan` for Xcr0 assembly

Avoids an additional allocation

* ARMeilleure: Formatting fixes
2022-12-18 16:46:13 -03:00
d7310d7a1c hle: Fix wrong conversion in UserPresence.ToString (#4142)
This fixes an error from #3805 that caused a wrong conversion of ``AppKeyValueStorage`` to string.
As that information isn't really relevant without appropriate parsing, it was removed from ``ToString``.

This should get ride of "bell warning" in Mario Kart 8 when entering Time Trials.
2022-12-18 14:23:19 +00:00
8c50943a2e nuget: bump Microsoft.NET.Test.Sdk from 17.4.0 to 17.4.1 (#4137)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.4.0 to 17.4.1.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.4.0...v17.4.1)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-17 01:19:04 +01:00
ec4cd57ccf Implement another non-indexed draw method on GPU (#4123) 2022-12-16 12:06:38 -03:00
5a085cba0f GPU: Fix layered attachment write (#4131)
Fixes a regression caused by #4003 where the code that writes `_vtgWritesRtLayer` was removed, breaking the crowd in mario strikers.
2022-12-16 09:40:01 -03:00
1a1d33a018 ava: Fix invisible swkbd applet on Linux (#4130) 2022-12-16 02:40:55 +01:00
0fbcd630bc Replace DllImport usage with LibraryImport (#4084)
* Replace usage of `DllImport` with `LibraryImport`

* Mark methods as `partial`

* Marshalling

* More `partial` & marshalling

* More `partial` and marshalling

* More partial and marshalling

* Update GdiPlusHelper to LibraryImport

* Unicorn

* More Partial

* Marshal

* Specify EntryPoint

* Specify EntryPoint

* Change GlobalMemoryStatusEx to LibraryImport

* Change RegisterClassEx to LibraryImport

* Define EntryPoints

* Update Ryujinx.Ava/Ui/Controls/Win32NativeInterop.cs

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

* Update Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs

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

* Move return mashal

* Remove calling convention specification

* Remove calling conventions

* Update Ryujinx.Common/SystemInfo/WindowsSystemInfo.cs

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

* Update Ryujinx/Modules/Updater/Updater.cs

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Update Ryujinx.Ava/Modules/Updater/Updater.cs

Co-authored-by: Mary-nyan <thog@protonmail.com>

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
Co-authored-by: Mary-nyan <thog@protonmail.com>
2022-12-15 18:07:31 +01:00
f4d731ae20 Fix NRE when loading Vulkan shader cache with Vertex A shaders (#4124) 2022-12-15 17:52:12 +01:00
8ac53c66b4 Remove Half Conversion (#4106)
* Remove HalfConversion

* Update `CodeGenVersion`
2022-12-14 21:13:23 -03:00
0f50de72be Vulkan: enable VK_EXT_custom_border_color features (#4116)
* Vulkan: enable VK_EXT_custom_border_color features

radv only create the border color bo if this feature is enabled, so it crashed when creating samplers with custom border colors
Fixes #4072
Fixes #3993

* Address gdkchan's comment

Co-authored-by: Mary <mary@mary.zone>
2022-12-14 20:53:33 -03:00
df758eddd1 Bsd: Add support for dns_mitm (#4102)
* bsd: Add dns_mitm from Atmosphère

related AMS files:
- https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.cpp
- https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_host_redirection.cpp

* Remove debug logging and adjust redirect message

* Improve formatting

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Replace Initialize with instance property

* bsd: dns_mitm - Ignore empty lines

* bsd: Mark _mitmHostEntries as readonly

* bsd: Initialize Aliases when returning IpHostEntry

Fixes NullReferenceException

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2022-12-12 18:04:08 +01:00
5f32a8ed94 misc: Update to Ryujinx.Graphics.Nvdec.Dependencies 5.0.1-build13 (#4097)
Fix packaging issues on macOS related to an unsatisfied dependency on libX11
2022-12-12 16:19:46 +01:00
535fbec675 Use NuGet Central Package Management to manage package versions solution-wise (#4095) 2022-12-12 16:03:10 +01:00
6fe88115a3 misc: Some fixes to the updaters (#4092)
This was meant to be only an upgrade of how we set unix permission in
the updater to use .NET 7 new APIs, but I end up finding bugs along the
way.

Changelog:
- Remove direct usage of chmod to use File.SetUnixFileMode.
- Fix command line being broken when updating (#3744) but on
  Ryujinx.Ava.
- Makes Ryujinx.Ava updater fallback to Ryujinx executable if current
  name isn't found.
- Make permission setter function more generic.
2022-12-12 15:17:22 +01:00
475fa4d390 Fix "UI" abbreviation being miscapitalized (#4093) 2022-12-12 15:11:55 +01:00
edf7e628ca Use method overloads that support trimming. Mark some types to be trimming friendly (#4083)
* Use method overloads that support trimming. Mark some types to be trimming friendly

* Use generic version of marshalling method
2022-12-12 15:10:05 +01:00
ba5c0cf5d8 Bsd: Implement Select (#4017)
* bsd: Add gdkchan's Select implementation

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

* bsd: Fix Select() causing a crash with an ArgumentException

.NET Sockets have to be used for the Select() call

* bsd: Make Select more generic

* bsd: Adjust namespaces and remove unused imports

* bsd: Fix NullReferenceException in Select

Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2022-12-12 14:59:31 +01:00
403e67d983 audio: Rewrite SoundIo bindings (#4088)
* audio: Rewrite SoundIo bindings

This rewrite SoundIo bindings to be safer and not a pedantic autogenerated mess.

* Address comments

* Switch DllImport to LibraryImport

* Address gdkchan's comment
2022-12-11 00:57:01 +01:00
c6f1908e0f Fix Lambda Explicit Type Specification Warning (#4090) 2022-12-10 22:12:51 +01:00
851d81d24a Fix Redundant Qualifer Warnings (#4091)
* Fix Redundant Qualifer Warnings

* Remove unnecessary using
2022-12-10 21:21:13 +01:00
459c4caeba Fix HasUnalignedStorageBuffers value when buffers are always unaligned (#4078) 2022-12-09 17:41:40 -03:00
539b22ef7b Add explicit dependency on System.Drawing.Common on Ryujinx.Ava to workaround triming bugs 2022-12-09 20:12:09 +01:00
872f036d64 misc: Remove dependency on System.Drawing.Common (#4082)
We only used it in one spot for DPI scaling factor.

This implements the same behaviour using gdiplus.

This remove 700KB of dependency to download and around 170KB unpacked.
2022-12-09 18:00:53 +01:00
dca96122bf gha: Add concurrency restriction on release workflow (#4081) 2022-12-09 16:15:28 +00:00
e752959109 misc: Update Ryujinx.Graphics.Nvdec.Dependencies to 5.0.1-build12 (#4080)
This adds support for Linux x64, macOS x64 and macOS arm64.
2022-12-09 15:46:07 +01:00
cf01664698 ava: Restyle the Status Bar (#4048) 2022-12-09 15:21:54 +01:00
b283a4adcd nuget: bump CommandLineParser from 2.8.0 to 2.9.1 (#4058)
Bumps [CommandLineParser](https://github.com/commandlineparser/commandline) from 2.8.0 to 2.9.1.
- [Release notes](https://github.com/commandlineparser/commandline/releases)
- [Changelog](https://github.com/commandlineparser/commandline/blob/master/CHANGELOG.md)
- [Commits](https://github.com/commandlineparser/commandline/compare/2.8.0...v2.9.1)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-09 14:16:22 +01:00
8428bb6541 Fix shader FSWZADD instruction (#4069)
* Fix shader FSWZADD instruction

* Shader cache version bump
2022-12-08 14:08:07 -03:00
9a0330f7f8 Shader: Implement PrimitiveID (#4067)
* Shader: Implement PrimitiveID

* Shader cache version bump
2022-12-08 10:55:03 +01:00
57fc996337 Fix inconsistent capitalization (#4070) 2022-12-08 09:32:24 +00:00
1f3b860f06 acc: Stub CheckNetworkServiceAvailabilityAsync (#4052) 2022-12-07 23:19:22 +01:00
abe3c02ab4 nuget: bump DynamicData from 7.12.8 to 7.12.11 (#4059)
Bumps [DynamicData](https://github.com/reactiveui/DynamicData) from 7.12.8 to 7.12.11.
- [Release notes](https://github.com/reactiveui/DynamicData/releases)
- [Changelog](https://github.com/reactivemarbles/DynamicData/blob/main/ReleaseNotes.md)
- [Commits](https://github.com/reactiveui/DynamicData/compare/7.12.8...7.12.11)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-07 23:07:23 +01:00
45b417b2b4 nuget: bump NUnit from 3.12.0 to 3.13.3 (#4060)
Bumps [NUnit](https://github.com/nunit/nunit) from 3.12.0 to 3.13.3.
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/v3.13.3/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/v3.12...v3.13.3)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-07 22:02:31 +01:00
183 changed files with 2996 additions and 3244 deletions

View File

@ -11,6 +11,7 @@ on:
- '*.yml'
- 'README.md'
concurrency: release
jobs:
release:

View File

@ -1587,6 +1587,12 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
{
return;
}
context.Assembler.Mov(dest, source, OperandType.I32);
}

View File

@ -1341,7 +1341,7 @@ namespace ARMeilleure.Decoders
{
string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16);
MakeOp reversedMakeOp =
(InstDescriptor inst, ulong address, int opCode)
(inst, address, opCode)
=> makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
}

View File

@ -381,7 +381,7 @@ namespace ARMeilleure.Instructions
for (int index = 0; index < elems; index++)
{
Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0);
Operand ne = context.VectorExtract(type, GetVec(op.Rn), index);
if (sizeF == 0)
{
@ -389,8 +389,6 @@ namespace ARMeilleure.Instructions
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
context.LoadFromContext();
e = context.ZeroExtend16(OperandType.I64, e);
res = EmitVectorInsert(context, res, e, part + index, 1);
}
else /* if (sizeF == 1) */

View File

@ -378,14 +378,7 @@ namespace ARMeilleure.IntermediateRepresentation
public override int GetHashCode()
{
if (Kind == OperandKind.LocalVariable)
{
return base.GetHashCode();
}
else
{
return (int)Value ^ ((int)Kind << 16) ^ ((int)Type << 20);
}
return ((ulong)_data).GetHashCode();
}
public bool Equals(Operand operand)

View File

@ -18,17 +18,17 @@ namespace ARMeilleure.Signal
public IntPtr sa_restorer;
}
static class UnixSignalHandlerRegistration
static partial class UnixSignalHandlerRegistration
{
private const int SIGSEGV = 11;
private const int SIGBUS = 10;
private const int SA_SIGINFO = 0x00000004;
[DllImport("libc", SetLastError = true)]
private static extern int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction);
[LibraryImport("libc", SetLastError = true)]
private static partial int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction);
[DllImport("libc", SetLastError = true)]
private static extern int sigemptyset(ref SigSet set);
[LibraryImport("libc", SetLastError = true)]
private static partial int sigemptyset(ref SigSet set);
public static SigAction RegisterExceptionHandler(IntPtr action)
{

View File

@ -3,19 +3,19 @@ using System.Runtime.InteropServices;
namespace ARMeilleure.Signal
{
unsafe class WindowsSignalHandlerRegistration
unsafe partial class WindowsSignalHandlerRegistration
{
[DllImport("kernel32.dll")]
private static extern IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
[LibraryImport("kernel32.dll")]
private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
[DllImport("kernel32.dll")]
private static extern ulong RemoveVectoredExceptionHandler(IntPtr handle);
[LibraryImport("kernel32.dll")]
private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
[LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[LibraryImport("kernel32.dll", SetLastError = true)]
private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
private static IntPtr _getCurrentThreadIdPtr;

View File

@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
namespace ARMeilleure.Translation.Cache
{
static class JitUnwindWindows
static partial class JitUnwindWindows
{
private const int MaxUnwindCodesArraySize = 32; // Must be an even value.
@ -42,14 +42,15 @@ namespace ARMeilleure.Translation.Cache
private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, IntPtr context);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static unsafe extern bool RtlInstallFunctionTableCallback(
[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static unsafe partial bool RtlInstallFunctionTableCallback(
ulong tableIdentifier,
ulong baseAddress,
uint length,
GetRuntimeFunctionCallback callback,
IntPtr context,
string outOfProcessCallbackDll);
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;

View File

@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 3713; //! To be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 4159; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";

View File

@ -140,7 +140,7 @@ namespace ARMeilleure.Translation
}
}
Array.Clear(localDefs, 0, localDefs.Length);
Array.Clear(localDefs);
}
}

54
Directory.Packages.props Normal file
View File

@ -0,0 +1,54 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia" Version="0.10.18" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
<PackageVersion Include="Avalonia.Desktop" Version="0.10.18" />
<PackageVersion Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
<PackageVersion Include="Avalonia.Svg" Version="0.10.18" />
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="Concentus" Version="1.1.7" />
<PackageVersion Include="Crc32.NET" Version="1.2.0" />
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
<PackageVersion Include="DynamicData" Version="7.12.11" />
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
<PackageVersion Include="LibHac" Version="0.17.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageVersion Include="OpenTK.Core" Version="4.7.5" />
<PackageVersion Include="OpenTK.Graphics" Version="4.7.5" />
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.5" />
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.5" />
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.24.2-build21" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.1" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
<PackageVersion Include="SPB" Version="0.0.4-build28" />
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" />
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageVersion Include="System.Management" Version="7.0.0" />
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
</ItemGroup>
</Project>

View File

@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" />
<PackageReference Include="OpenTK.OpenAL" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,178 @@
using Ryujinx.Common.Memory;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public static partial class SoundIo
{
private const string LibraryName = "libsoundio";
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void OnDeviceChangeNativeDelegate(IntPtr ctx);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void OnBackendDisconnectedDelegate(IntPtr ctx, SoundIoError err);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void OnEventsSignalDelegate(IntPtr ctx);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void EmitRtPrioWarningDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void JackCallbackDelegate(IntPtr msg);
[StructLayout(LayoutKind.Sequential)]
public struct SoundIoStruct
{
public IntPtr UserData;
public IntPtr OnDeviceChange;
public IntPtr OnBackendDisconnected;
public IntPtr OnEventsSignal;
public SoundIoBackend CurrentBackend;
public IntPtr ApplicationName;
public IntPtr EmitRtPrioWarning;
public IntPtr JackInfoCallback;
public IntPtr JackErrorCallback;
}
public struct SoundIoChannelLayout
{
public IntPtr Name;
public int ChannelCount;
public Array24<SoundIoChannelId> Channels;
public static IntPtr GetDefault(int channelCount)
{
return soundio_channel_layout_get_default(channelCount);
}
public static unsafe SoundIoChannelLayout GetDefaultValue(int channelCount)
{
return Unsafe.AsRef<SoundIoChannelLayout>((SoundIoChannelLayout*)GetDefault(channelCount));
}
}
public struct SoundIoSampleRateRange
{
public int Min;
public int Max;
}
public struct SoundIoDevice
{
public IntPtr SoundIo;
public IntPtr Id;
public IntPtr Name;
public SoundIoDeviceAim Aim;
public IntPtr Layouts;
public int LayoutCount;
public SoundIoChannelLayout CurrentLayout;
public IntPtr Formats;
public int FormatCount;
public SoundIoFormat CurrentFormat;
public IntPtr SampleRates;
public int SampleRateCount;
public int SampleRateCurrent;
public double SoftwareLatencyMin;
public double SoftwareLatencyMax;
public double SoftwareLatencyCurrent;
public bool IsRaw;
public int RefCount;
public SoundIoError ProbeError;
}
public struct SoundIoOutStream
{
public IntPtr 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 bool NonTerminalHint;
public int BytesPerFrame;
public int BytesPerSample;
public SoundIoError LayoutError;
}
public struct SoundIoChannelArea
{
public IntPtr Pointer;
public int Step;
}
[LibraryImport(LibraryName)]
public static partial IntPtr soundio_create();
[LibraryImport(LibraryName)]
public static partial SoundIoError soundio_connect(IntPtr ctx);
[LibraryImport(LibraryName)]
public static partial void soundio_disconnect(IntPtr ctx);
[LibraryImport(LibraryName)]
public static partial void soundio_flush_events(IntPtr ctx);
[LibraryImport(LibraryName)]
public static partial int soundio_output_device_count(IntPtr ctx);
[LibraryImport(LibraryName)]
public static partial int soundio_default_output_device_index(IntPtr ctx);
[LibraryImport(LibraryName)]
public static partial IntPtr soundio_get_output_device(IntPtr ctx, int index);
[LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool soundio_device_supports_format(IntPtr devCtx, SoundIoFormat format);
[LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool soundio_device_supports_layout(IntPtr devCtx, IntPtr layout);
[LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool soundio_device_supports_sample_rate(IntPtr devCtx, int sampleRate);
[LibraryImport(LibraryName)]
public static partial IntPtr soundio_outstream_create(IntPtr devCtx);
[LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_open(IntPtr outStreamCtx);
[LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_start(IntPtr outStreamCtx);
[LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_begin_write(IntPtr outStreamCtx, IntPtr areas, IntPtr frameCount);
[LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_end_write(IntPtr outStreamCtx);
[LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_pause(IntPtr devCtx, [MarshalAs(UnmanagedType.Bool)] bool pause);
[LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_set_volume(IntPtr devCtx, double volume);
[LibraryImport(LibraryName)]
public static partial void soundio_outstream_destroy(IntPtr streamCtx);
[LibraryImport(LibraryName)]
public static partial void soundio_destroy(IntPtr ctx);
[LibraryImport(LibraryName)]
public static partial IntPtr soundio_channel_layout_get_default(int channelCount);
[LibraryImport(LibraryName)]
public static partial IntPtr soundio_strerror(SoundIoError err);
}
}

View File

@ -0,0 +1,13 @@
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public enum SoundIoBackend : int
{
None = 0,
Jack = 1,
PulseAudio = 2,
Alsa = 3,
CoreAudio = 4,
Wasapi = 5,
Dummy = 6
}
}

View File

@ -0,0 +1,75 @@
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public enum SoundIoChannelId
{
Invalid = 0,
FrontLeft = 1,
FrontRight = 2,
FrontCenter = 3,
Lfe = 4,
BackLeft = 5,
BackRight = 6,
FrontLeftCenter = 7,
FrontRightCenter = 8,
BackCenter = 9,
SideLeft = 10,
SideRight = 11,
TopCenter = 12,
TopFrontLeft = 13,
TopFrontCenter = 14,
TopFrontRight = 15,
TopBackLeft = 16,
TopBackCenter = 17,
TopBackRight = 18,
BackLeftCenter = 19,
BackRightCenter = 20,
FrontLeftWide = 21,
FrontRightWide = 22,
FrontLeftHigh = 23,
FrontCenterHigh = 24,
FrontRightHigh = 25,
TopFrontLeftCenter = 26,
TopFrontRightCenter = 27,
TopSideLeft = 28,
TopSideRight = 29,
LeftLfe = 30,
RightLfe = 31,
Lfe2 = 32,
BottomCenter = 33,
BottomLeftCenter = 34,
BottomRightCenter = 35,
MsMid = 36,
MsSide = 37,
AmbisonicW = 38,
AmbisonicX = 39,
AmbisonicY = 40,
AmbisonicZ = 41,
XyX = 42,
XyY = 43,
HeadphonesLeft = 44,
HeadphonesRight = 45,
ClickTrack = 46,
ForeignLanguage = 47,
HearingImpaired = 48,
Narration = 49,
Haptic = 50,
DialogCentricMix = 51,
Aux = 52,
Aux0 = 53,
Aux1 = 54,
Aux2 = 55,
Aux3 = 56,
Aux4 = 57,
Aux5 = 58,
Aux6 = 59,
Aux7 = 60,
Aux8 = 61,
Aux9 = 62,
Aux10 = 63,
Aux11 = 64,
Aux12 = 65,
Aux13 = 66,
Aux14 = 67,
Aux15 = 68,
}
}

View File

@ -0,0 +1,107 @@
using System;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public class SoundIoContext : IDisposable
{
private IntPtr _context;
private Action<SoundIoError> _onBackendDisconnect;
private OnBackendDisconnectedDelegate _onBackendDisconnectNative;
public IntPtr Context => _context;
internal SoundIoContext(IntPtr context)
{
_context = context;
_onBackendDisconnect = null;
_onBackendDisconnectNative = null;
}
public SoundIoError Connect() => soundio_connect(_context);
public void Disconnect() => soundio_disconnect(_context);
public void FlushEvents() => soundio_flush_events(_context);
public int OutputDeviceCount => soundio_output_device_count(_context);
public int DefaultOutputDeviceIndex => soundio_default_output_device_index(_context);
public Action<SoundIoError> OnBackendDisconnect
{
get { return _onBackendDisconnect; }
set
{
_onBackendDisconnect = value;
if (_onBackendDisconnect == null)
{
_onBackendDisconnectNative = null;
}
else
{
_onBackendDisconnectNative = (ctx, err) => _onBackendDisconnect(err);
}
GetContext().OnBackendDisconnected = Marshal.GetFunctionPointerForDelegate(_onBackendDisconnectNative);
}
}
private ref SoundIoStruct GetContext()
{
unsafe
{
return ref Unsafe.AsRef<SoundIoStruct>((SoundIoStruct*)_context);
}
}
public SoundIoDeviceContext GetOutputDevice(int index)
{
IntPtr deviceContext = soundio_get_output_device(_context, index);
if (deviceContext == IntPtr.Zero)
{
return null;
}
return new SoundIoDeviceContext(deviceContext);
}
public static SoundIoContext Create()
{
IntPtr context = soundio_create();
if (context == IntPtr.Zero)
{
return null;
}
return new SoundIoContext(context);
}
protected virtual void Dispose(bool disposing)
{
IntPtr currentContext = Interlocked.Exchange(ref _context, IntPtr.Zero);
if (currentContext != IntPtr.Zero)
{
soundio_destroy(currentContext);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~SoundIoContext()
{
Dispose(false);
}
}
}

View File

@ -0,0 +1,8 @@
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public enum SoundIoDeviceAim
{
SoundIoDeviceAimInput = 0,
SoundIoDeviceAimOutput = 1
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public class SoundIoDeviceContext
{
private readonly IntPtr _context;
public IntPtr Context => _context;
internal SoundIoDeviceContext(IntPtr context)
{
_context = context;
}
private ref SoundIoDevice GetDeviceContext()
{
unsafe
{
return ref Unsafe.AsRef<SoundIoDevice>((SoundIoDevice*)_context);
}
}
public bool IsRaw => GetDeviceContext().IsRaw;
public string Id => Marshal.PtrToStringAnsi(GetDeviceContext().Id);
public bool SupportsSampleRate(int sampleRate) => soundio_device_supports_sample_rate(_context, sampleRate);
public bool SupportsFormat(SoundIoFormat format) => soundio_device_supports_format(_context, format);
public bool SupportsChannelCount(int channelCount) => soundio_device_supports_layout(_context, SoundIoChannelLayout.GetDefault(channelCount));
public SoundIoOutStreamContext CreateOutStream()
{
IntPtr context = soundio_outstream_create(_context);
if (context == IntPtr.Zero)
{
return null;
}
return new SoundIoOutStreamContext(context);
}
}
}

View File

@ -0,0 +1,22 @@
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public enum SoundIoError
{
None = 0,
NoMem = 1,
InitAudioBackend = 2,
SystemResources = 3,
OpeningDevice = 4,
NoSuchDevice = 5,
Invalid = 6,
BackendUnavailable = 7,
Streaming = 8,
IncompatibleDevice = 9,
NoSuchClient = 10,
IncompatibleBackend = 11,
BackendDisconnected = 12,
Interrupted = 13,
Underflow = 14,
EncodingString = 15,
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Runtime.InteropServices;
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
internal class SoundIoException : Exception
{
internal SoundIoException(SoundIoError error) : base(Marshal.PtrToStringAnsi(soundio_strerror(error))) { }
}
}

View File

@ -0,0 +1,25 @@
namespace Ryujinx.Audio.Backends.SoundIo.Native
{
public enum SoundIoFormat
{
Invalid = 0,
S8 = 1,
U8 = 2,
S16LE = 3,
S16BE = 4,
U16LE = 5,
U16BE = 6,
S24LE = 7,
S24BE = 8,
U24LE = 9,
U24BE = 10,
S32LE = 11,
S32BE = 12,
U32LE = 13,
U32BE = 14,
Float32LE = 15,
Float32BE = 16,
Float64LE = 17,
Float64BE = 18,
}
}

View File

@ -0,0 +1,164 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
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 IntPtr _context;
private IntPtr _nameStored;
private Action<int, int> _writeCallback;
private WriteCallbackDelegate _writeCallbackNative;
public IntPtr Context => _context;
internal SoundIoOutStreamContext(IntPtr context)
{
_context = context;
_nameStored = IntPtr.Zero;
_writeCallback = null;
_writeCallbackNative = null;
}
private ref SoundIoOutStream GetOutContext()
{
unsafe
{
return ref Unsafe.AsRef<SoundIoOutStream>((SoundIoOutStream*)_context);
}
}
public string Name
{
get => Marshal.PtrToStringAnsi(GetOutContext().Name);
set
{
var context = GetOutContext();
if (_nameStored != IntPtr.Zero && context.Name == _nameStored)
{
Marshal.FreeHGlobal(_nameStored);
}
_nameStored = Marshal.StringToHGlobalAnsi(value);
GetOutContext().Name = _nameStored;
}
}
public SoundIoChannelLayout Layout
{
get => GetOutContext().Layout;
set => GetOutContext().Layout = value;
}
public SoundIoFormat Format
{
get => GetOutContext().Format;
set => GetOutContext().Format = value;
}
public int SampleRate
{
get => GetOutContext().SampleRate;
set => GetOutContext().SampleRate = value;
}
public float Volume
{
get => GetOutContext().Volume;
set => GetOutContext().Volume = value;
}
public int BytesPerFrame
{
get => GetOutContext().BytesPerFrame;
set => GetOutContext().BytesPerFrame = value;
}
public int BytesPerSample
{
get => GetOutContext().BytesPerSample;
set => GetOutContext().BytesPerSample = value;
}
public Action<int, int> WriteCallback
{
get { return _writeCallback; }
set
{
_writeCallback = value;
if (_writeCallback == null)
{
_writeCallbackNative = null;
}
else
{
_writeCallbackNative = (ctx, frameCountMin, frameCountMax) => _writeCallback(frameCountMin, frameCountMax);
}
GetOutContext().WriteCallback = Marshal.GetFunctionPointerForDelegate(_writeCallbackNative);
}
}
private static void CheckError(SoundIoError error)
{
if (error != SoundIoError.None)
{
throw new SoundIoException(error);
}
}
public void Open() => CheckError(soundio_outstream_open(_context));
public void Start() => CheckError(soundio_outstream_start(_context));
public void Pause(bool pause) => CheckError(soundio_outstream_pause(_context, pause));
public void SetVolume(double volume) => CheckError(soundio_outstream_set_volume(_context, volume));
public Span<SoundIoChannelArea> BeginWrite(ref int frameCount)
{
IntPtr arenas = default;
int nativeFrameCount = frameCount;
unsafe
{
var frameCountPtr = &nativeFrameCount;
var arenasPtr = &arenas;
CheckError(soundio_outstream_begin_write(_context, (IntPtr)arenasPtr, (IntPtr)frameCountPtr));
frameCount = *frameCountPtr;
return new Span<SoundIoChannelArea>((void*)arenas, Layout.ChannelCount);
}
}
public void EndWrite() => CheckError(soundio_outstream_end_write(_context));
protected virtual void Dispose(bool disposing)
{
if (_context != IntPtr.Zero)
{
soundio_outstream_destroy(_context);
_context = IntPtr.Zero;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~SoundIoOutStreamContext()
{
Dispose(false);
}
}
}

View File

@ -1,38 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public static class MarshalEx
{
public static double ReadDouble(IntPtr handle, int offset = 0)
{
return BitConverter.Int64BitsToDouble(Marshal.ReadInt64(handle, offset));
}
public static void WriteDouble(IntPtr handle, double value)
{
WriteDouble(handle, 0, value);
}
public static void WriteDouble(IntPtr handle, int offset, double value)
{
Marshal.WriteInt64(handle, offset, BitConverter.DoubleToInt64Bits(value));
}
public static float ReadFloat(IntPtr handle, int offset = 0)
{
return BitConverter.Int32BitsToSingle(Marshal.ReadInt32(handle, offset));
}
public static void WriteFloat(IntPtr handle, float value)
{
WriteFloat(handle, 0, value);
}
public static void WriteFloat(IntPtr handle, int offset, float value)
{
Marshal.WriteInt32(handle, offset, BitConverter.SingleToInt32Bits(value));
}
}
}

View File

@ -1,386 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public class SoundIO : IDisposable
{
Pointer<SoundIo> handle;
public SoundIO()
{
handle = Natives.soundio_create();
}
internal SoundIO(Pointer<SoundIo> handle)
{
this.handle = handle;
}
public void Dispose ()
{
foreach (var h in allocated_hglobals)
{
Marshal.FreeHGlobal(h);
}
Natives.soundio_destroy(handle);
}
// Equality (based on handle)
public override bool Equals(object other)
{
var d = other as SoundIO;
return d != null && this.handle == d.handle;
}
public override int GetHashCode()
{
return (int)(IntPtr)handle;
}
public static bool operator == (SoundIO obj1, SoundIO obj2)
{
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
}
public static bool operator != (SoundIO obj1, SoundIO obj2)
{
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
}
// fields
// FIXME: this should be taken care in more centralized/decent manner... we don't want to write
// this kind of code anywhere we need string marshaling.
List<IntPtr> allocated_hglobals = new List<IntPtr>();
public string ApplicationName {
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, app_name_offset)); }
set
{
unsafe
{
var existing = Marshal.ReadIntPtr(handle, app_name_offset);
if (allocated_hglobals.Contains (existing))
{
allocated_hglobals.Remove(existing);
Marshal.FreeHGlobal(existing);
}
var ptr = Marshal.StringToHGlobalAnsi(value);
Marshal.WriteIntPtr(handle, app_name_offset, ptr);
allocated_hglobals.Add(ptr);
}
}
}
static readonly int app_name_offset = (int)Marshal.OffsetOf<SoundIo>("app_name");
public SoundIOBackend CurrentBackend
{
get { return (SoundIOBackend)Marshal.ReadInt32(handle, current_backend_offset); }
}
static readonly int current_backend_offset = (int)Marshal.OffsetOf<SoundIo>("current_backend");
// emit_rtprio_warning
public Action EmitRealtimePriorityWarning
{
get { return emit_rtprio_warning; }
set
{
emit_rtprio_warning = value;
var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change);
Marshal.WriteIntPtr(handle, emit_rtprio_warning_offset, ptr);
}
}
static readonly int emit_rtprio_warning_offset = (int)Marshal.OffsetOf<SoundIo>("emit_rtprio_warning");
Action emit_rtprio_warning;
// jack_error_callback
public Action<string> JackErrorCallback
{
get { return jack_error_callback; }
set
{
jack_error_callback = value;
if (value == null)
{
jack_error_callback = null;
}
else
{
jack_error_callback_native = msg => jack_error_callback(msg);
}
var ptr = Marshal.GetFunctionPointerForDelegate(jack_error_callback_native);
Marshal.WriteIntPtr(handle, jack_error_callback_offset, ptr);
}
}
static readonly int jack_error_callback_offset = (int)Marshal.OffsetOf<SoundIo>("jack_error_callback");
Action<string> jack_error_callback;
delegate void jack_error_delegate(string message);
jack_error_delegate jack_error_callback_native;
// jack_info_callback
public Action<string> JackInfoCallback
{
get { return jack_info_callback; }
set
{
jack_info_callback = value;
if (value == null)
{
jack_info_callback = null;
}
else
{
jack_info_callback_native = msg => jack_info_callback(msg);
}
var ptr = Marshal.GetFunctionPointerForDelegate(jack_info_callback_native);
Marshal.WriteIntPtr(handle, jack_info_callback_offset, ptr);
}
}
static readonly int jack_info_callback_offset = (int)Marshal.OffsetOf<SoundIo>("jack_info_callback");
Action<string> jack_info_callback;
delegate void jack_info_delegate(string message);
jack_info_delegate jack_info_callback_native;
// on_backend_disconnect
public Action<int> OnBackendDisconnect
{
get { return on_backend_disconnect; }
set
{
on_backend_disconnect = value;
if (value == null)
{
on_backend_disconnect_native = null;
}
else
{
on_backend_disconnect_native = (sio, err) => on_backend_disconnect(err);
}
var ptr = Marshal.GetFunctionPointerForDelegate(on_backend_disconnect_native);
Marshal.WriteIntPtr(handle, on_backend_disconnect_offset, ptr);
}
}
static readonly int on_backend_disconnect_offset = (int)Marshal.OffsetOf<SoundIo>("on_backend_disconnect");
Action<int> on_backend_disconnect;
delegate void on_backend_disconnect_delegate(IntPtr handle, int errorCode);
on_backend_disconnect_delegate on_backend_disconnect_native;
// on_devices_change
public Action OnDevicesChange
{
get { return on_devices_change; }
set
{
on_devices_change = value;
if (value == null)
{
on_devices_change_native = null;
}
else
{
on_devices_change_native = sio => on_devices_change();
}
var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change_native);
Marshal.WriteIntPtr(handle, on_devices_change_offset, ptr);
}
}
static readonly int on_devices_change_offset = (int)Marshal.OffsetOf<SoundIo>("on_devices_change");
Action on_devices_change;
delegate void on_devices_change_delegate(IntPtr handle);
on_devices_change_delegate on_devices_change_native;
// on_events_signal
public Action OnEventsSignal
{
get { return on_events_signal; }
set
{
on_events_signal = value;
if (value == null)
{
on_events_signal_native = null;
}
else
{
on_events_signal_native = sio => on_events_signal();
}
var ptr = Marshal.GetFunctionPointerForDelegate(on_events_signal_native);
Marshal.WriteIntPtr(handle, on_events_signal_offset, ptr);
}
}
static readonly int on_events_signal_offset = (int)Marshal.OffsetOf<SoundIo>("on_events_signal");
Action on_events_signal;
delegate void on_events_signal_delegate(IntPtr handle);
on_events_signal_delegate on_events_signal_native;
// functions
public int BackendCount
{
get { return Natives.soundio_backend_count(handle); }
}
public int InputDeviceCount
{
get { return Natives.soundio_input_device_count(handle); }
}
public int OutputDeviceCount
{
get { return Natives.soundio_output_device_count(handle); }
}
public int DefaultInputDeviceIndex
{
get { return Natives.soundio_default_input_device_index(handle); }
}
public int DefaultOutputDeviceIndex
{
get { return Natives.soundio_default_output_device_index(handle); }
}
public SoundIOBackend GetBackend(int index)
{
return (SoundIOBackend)Natives.soundio_get_backend(handle, index);
}
public SoundIODevice GetInputDevice(int index)
{
return new SoundIODevice(Natives.soundio_get_input_device(handle, index));
}
public SoundIODevice GetOutputDevice(int index)
{
return new SoundIODevice(Natives.soundio_get_output_device(handle, index));
}
public void Connect()
{
var ret = (SoundIoError)Natives.soundio_connect(handle);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public void ConnectBackend(SoundIOBackend backend)
{
var ret = (SoundIoError)Natives.soundio_connect_backend(handle, (SoundIoBackend)backend);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public void Disconnect()
{
Natives.soundio_disconnect(handle);
}
public void FlushEvents()
{
Natives.soundio_flush_events(handle);
}
public void WaitEvents()
{
Natives.soundio_wait_events(handle);
}
public void Wakeup()
{
Natives.soundio_wakeup(handle);
}
public void ForceDeviceScan()
{
Natives.soundio_force_device_scan(handle);
}
public SoundIORingBuffer CreateRingBuffer(int capacity)
{
return new SoundIORingBuffer(Natives.soundio_ring_buffer_create(handle, capacity));
}
// static methods
public static string VersionString
{
get { return Marshal.PtrToStringAnsi(Natives.soundio_version_string()); }
}
public static int VersionMajor
{
get { return Natives.soundio_version_major(); }
}
public static int VersionMinor
{
get { return Natives.soundio_version_minor(); }
}
public static int VersionPatch
{
get { return Natives.soundio_version_patch(); }
}
public static string GetBackendName(SoundIOBackend backend)
{
return Marshal.PtrToStringAnsi(Natives.soundio_backend_name((SoundIoBackend)backend));
}
public static bool HaveBackend(SoundIOBackend backend)
{
return Natives.soundio_have_backend((SoundIoBackend)backend);
}
public static int GetBytesPerSample(SoundIOFormat format)
{
return Natives.soundio_get_bytes_per_sample((SoundIoFormat)format);
}
public static int GetBytesPerFrame(SoundIOFormat format, int channelCount)
{
return Natives.soundio_get_bytes_per_frame((SoundIoFormat)format, channelCount);
}
public static int GetBytesPerSecond(SoundIOFormat format, int channelCount, int sampleRate)
{
return Natives.soundio_get_bytes_per_second((SoundIoFormat)format, channelCount, sampleRate);
}
public static string GetSoundFormatName(SoundIOFormat format)
{
return Marshal.PtrToStringAnsi(Natives.soundio_format_string((SoundIoFormat)format));
}
}
}

View File

@ -1,13 +0,0 @@
namespace SoundIOSharp
{
public enum SoundIOBackend
{
None,
Jack,
PulseAudio,
Alsa,
CoreAudio,
Wasapi,
Dummy
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public struct SoundIOChannelArea
{
internal SoundIOChannelArea(Pointer<SoundIoChannelArea> handle)
{
this.handle = handle;
}
Pointer<SoundIoChannelArea> handle;
public IntPtr Pointer
{
get { return Marshal.ReadIntPtr(handle, ptr_offset); }
set { Marshal.WriteIntPtr(handle, ptr_offset, value); }
}
static readonly int ptr_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("ptr");
public int Step
{
get { return Marshal.ReadInt32(handle, step_offset); }
}
static readonly int step_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("step");
}
}

View File

@ -1,34 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public struct SoundIOChannelAreas
{
static readonly int native_size = Marshal.SizeOf<SoundIoChannelArea>();
internal SoundIOChannelAreas(IntPtr head, int channelCount, int frameCount)
{
this.head = head;
this.channel_count = channelCount;
this.frame_count = frameCount;
}
IntPtr head;
int channel_count;
int frame_count;
public bool IsEmpty
{
get { return head == IntPtr.Zero; }
}
public SoundIOChannelArea GetArea(int channel)
{
return new SoundIOChannelArea(head + native_size * channel);
}
public int ChannelCount => channel_count;
public int FrameCount => frame_count;
}
}

View File

@ -1,75 +0,0 @@
namespace SoundIOSharp
{
public enum SoundIOChannelId
{
Invalid,
FrontLeft,
FrontRight,
FrontCenter,
Lfe,
BackLeft,
BackRight,
FrontLeftCenter,
FrontRightCenter,
BackCenter,
SideLeft,
SideRight,
TopCenter,
TopFrontLeft,
TopFrontCenter,
TopFrontRight,
TopBackLeft,
TopBackCenter,
TopBackRight,
BackLeftCenter,
BackRightCenter,
FrontLeftWide,
FrontRightWide,
FrontLeftHigh,
FrontCenterHigh,
FrontRightHigh,
TopFrontLeftCenter,
TopFrontRightCenter,
TopSideLeft,
TopSideRight,
LeftLfe,
RightLfe,
Lfe2,
BottomCenter,
BottomLeftCenter,
BottomRightCenter,
MsMid,
MsSide,
AmbisonicW,
AmbisonicX,
AmbisonicY,
AmbisonicZ,
XyX,
XyY,
HeadphonesLeft,
HeadphonesRight,
ClickTrack,
ForeignLanguage,
HearingImpaired,
Narration,
Haptic,
DialogCentricMix,
Aux,
Aux0,
Aux1,
Aux2,
Aux3,
Aux4,
Aux5,
Aux6,
Aux7,
Aux8,
Aux9,
Aux10,
Aux11,
Aux12,
Aux13,
Aux14,
Aux15
}
}

View File

@ -1,116 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public readonly struct SoundIOChannelLayout
{
public static int BuiltInCount
{
get { return Natives.soundio_channel_layout_builtin_count(); }
}
public static SoundIOChannelLayout GetBuiltIn(int index)
{
return new SoundIOChannelLayout(Natives.soundio_channel_layout_get_builtin(index));
}
public static SoundIOChannelLayout GetDefault(int channelCount)
{
var handle = Natives.soundio_channel_layout_get_default(channelCount);
return new SoundIOChannelLayout (handle);
}
public static SoundIOChannelId ParseChannelId(string name)
{
var ptr = Marshal.StringToHGlobalAnsi(name);
try
{
return (SoundIOChannelId)Natives.soundio_parse_channel_id(ptr, name.Length);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
// instance members
internal SoundIOChannelLayout(Pointer<SoundIoChannelLayout> handle)
{
this.handle = handle;
}
readonly Pointer<SoundIoChannelLayout> handle;
public bool IsNull
{
get { return handle.Handle == IntPtr.Zero; }
}
internal IntPtr Handle
{
get { return handle; }
}
public int ChannelCount
{
get { return IsNull ? 0 : Marshal.ReadInt32((IntPtr)handle + channel_count_offset); }
}
static readonly int channel_count_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("channel_count");
public string Name
{
get { return IsNull ? null : Marshal.PtrToStringAnsi(Marshal.ReadIntPtr((IntPtr)handle + name_offset)); }
}
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("name");
public IEnumerable<SoundIOChannelId> Channels
{
get
{
if (IsNull) yield break;
for (int i = 0; i < 24; i++)
{
yield return (SoundIOChannelId)Marshal.ReadInt32((IntPtr)handle + channels_offset + sizeof(SoundIoChannelId) * i);
}
}
}
static readonly int channels_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("channels");
public override bool Equals(object other)
{
if (!(other is SoundIOChannelLayout)) return false;
var s = (SoundIOChannelLayout) other;
return handle == s.handle || Natives.soundio_channel_layout_equal(handle, s.handle);
}
public override int GetHashCode()
{
return handle.GetHashCode();
}
public string DetectBuiltInName()
{
if (IsNull) throw new InvalidOperationException();
return Natives.soundio_channel_layout_detect_builtin(handle) ? Name : null;
}
public int FindChannel(SoundIOChannelId channel)
{
if (IsNull) throw new InvalidOperationException();
return Natives.soundio_channel_layout_find_channel(handle, (SoundIoChannelId)channel);
}
}
}

View File

@ -1,267 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public class SoundIODevice
{
public static SoundIOChannelLayout BestMatchingChannelLayout(SoundIODevice device1, SoundIODevice device2)
{
var ptr1 = Marshal.ReadIntPtr(device1.handle, layouts_offset);
var ptr2 = Marshal.ReadIntPtr(device2.handle, layouts_offset);
return new SoundIOChannelLayout(Natives.soundio_best_matching_channel_layout(ptr1, device1.LayoutCount, ptr2, device2.LayoutCount));
}
internal SoundIODevice(Pointer<SoundIoDevice> handle)
{
this.handle = handle;
}
readonly Pointer<SoundIoDevice> handle;
// Equality (based on handle and native func)
public override bool Equals(object other)
{
var d = other as SoundIODevice;
return d != null && (this.handle == d.handle || Natives.soundio_device_equal (this.handle, d.handle));
}
public override int GetHashCode()
{
return (int)(IntPtr)handle;
}
public static bool operator == (SoundIODevice obj1, SoundIODevice obj2)
{
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
}
public static bool operator != (SoundIODevice obj1, SoundIODevice obj2)
{
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
}
// fields
public SoundIODeviceAim Aim
{
get { return (SoundIODeviceAim)Marshal.ReadInt32(handle, aim_offset); }
}
static readonly int aim_offset = (int)Marshal.OffsetOf<SoundIoDevice>("aim");
public SoundIOFormat CurrentFormat
{
get { return (SoundIOFormat)Marshal.ReadInt32(handle, current_format_offset); }
}
static readonly int current_format_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_format");
public SoundIOChannelLayout CurrentLayout
{
get { return new SoundIOChannelLayout((IntPtr)handle + current_layout_offset); }
}
static readonly int current_layout_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_layout");
public int FormatCount
{
get { return Marshal.ReadInt32(handle, format_count_offset); }
}
static readonly int format_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("format_count");
public IEnumerable<SoundIOFormat> Formats
{
get
{
var ptr = Marshal.ReadIntPtr(handle, formats_offset);
for (int i = 0; i < FormatCount; i++)
{
yield return (SoundIOFormat)Marshal.ReadInt32(ptr, i);
}
}
}
static readonly int formats_offset = (int)Marshal.OffsetOf<SoundIoDevice>("formats");
public string Id
{
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, id_offset)); }
}
static readonly int id_offset = (int)Marshal.OffsetOf<SoundIoDevice>("id");
public bool IsRaw
{
get { return Marshal.ReadInt32(handle, is_raw_offset) != 0; }
}
static readonly int is_raw_offset = (int)Marshal.OffsetOf<SoundIoDevice>("is_raw");
public int LayoutCount
{
get { return Marshal.ReadInt32(handle, layout_count_offset); }
}
static readonly int layout_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layout_count");
public IEnumerable<SoundIOChannelLayout> Layouts
{
get
{
var ptr = Marshal.ReadIntPtr (handle, layouts_offset);
for (int i = 0; i < LayoutCount; i++)
{
yield return new SoundIOChannelLayout(ptr + i * Marshal.SizeOf<SoundIoChannelLayout>());
}
}
}
static readonly int layouts_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layouts");
public string Name
{
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
}
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoDevice>("name");
public int ProbeError
{
get { return Marshal.ReadInt32(handle, probe_error_offset); }
}
static readonly int probe_error_offset = (int)Marshal.OffsetOf<SoundIoDevice>("probe_error");
public int ReferenceCount
{
get { return Marshal.ReadInt32(handle, ref_count_offset); }
}
static readonly int ref_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("ref_count");
public int SampleRateCount
{
get { return Marshal.ReadInt32(handle, sample_rate_count_offset); }
}
static readonly int sample_rate_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("sample_rate_count");
public IEnumerable<SoundIOSampleRateRange> SampleRates
{
get
{
var ptr = Marshal.ReadIntPtr(handle, sample_rates_offset);
for (int i = 0; i < SampleRateCount; i++)
{
yield return new SoundIOSampleRateRange(Marshal.ReadInt32(ptr, i * 2), Marshal.ReadInt32(ptr, i * 2 + 1));
}
}
}
static readonly int sample_rates_offset = (int)Marshal.OffsetOf<SoundIoDevice>("sample_rates");
public double SoftwareLatencyCurrent
{
get { return MarshalEx.ReadDouble(handle, software_latency_current_offset); }
set { MarshalEx.WriteDouble(handle, software_latency_current_offset, value); }
}
static readonly int software_latency_current_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_current");
public double SoftwareLatencyMin
{
get { return MarshalEx.ReadDouble(handle, software_latency_min_offset); }
set { MarshalEx.WriteDouble(handle, software_latency_min_offset, value); }
}
static readonly int software_latency_min_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_min");
public double SoftwareLatencyMax
{
get { return MarshalEx.ReadDouble(handle, software_latency_max_offset); }
set { MarshalEx.WriteDouble(handle, software_latency_max_offset, value); }
}
static readonly int software_latency_max_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_max");
public SoundIO SoundIO
{
get { return new SoundIO(Marshal.ReadIntPtr(handle, soundio_offset)); }
}
static readonly int soundio_offset = (int)Marshal.OffsetOf<SoundIoDevice>("soundio");
// functions
public void AddReference()
{
Natives.soundio_device_ref(handle);
}
public void RemoveReference()
{
Natives.soundio_device_unref(handle);
}
public void SortDeviceChannelLayouts()
{
Natives.soundio_device_sort_channel_layouts(handle);
}
public static readonly SoundIOFormat S16NE = BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE;
public static readonly SoundIOFormat U16NE = BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE;
public static readonly SoundIOFormat S24NE = BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE;
public static readonly SoundIOFormat U24NE = BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE;
public static readonly SoundIOFormat S32NE = BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE;
public static readonly SoundIOFormat U32NE = BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE;
public static readonly SoundIOFormat Float32NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE;
public static readonly SoundIOFormat Float64NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE;
public static readonly SoundIOFormat S16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE;
public static readonly SoundIOFormat U16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE;
public static readonly SoundIOFormat S24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE;
public static readonly SoundIOFormat U24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE;
public static readonly SoundIOFormat S32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE;
public static readonly SoundIOFormat U32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE;
public static readonly SoundIOFormat Float32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE;
public static readonly SoundIOFormat Float64FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE;
public bool SupportsFormat(SoundIOFormat format)
{
return Natives.soundio_device_supports_format(handle, (SoundIoFormat)format);
}
public bool SupportsSampleRate(int sampleRate)
{
return Natives.soundio_device_supports_sample_rate(handle, sampleRate);
}
public bool SupportsChannelCount(int channelCount)
{
return Natives.soundio_device_supports_layout(handle, SoundIOChannelLayout.GetDefault(channelCount).Handle);
}
public int GetNearestSampleRate(int sampleRate)
{
return Natives.soundio_device_nearest_sample_rate(handle, sampleRate);
}
public SoundIOInStream CreateInStream()
{
return new SoundIOInStream(Natives.soundio_instream_create(handle));
}
public SoundIOOutStream CreateOutStream()
{
return new SoundIOOutStream(Natives.soundio_outstream_create(handle));
}
}
}

View File

@ -1,8 +0,0 @@
namespace SoundIOSharp
{
public enum SoundIODeviceAim // soundio.h (228, 6)
{
Input,
Output
}
}

View File

@ -1,10 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public class SoundIOException : Exception
{
internal SoundIOException(SoundIoError errorCode) : base (Marshal.PtrToStringAnsi(Natives.soundio_strerror((int) errorCode))) { }
}
}

View File

@ -1,25 +0,0 @@
namespace SoundIOSharp
{
public enum SoundIOFormat
{
Invalid,
S8,
U8,
S16LE,
S16BE,
U16LE,
U16BE,
S24LE,
S24BE,
U24LE,
U24BE,
S32LE,
S32BE,
U32LE,
U32BE,
Float32LE,
Float32BE,
Float64LE,
Float64BE
}
}

View File

@ -1,293 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public class SoundIOInStream : IDisposable
{
internal SoundIOInStream(Pointer<SoundIoInStream> handle)
{
this.handle = handle;
}
Pointer<SoundIoInStream> handle;
public void Dispose()
{
Natives.soundio_instream_destroy(handle);
}
// Equality (based on handle)
public override bool Equals(object other)
{
var d = other as SoundIOInStream;
return d != null && (this.handle == d.handle);
}
public override int GetHashCode()
{
return (int)(IntPtr)handle;
}
public static bool operator == (SoundIOInStream obj1, SoundIOInStream obj2)
{
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
}
public static bool operator != (SoundIOInStream obj1, SoundIOInStream obj2)
{
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
}
// fields
public SoundIODevice Device
{
get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); }
}
static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoInStream>("device");
public SoundIOFormat Format
{
get { return (SoundIOFormat)Marshal.ReadInt32(handle, format_offset); }
set { Marshal.WriteInt32(handle, format_offset, (int) value); }
}
static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoInStream>("format");
public int SampleRate
{
get { return Marshal.ReadInt32(handle, sample_rate_offset); }
set { Marshal.WriteInt32(handle, sample_rate_offset, value); }
}
static readonly int sample_rate_offset = (int)Marshal.OffsetOf<SoundIoInStream>("sample_rate");
public SoundIOChannelLayout Layout
{
get { return new SoundIOChannelLayout ((IntPtr) handle + layout_offset); }
set
{
unsafe
{
Buffer.MemoryCopy((void*)((IntPtr)handle + layout_offset), (void*)value.Handle, Marshal.SizeOf<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
}
}
}
static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoInStream>("layout");
public double SoftwareLatency
{
get { return MarshalEx.ReadDouble(handle, software_latency_offset); }
set { MarshalEx.WriteDouble(handle, software_latency_offset, value); }
}
static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoInStream>("software_latency");
// error_callback
public Action ErrorCallback
{
get { return error_callback; }
set
{
error_callback = value;
error_callback_native = _ => error_callback();
var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native);
Marshal.WriteIntPtr(handle, error_callback_offset, ptr);
}
}
static readonly int error_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("error_callback");
Action error_callback;
delegate void error_callback_delegate(IntPtr handle);
error_callback_delegate error_callback_native;
// read_callback
public Action<int,int> ReadCallback
{
get { return read_callback; }
set
{
read_callback = value;
read_callback_native = (_, minFrameCount, maxFrameCount) => read_callback(minFrameCount, maxFrameCount);
var ptr = Marshal.GetFunctionPointerForDelegate(read_callback_native);
Marshal.WriteIntPtr(handle, read_callback_offset, ptr);
}
}
static readonly int read_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("read_callback");
Action<int, int> read_callback;
delegate void read_callback_delegate(IntPtr handle, int min, int max);
read_callback_delegate read_callback_native;
// overflow_callback
public Action OverflowCallback
{
get { return overflow_callback; }
set
{
overflow_callback = value;
overflow_callback_native = _ => overflow_callback();
var ptr = Marshal.GetFunctionPointerForDelegate(overflow_callback_native);
Marshal.WriteIntPtr(handle, overflow_callback_offset, ptr);
}
}
static readonly int overflow_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("overflow_callback");
Action overflow_callback;
delegate void overflow_callback_delegate(IntPtr handle);
overflow_callback_delegate overflow_callback_native;
// FIXME: this should be taken care in more centralized/decent manner... we don't want to write
// this kind of code anywhere we need string marshaling.
List<IntPtr> allocated_hglobals = new List<IntPtr>();
public string Name
{
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
set
{
unsafe
{
var existing = Marshal.ReadIntPtr(handle, name_offset);
if (allocated_hglobals.Contains(existing))
{
allocated_hglobals.Remove(existing);
Marshal.FreeHGlobal(existing);
}
var ptr = Marshal.StringToHGlobalAnsi(value);
Marshal.WriteIntPtr(handle, name_offset, ptr);
allocated_hglobals.Add(ptr);
}
}
}
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoInStream>("name");
public bool NonTerminalHint
{
get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; }
}
static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoInStream>("non_terminal_hint");
public int BytesPerFrame
{
get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); }
}
static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf<SoundIoInStream>("bytes_per_frame");
public int BytesPerSample
{
get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); }
}
static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf<SoundIoInStream>("bytes_per_sample");
public string LayoutErrorMessage
{
get
{
var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset);
return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code));
}
}
static readonly int layout_error_offset = (int)Marshal.OffsetOf<SoundIoInStream>("layout_error");
// functions
public void Open()
{
var ret = (SoundIoError)Natives.soundio_instream_open(handle);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public void Start()
{
var ret = (SoundIoError)Natives.soundio_instream_start(handle);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public SoundIOChannelAreas BeginRead(ref int frameCount)
{
IntPtr ptrs = default;
int nativeFrameCount = frameCount;
unsafe
{
var frameCountPtr = &nativeFrameCount;
var ptrptr = &ptrs;
var ret = (SoundIoError)Natives.soundio_instream_begin_read(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr);
frameCount = *frameCountPtr;
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount);
}
}
public void EndRead()
{
var ret = (SoundIoError)Natives.soundio_instream_end_read(handle);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public void Pause(bool pause)
{
var ret = (SoundIoError)Natives.soundio_instream_pause(handle, pause);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public double GetLatency()
{
unsafe
{
double* dptr = null;
IntPtr p = new IntPtr(dptr);
var ret = (SoundIoError)Natives.soundio_instream_get_latency(handle, p);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
dptr = (double*)p;
return *dptr;
}
}
}
}

View File

@ -1,331 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public class SoundIOOutStream : IDisposable
{
internal SoundIOOutStream (Pointer<SoundIoOutStream> handle)
{
this.handle = handle;
}
Pointer<SoundIoOutStream> handle;
public void Dispose ()
{
Natives.soundio_outstream_destroy (handle);
}
// Equality (based on handle)
public override bool Equals (object other)
{
var d = other as SoundIOOutStream;
return d != null && (this.handle == d.handle);
}
public override int GetHashCode ()
{
return (int)(IntPtr)handle;
}
public static bool operator == (SoundIOOutStream obj1, SoundIOOutStream obj2)
{
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
}
public static bool operator != (SoundIOOutStream obj1, SoundIOOutStream obj2)
{
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
}
// fields
public SoundIODevice Device
{
get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); }
}
static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("device");
public SoundIOFormat Format
{
get { return (SoundIOFormat) Marshal.ReadInt32(handle, format_offset); }
set { Marshal.WriteInt32(handle, format_offset, (int) value); }
}
static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("format");
public int SampleRate
{
get { return Marshal.ReadInt32(handle, sample_rate_offset); }
set { Marshal.WriteInt32(handle, sample_rate_offset, value); }
}
static readonly int sample_rate_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("sample_rate");
public SoundIOChannelLayout Layout
{
get { unsafe { return new SoundIOChannelLayout((IntPtr) (void*)((IntPtr)handle + layout_offset)); } }
set
{
unsafe
{
Buffer.MemoryCopy((void*)value.Handle, (void*)((IntPtr)handle + layout_offset), Marshal.SizeOf<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
}
}
}
static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("layout");
public double SoftwareLatency
{
get { return MarshalEx.ReadDouble (handle, software_latency_offset); }
set { MarshalEx.WriteDouble (handle, software_latency_offset, value); }
}
static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("software_latency");
public float Volume
{
get { return MarshalEx.ReadFloat(handle, volume_offset); }
set { MarshalEx.WriteFloat(handle, volume_offset, value); }
}
static readonly int volume_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("volume");
// error_callback
public Action ErrorCallback
{
get { return error_callback; }
set
{
error_callback = value;
if (value == null)
{
error_callback_native = null;
}
else
{
error_callback_native = stream => error_callback();
}
var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native);
Marshal.WriteIntPtr(handle, error_callback_offset, ptr);
}
}
static readonly int error_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("error_callback");
Action error_callback;
delegate void error_callback_delegate (IntPtr handle);
error_callback_delegate error_callback_native;
// write_callback
public Action<int, int> WriteCallback
{
get { return write_callback; }
set
{
write_callback = value;
if (value == null)
{
write_callback_native = null;
}
else
{
write_callback_native = (h, frame_count_min, frame_count_max) => write_callback(frame_count_min, frame_count_max);
}
var ptr = Marshal.GetFunctionPointerForDelegate (write_callback_native);
Marshal.WriteIntPtr (handle, write_callback_offset, ptr);
}
}
static readonly int write_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("write_callback");
Action<int, int> write_callback;
delegate void write_callback_delegate(IntPtr handle, int min, int max);
write_callback_delegate write_callback_native;
// underflow_callback
public Action UnderflowCallback
{
get { return underflow_callback; }
set
{
underflow_callback = value;
if (value == null)
{
underflow_callback_native = null;
}
else
{
underflow_callback_native = h => underflow_callback();
}
var ptr = Marshal.GetFunctionPointerForDelegate (underflow_callback_native);
Marshal.WriteIntPtr (handle, underflow_callback_offset, ptr);
}
}
static readonly int underflow_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("underflow_callback");
Action underflow_callback;
delegate void underflow_callback_delegate(IntPtr handle);
underflow_callback_delegate underflow_callback_native;
// FIXME: this should be taken care in more centralized/decent manner... we don't want to write
// this kind of code anywhere we need string marshaling.
List<IntPtr> allocated_hglobals = new List<IntPtr>();
public string Name {
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
set
{
unsafe
{
var existing = Marshal.ReadIntPtr(handle, name_offset);
if (allocated_hglobals.Contains(existing))
{
allocated_hglobals.Remove(existing);
Marshal.FreeHGlobal(existing);
}
var ptr = Marshal.StringToHGlobalAnsi(value);
Marshal.WriteIntPtr(handle, name_offset, ptr);
allocated_hglobals.Add(ptr);
}
}
}
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("name");
public bool NonTerminalHint
{
get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; }
}
static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("non_terminal_hint");
public int BytesPerFrame
{
get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); }
}
static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("bytes_per_frame");
public int BytesPerSample
{
get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); }
}
static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("bytes_per_sample");
public string LayoutErrorMessage
{
get
{
var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset);
return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code));
}
}
static readonly int layout_error_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("layout_error");
// functions
public void Open ()
{
var ret = (SoundIoError)Natives.soundio_outstream_open(handle);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public void Start ()
{
var ret = (SoundIoError)Natives.soundio_outstream_start(handle);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public SoundIOChannelAreas BeginWrite(ref int frameCount)
{
IntPtr ptrs = default;
int nativeFrameCount = frameCount;
unsafe
{
var frameCountPtr = &nativeFrameCount;
var ptrptr = &ptrs;
var ret = (SoundIoError)Natives.soundio_outstream_begin_write(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr);
frameCount = *frameCountPtr;
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount);
}
}
public void EndWrite ()
{
var ret = (SoundIoError)Natives.soundio_outstream_end_write(handle);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public void ClearBuffer ()
{
_ = Natives.soundio_outstream_clear_buffer(handle);
}
public void Pause (bool pause)
{
var ret = (SoundIoError)Natives.soundio_outstream_pause(handle, pause);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
public double GetLatency ()
{
unsafe
{
double* dptr = null;
IntPtr p = new IntPtr(dptr);
var ret = (SoundIoError)Natives.soundio_outstream_get_latency(handle, p);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
dptr = (double*)p;
return *dptr;
}
}
public void SetVolume (double volume)
{
var ret = (SoundIoError)Natives.soundio_outstream_set_volume(handle, volume);
if (ret != SoundIoError.SoundIoErrorNone)
{
throw new SoundIOException(ret);
}
}
}
}

View File

@ -1,58 +0,0 @@
using System;
namespace SoundIOSharp
{
public class SoundIORingBuffer : IDisposable
{
internal SoundIORingBuffer(IntPtr handle)
{
this.handle = handle;
}
IntPtr handle;
public int Capacity
{
get { return Natives.soundio_ring_buffer_capacity(handle); }
}
public void Clear()
{
Natives.soundio_ring_buffer_clear(handle);
}
public void Dispose()
{
Natives.soundio_ring_buffer_destroy(handle);
}
public int FillCount
{
get { return Natives.soundio_ring_buffer_fill_count(handle); }
}
public int FreeCount
{
get { return Natives.soundio_ring_buffer_free_count(handle); }
}
public IntPtr ReadPointer
{
get { return Natives.soundio_ring_buffer_read_ptr(handle); }
}
public IntPtr WritePointer
{
get { return Natives.soundio_ring_buffer_write_ptr(handle); }
}
public void AdvanceReadPointer(int count)
{
Natives.soundio_ring_buffer_advance_read_ptr(handle, count);
}
public void AdvanceWritePointer(int count)
{
Natives.soundio_ring_buffer_advance_write_ptr(handle, count);
}
}
}

View File

@ -1,14 +0,0 @@
namespace SoundIOSharp
{
public readonly struct SoundIOSampleRateRange
{
internal SoundIOSampleRateRange(int min, int max)
{
Min = min;
Max = max;
}
public readonly int Min;
public readonly int Max;
}
}

View File

@ -1,643 +0,0 @@
// This source file is generated by nclang PInvokeGenerator.
using System;
using System.Runtime.InteropServices;
using delegate0 = SoundIOSharp.Delegates.delegate0;
using delegate1 = SoundIOSharp.Delegates.delegate1;
using delegate2 = SoundIOSharp.Delegates.delegate2;
using delegate3 = SoundIOSharp.Delegates.delegate3;
using delegate4 = SoundIOSharp.Delegates.delegate4;
using delegate5 = SoundIOSharp.Delegates.delegate5;
using delegate6 = SoundIOSharp.Delegates.delegate6;
using delegate7 = SoundIOSharp.Delegates.delegate7;
using delegate8 = SoundIOSharp.Delegates.delegate8;
using delegate9 = SoundIOSharp.Delegates.delegate9;
namespace SoundIOSharp
{
enum SoundIoError // soundio.h (72, 6)
{
SoundIoErrorNone = 0,
SoundIoErrorNoMem = 1,
SoundIoErrorInitAudioBackend = 2,
SoundIoErrorSystemResources = 3,
SoundIoErrorOpeningDevice = 4,
SoundIoErrorNoSuchDevice = 5,
SoundIoErrorInvalid = 6,
SoundIoErrorBackendUnavailable = 7,
SoundIoErrorStreaming = 8,
SoundIoErrorIncompatibleDevice = 9,
SoundIoErrorNoSuchClient = 10,
SoundIoErrorIncompatibleBackend = 11,
SoundIoErrorBackendDisconnected = 12,
SoundIoErrorInterrupted = 13,
SoundIoErrorUnderflow = 14,
SoundIoErrorEncodingString = 15,
}
enum SoundIoChannelId // soundio.h (106, 6)
{
SoundIoChannelIdInvalid = 0,
SoundIoChannelIdFrontLeft = 1,
SoundIoChannelIdFrontRight = 2,
SoundIoChannelIdFrontCenter = 3,
SoundIoChannelIdLfe = 4,
SoundIoChannelIdBackLeft = 5,
SoundIoChannelIdBackRight = 6,
SoundIoChannelIdFrontLeftCenter = 7,
SoundIoChannelIdFrontRightCenter = 8,
SoundIoChannelIdBackCenter = 9,
SoundIoChannelIdSideLeft = 10,
SoundIoChannelIdSideRight = 11,
SoundIoChannelIdTopCenter = 12,
SoundIoChannelIdTopFrontLeft = 13,
SoundIoChannelIdTopFrontCenter = 14,
SoundIoChannelIdTopFrontRight = 15,
SoundIoChannelIdTopBackLeft = 16,
SoundIoChannelIdTopBackCenter = 17,
SoundIoChannelIdTopBackRight = 18,
SoundIoChannelIdBackLeftCenter = 19,
SoundIoChannelIdBackRightCenter = 20,
SoundIoChannelIdFrontLeftWide = 21,
SoundIoChannelIdFrontRightWide = 22,
SoundIoChannelIdFrontLeftHigh = 23,
SoundIoChannelIdFrontCenterHigh = 24,
SoundIoChannelIdFrontRightHigh = 25,
SoundIoChannelIdTopFrontLeftCenter = 26,
SoundIoChannelIdTopFrontRightCenter = 27,
SoundIoChannelIdTopSideLeft = 28,
SoundIoChannelIdTopSideRight = 29,
SoundIoChannelIdLeftLfe = 30,
SoundIoChannelIdRightLfe = 31,
SoundIoChannelIdLfe2 = 32,
SoundIoChannelIdBottomCenter = 33,
SoundIoChannelIdBottomLeftCenter = 34,
SoundIoChannelIdBottomRightCenter = 35,
SoundIoChannelIdMsMid = 36,
SoundIoChannelIdMsSide = 37,
SoundIoChannelIdAmbisonicW = 38,
SoundIoChannelIdAmbisonicX = 39,
SoundIoChannelIdAmbisonicY = 40,
SoundIoChannelIdAmbisonicZ = 41,
SoundIoChannelIdXyX = 42,
SoundIoChannelIdXyY = 43,
SoundIoChannelIdHeadphonesLeft = 44,
SoundIoChannelIdHeadphonesRight = 45,
SoundIoChannelIdClickTrack = 46,
SoundIoChannelIdForeignLanguage = 47,
SoundIoChannelIdHearingImpaired = 48,
SoundIoChannelIdNarration = 49,
SoundIoChannelIdHaptic = 50,
SoundIoChannelIdDialogCentricMix = 51,
SoundIoChannelIdAux = 52,
SoundIoChannelIdAux0 = 53,
SoundIoChannelIdAux1 = 54,
SoundIoChannelIdAux2 = 55,
SoundIoChannelIdAux3 = 56,
SoundIoChannelIdAux4 = 57,
SoundIoChannelIdAux5 = 58,
SoundIoChannelIdAux6 = 59,
SoundIoChannelIdAux7 = 60,
SoundIoChannelIdAux8 = 61,
SoundIoChannelIdAux9 = 62,
SoundIoChannelIdAux10 = 63,
SoundIoChannelIdAux11 = 64,
SoundIoChannelIdAux12 = 65,
SoundIoChannelIdAux13 = 66,
SoundIoChannelIdAux14 = 67,
SoundIoChannelIdAux15 = 68,
}
enum SoundIoChannelLayoutId // soundio.h (189, 6)
{
SoundIoChannelLayoutIdMono = 0,
SoundIoChannelLayoutIdStereo = 1,
SoundIoChannelLayoutId2Point1 = 2,
SoundIoChannelLayoutId3Point0 = 3,
SoundIoChannelLayoutId3Point0Back = 4,
SoundIoChannelLayoutId3Point1 = 5,
SoundIoChannelLayoutId4Point0 = 6,
SoundIoChannelLayoutIdQuad = 7,
SoundIoChannelLayoutIdQuadSide = 8,
SoundIoChannelLayoutId4Point1 = 9,
SoundIoChannelLayoutId5Point0Back = 10,
SoundIoChannelLayoutId5Point0Side = 11,
SoundIoChannelLayoutId5Point1 = 12,
SoundIoChannelLayoutId5Point1Back = 13,
SoundIoChannelLayoutId6Point0Side = 14,
SoundIoChannelLayoutId6Point0Front = 15,
SoundIoChannelLayoutIdHexagonal = 16,
SoundIoChannelLayoutId6Point1 = 17,
SoundIoChannelLayoutId6Point1Back = 18,
SoundIoChannelLayoutId6Point1Front = 19,
SoundIoChannelLayoutId7Point0 = 20,
SoundIoChannelLayoutId7Point0Front = 21,
SoundIoChannelLayoutId7Point1 = 22,
SoundIoChannelLayoutId7Point1Wide = 23,
SoundIoChannelLayoutId7Point1WideBack = 24,
SoundIoChannelLayoutIdOctagonal = 25,
}
enum SoundIoBackend // soundio.h (218, 6)
{
SoundIoBackendNone = 0,
SoundIoBackendJack = 1,
SoundIoBackendPulseAudio = 2,
SoundIoBackendAlsa = 3,
SoundIoBackendCoreAudio = 4,
SoundIoBackendWasapi = 5,
SoundIoBackendDummy = 6,
}
enum SoundIoDeviceAim // soundio.h (228, 6)
{
SoundIoDeviceAimInput = 0,
SoundIoDeviceAimOutput = 1,
}
enum SoundIoFormat // soundio.h (235, 6)
{
SoundIoFormatInvalid = 0,
SoundIoFormatS8 = 1,
SoundIoFormatU8 = 2,
SoundIoFormatS16LE = 3,
SoundIoFormatS16BE = 4,
SoundIoFormatU16LE = 5,
SoundIoFormatU16BE = 6,
SoundIoFormatS24LE = 7,
SoundIoFormatS24BE = 8,
SoundIoFormatU24LE = 9,
SoundIoFormatU24BE = 10,
SoundIoFormatS32LE = 11,
SoundIoFormatS32BE = 12,
SoundIoFormatU32LE = 13,
SoundIoFormatU32BE = 14,
SoundIoFormatFloat32LE = 15,
SoundIoFormatFloat32BE = 16,
SoundIoFormatFloat64LE = 17,
SoundIoFormatFloat64BE = 18,
}
[StructLayout(LayoutKind.Sequential)]
struct SoundIoChannelLayout // soundio.h (306, 8)
{
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
public int @channel_count;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
[CTypeDetails("ConstArrayOf<SoundIoChannelId>")] public SoundIoChannelId[] @channels;
}
[StructLayout(LayoutKind.Sequential)]
struct SoundIoSampleRateRange // soundio.h (313, 8)
{
public int @min;
public int @max;
}
[StructLayout(LayoutKind.Sequential)]
struct SoundIoChannelArea // soundio.h (319, 8)
{
[CTypeDetails("Pointer<byte>")] public System.IntPtr @ptr;
public int @step;
}
[StructLayout(LayoutKind.Sequential)]
struct SoundIo // soundio.h (328, 8)
{
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
[CTypeDetails("Pointer<void (SoundIo *)>")] public delegate0 @on_devices_change;
[CTypeDetails("Pointer<void (SoundIo *, int)>")] public delegate1 @on_backend_disconnect;
[CTypeDetails("Pointer<void (SoundIo *)>")] public Delegates.delegate0 @on_events_signal;
public SoundIoBackend @current_backend;
[CTypeDetails("Pointer<byte>")] public System.IntPtr @app_name;
[CTypeDetails("Pointer<void ()>")] public delegate2 @emit_rtprio_warning;
[CTypeDetails("Pointer<void (const char *)>")] public delegate3 @jack_info_callback;
[CTypeDetails("Pointer<void (const char *)>")] public Delegates.delegate3 @jack_error_callback;
}
[StructLayout(LayoutKind.Sequential)]
struct SoundIoDevice // soundio.h (387, 8)
{
[CTypeDetails("Pointer<SoundIo>")] public System.IntPtr @soundio;
[CTypeDetails("Pointer<byte>")] public System.IntPtr @id;
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
public SoundIoDeviceAim @aim;
[CTypeDetails("Pointer<SoundIoChannelLayout>")] public System.IntPtr @layouts;
public int @layout_count;
public SoundIoChannelLayout @current_layout;
[CTypeDetails("Pointer<SoundIoFormat>")] public System.IntPtr @formats;
public int @format_count;
public SoundIoFormat @current_format;
[CTypeDetails("Pointer<SoundIoSampleRateRange>")] public System.IntPtr @sample_rates;
public int @sample_rate_count;
public int @sample_rate_current;
public double @software_latency_min;
public double @software_latency_max;
public double @software_latency_current;
public bool @is_raw;
public int @ref_count;
public int @probe_error;
}
[StructLayout(LayoutKind.Sequential)]
struct SoundIoOutStream // soundio.h (497, 8)
{
[CTypeDetails("Pointer<SoundIoDevice>")] public System.IntPtr @device;
public SoundIoFormat @format;
public int @sample_rate;
public SoundIoChannelLayout @layout;
public double @software_latency;
public float @volume;
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
[CTypeDetails("Pointer<void (SoundIoOutStream *, int, int)>")] public delegate4 @write_callback;
[CTypeDetails("Pointer<void (SoundIoOutStream *)>")] public delegate5 @underflow_callback;
[CTypeDetails("Pointer<void (SoundIoOutStream *, int)>")] public delegate6 @error_callback;
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
public bool @non_terminal_hint;
public int @bytes_per_frame;
public int @bytes_per_sample;
public int @layout_error;
}
[StructLayout(LayoutKind.Sequential)]
struct SoundIoInStream // soundio.h (600, 8)
{
[CTypeDetails("Pointer<SoundIoDevice>")] public System.IntPtr @device;
public SoundIoFormat @format;
public int @sample_rate;
public SoundIoChannelLayout @layout;
public double @software_latency;
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
[CTypeDetails("Pointer<void (SoundIoInStream *, int, int)>")] public delegate7 @read_callback;
[CTypeDetails("Pointer<void (SoundIoInStream *)>")] public delegate8 @overflow_callback;
[CTypeDetails("Pointer<void (SoundIoInStream *, int)>")] public delegate9 @error_callback;
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
public bool @non_terminal_hint;
public int @bytes_per_frame;
public int @bytes_per_sample;
public int @layout_error;
}
[StructLayout(LayoutKind.Sequential)]
struct SoundIoRingBuffer // soundio.h (1170, 8)
{
}
partial class Natives
{
const string LibraryName = "libsoundio";
// function soundio_version_string - soundio.h (682, 28)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_version_string();
// function soundio_version_major - soundio.h (684, 20)
[DllImport(LibraryName)]
internal static extern int soundio_version_major();
// function soundio_version_minor - soundio.h (686, 20)
[DllImport(LibraryName)]
internal static extern int soundio_version_minor();
// function soundio_version_patch - soundio.h (688, 20)
[DllImport(LibraryName)]
internal static extern int soundio_version_patch();
// function soundio_create - soundio.h (694, 32)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_create();
// function soundio_destroy - soundio.h (695, 21)
[DllImport(LibraryName)]
internal static extern void soundio_destroy([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_connect - soundio.h (705, 20)
[DllImport(LibraryName)]
internal static extern int soundio_connect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_connect_backend - soundio.h (717, 20)
[DllImport(LibraryName)]
internal static extern int soundio_connect_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, SoundIoBackend @backend);
// function soundio_disconnect - soundio.h (718, 21)
[DllImport(LibraryName)]
internal static extern void soundio_disconnect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_strerror - soundio.h (721, 28)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_strerror(int @error);
// function soundio_backend_name - soundio.h (723, 28)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_backend_name(SoundIoBackend @backend);
// function soundio_backend_count - soundio.h (726, 20)
[DllImport(LibraryName)]
internal static extern int soundio_backend_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_get_backend - soundio.h (729, 36)
[DllImport(LibraryName)]
internal static extern SoundIoBackend soundio_get_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
// function soundio_have_backend - soundio.h (732, 21)
[DllImport(LibraryName)]
internal static extern bool soundio_have_backend(SoundIoBackend @backend);
// function soundio_flush_events - soundio.h (756, 21)
[DllImport(LibraryName)]
internal static extern void soundio_flush_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_wait_events - soundio.h (760, 21)
[DllImport(LibraryName)]
internal static extern void soundio_wait_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_wakeup - soundio.h (763, 21)
[DllImport(LibraryName)]
internal static extern void soundio_wakeup([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_force_device_scan - soundio.h (780, 21)
[DllImport(LibraryName)]
internal static extern void soundio_force_device_scan([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_channel_layout_equal - soundio.h (787, 21)
[DllImport(LibraryName)]
internal static extern bool soundio_channel_layout_equal([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @b);
// function soundio_get_channel_name - soundio.h (791, 28)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_get_channel_name(SoundIoChannelId @id);
// function soundio_parse_channel_id - soundio.h (795, 38)
[DllImport(LibraryName)]
internal static extern SoundIoChannelId soundio_parse_channel_id([CTypeDetails("Pointer<byte>")]System.IntPtr @str, int @str_len);
// function soundio_channel_layout_builtin_count - soundio.h (798, 20)
[DllImport(LibraryName)]
internal static extern int soundio_channel_layout_builtin_count();
// function soundio_channel_layout_get_builtin - soundio.h (803, 51)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_channel_layout_get_builtin(int @index);
// function soundio_channel_layout_get_default - soundio.h (806, 51)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_channel_layout_get_default(int @channel_count);
// function soundio_channel_layout_find_channel - soundio.h (809, 20)
[DllImport(LibraryName)]
internal static extern int soundio_channel_layout_find_channel([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout, SoundIoChannelId @channel);
// function soundio_channel_layout_detect_builtin - soundio.h (814, 21)
[DllImport(LibraryName)]
internal static extern bool soundio_channel_layout_detect_builtin([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
// function soundio_best_matching_channel_layout - soundio.h (819, 51)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_best_matching_channel_layout([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @preferred_layouts, int @preferred_layout_count, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @available_layouts, int @available_layout_count);
// function soundio_sort_channel_layouts - soundio.h (824, 21)
[DllImport(LibraryName)]
internal static extern void soundio_sort_channel_layouts([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layouts, int @layout_count);
// function soundio_get_bytes_per_sample - soundio.h (830, 20)
[DllImport(LibraryName)]
internal static extern int soundio_get_bytes_per_sample(SoundIoFormat @format);
// function soundio_get_bytes_per_frame - soundio.h (833, 19)
[DllImport(LibraryName)]
internal static extern int soundio_get_bytes_per_frame(SoundIoFormat @format, int @channel_count);
// function soundio_get_bytes_per_second - soundio.h (838, 19)
[DllImport(LibraryName)]
internal static extern int soundio_get_bytes_per_second(SoundIoFormat @format, int @channel_count, int @sample_rate);
// function soundio_format_string - soundio.h (845, 29)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_format_string(SoundIoFormat @format);
// function soundio_input_device_count - soundio.h (861, 20)
[DllImport(LibraryName)]
internal static extern int soundio_input_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_output_device_count - soundio.h (864, 20)
[DllImport(LibraryName)]
internal static extern int soundio_output_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_get_input_device - soundio.h (870, 38)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_get_input_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
// function soundio_get_output_device - soundio.h (875, 38)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_get_output_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
// function soundio_default_input_device_index - soundio.h (880, 20)
[DllImport(LibraryName)]
internal static extern int soundio_default_input_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_default_output_device_index - soundio.h (885, 20)
[DllImport(LibraryName)]
internal static extern int soundio_default_output_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
// function soundio_device_ref - soundio.h (888, 21)
[DllImport(LibraryName)]
internal static extern void soundio_device_ref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
// function soundio_device_unref - soundio.h (891, 21)
[DllImport(LibraryName)]
internal static extern void soundio_device_unref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
// function soundio_device_equal - soundio.h (895, 21)
[DllImport(LibraryName)]
internal static extern bool soundio_device_equal([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @b);
// function soundio_device_sort_channel_layouts - soundio.h (900, 21)
[DllImport(LibraryName)]
internal static extern void soundio_device_sort_channel_layouts([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
// function soundio_device_supports_format - soundio.h (904, 21)
[DllImport(LibraryName)]
internal static extern bool soundio_device_supports_format([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, SoundIoFormat @format);
// function soundio_device_supports_layout - soundio.h (909, 21)
[DllImport(LibraryName)]
internal static extern bool soundio_device_supports_layout([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
// function soundio_device_supports_sample_rate - soundio.h (914, 21)
[DllImport(LibraryName)]
internal static extern bool soundio_device_supports_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
// function soundio_device_nearest_sample_rate - soundio.h (919, 20)
[DllImport(LibraryName)]
internal static extern int soundio_device_nearest_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
// function soundio_outstream_create - soundio.h (929, 41)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_outstream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
// function soundio_outstream_destroy - soundio.h (931, 21)
[DllImport(LibraryName)]
internal static extern void soundio_outstream_destroy([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
// function soundio_outstream_open - soundio.h (954, 20)
[DllImport(LibraryName)]
internal static extern int soundio_outstream_open([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
// function soundio_outstream_start - soundio.h (965, 20)
[DllImport(LibraryName)]
internal static extern int soundio_outstream_start([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
// function soundio_outstream_begin_write - soundio.h (997, 20)
[DllImport(LibraryName)]
internal static extern int soundio_outstream_begin_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
// function soundio_outstream_end_write - soundio.h (1009, 20)
[DllImport(LibraryName)]
internal static extern int soundio_outstream_end_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
// function soundio_outstream_clear_buffer - soundio.h (1024, 20)
[DllImport(LibraryName)]
internal static extern int soundio_outstream_clear_buffer([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
// function soundio_outstream_pause - soundio.h (1045, 20)
[DllImport(LibraryName)]
internal static extern int soundio_outstream_pause([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, bool @pause);
// function soundio_outstream_get_latency - soundio.h (1058, 20)
[DllImport(LibraryName)]
internal static extern int soundio_outstream_get_latency([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
// function soundio_outstream_set_volume - soundio.h (1061, 20)
[DllImport(LibraryName)]
internal static extern int soundio_outstream_set_volume([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, double @volume);
// function soundio_instream_create - soundio.h (1071, 40)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_instream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
// function soundio_instream_destroy - soundio.h (1073, 21)
[DllImport(LibraryName)]
internal static extern void soundio_instream_destroy([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
// function soundio_instream_open - soundio.h (1093, 20)
[DllImport(LibraryName)]
internal static extern int soundio_instream_open([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
// function soundio_instream_start - soundio.h (1102, 20)
[DllImport(LibraryName)]
internal static extern int soundio_instream_start([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
// function soundio_instream_begin_read - soundio.h (1133, 20)
[DllImport(LibraryName)]
internal static extern int soundio_instream_begin_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
// function soundio_instream_end_read - soundio.h (1143, 20)
[DllImport(LibraryName)]
internal static extern int soundio_instream_end_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
// function soundio_instream_pause - soundio.h (1156, 20)
[DllImport(LibraryName)]
internal static extern int soundio_instream_pause([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, bool @pause);
// function soundio_instream_get_latency - soundio.h (1166, 20)
[DllImport(LibraryName)]
internal static extern int soundio_instream_get_latency([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
// function soundio_ring_buffer_create - soundio.h (1181, 42)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_ring_buffer_create([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @requested_capacity);
// function soundio_ring_buffer_destroy - soundio.h (1182, 21)
[DllImport(LibraryName)]
internal static extern void soundio_ring_buffer_destroy([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
// function soundio_ring_buffer_capacity - soundio.h (1186, 20)
[DllImport(LibraryName)]
internal static extern int soundio_ring_buffer_capacity([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
// function soundio_ring_buffer_write_ptr - soundio.h (1189, 22)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_ring_buffer_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
// function soundio_ring_buffer_advance_write_ptr - soundio.h (1191, 21)
[DllImport(LibraryName)]
internal static extern void soundio_ring_buffer_advance_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
// function soundio_ring_buffer_read_ptr - soundio.h (1194, 22)
[DllImport(LibraryName)]
internal static extern System.IntPtr soundio_ring_buffer_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
// function soundio_ring_buffer_advance_read_ptr - soundio.h (1196, 21)
[DllImport(LibraryName)]
internal static extern void soundio_ring_buffer_advance_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
// function soundio_ring_buffer_fill_count - soundio.h (1199, 20)
[DllImport(LibraryName)]
internal static extern int soundio_ring_buffer_fill_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
// function soundio_ring_buffer_free_count - soundio.h (1202, 20)
[DllImport(LibraryName)]
internal static extern int soundio_ring_buffer_free_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
// function soundio_ring_buffer_clear - soundio.h (1205, 21)
[DllImport(LibraryName)]
internal static extern void soundio_ring_buffer_clear([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
}
class Delegates
{
public delegate void delegate0(System.IntPtr p0);
public delegate void delegate1(System.IntPtr p0, int p1);
public delegate void delegate2();
public delegate void delegate3(System.IntPtr p0);
public delegate void delegate4(System.IntPtr p0, int p1, int p2);
public delegate void delegate5(System.IntPtr p0);
public delegate void delegate6(System.IntPtr p0, int p1);
public delegate void delegate7(System.IntPtr p0, int p1, int p2);
public delegate void delegate8(System.IntPtr p0);
public delegate void delegate9(System.IntPtr p0, int p1);
}
public struct Pointer<T>
{
public IntPtr Handle;
public static implicit operator IntPtr(Pointer<T> value) { return value.Handle; }
public static implicit operator Pointer<T>(IntPtr value) { return new Pointer<T>(value); }
public Pointer(IntPtr handle)
{
Handle = handle;
}
public override bool Equals(object obj)
{
return obj is Pointer<T> && this == (Pointer<T>)obj;
}
public override int GetHashCode()
{
return (int)Handle;
}
public static bool operator ==(Pointer<T> p1, Pointer<T> p2)
{
return p1.Handle == p2.Handle;
}
public static bool operator !=(Pointer<T> p1, Pointer<T> p2)
{
return p1.Handle != p2.Handle;
}
}
public struct ArrayOf<T> { }
public struct ConstArrayOf<T> { }
public class CTypeDetailsAttribute : Attribute
{
public CTypeDetailsAttribute(string value)
{
Value = value;
}
public string Value { get; set; }
}
}

View File

@ -1,19 +1,20 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Backends.SoundIo.Native;
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Memory;
using SoundIOSharp;
using System;
using System.Collections.Concurrent;
using System.Threading;
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
namespace Ryujinx.Audio.Backends.SoundIo
{
public class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly SoundIO _audioContext;
private readonly SoundIODevice _audioDevice;
private readonly SoundIoContext _audioContext;
private readonly SoundIoDeviceContext _audioDevice;
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
private readonly ConcurrentDictionary<SoundIoHardwareDeviceSession, byte> _sessions;
@ -21,7 +22,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
public SoundIoHardwareDeviceDriver()
{
_audioContext = new SoundIO();
_audioContext = SoundIoContext.Create();
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
_sessions = new ConcurrentDictionary<SoundIoHardwareDeviceSession, byte>();
@ -29,24 +30,23 @@ namespace Ryujinx.Audio.Backends.SoundIo
_audioContext.Connect();
_audioContext.FlushEvents();
_audioDevice = FindNonRawDefaultAudioDevice(_audioContext, true);
_audioDevice = FindValidAudioDevice(_audioContext, true);
}
public static bool IsSupported => IsSupportedInternal();
private static bool IsSupportedInternal()
{
SoundIO context = null;
SoundIODevice device = null;
SoundIOOutStream stream = null;
SoundIoContext context = null;
SoundIoDeviceContext device = null;
SoundIoOutStreamContext stream = null;
bool backendDisconnected = false;
try
{
context = new SoundIO();
context.OnBackendDisconnect = (i) =>
context = SoundIoContext.Create();
context.OnBackendDisconnect = err =>
{
backendDisconnected = true;
};
@ -64,7 +64,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
return false;
}
device = FindNonRawDefaultAudioDevice(context);
device = FindValidAudioDevice(context);
if (device == null || backendDisconnected)
{
@ -86,30 +86,23 @@ namespace Ryujinx.Audio.Backends.SoundIo
}
finally
{
if (stream != null)
{
stream.Dispose();
}
if (context != null)
{
context.Dispose();
}
stream?.Dispose();
context?.Dispose();
}
}
private static SoundIODevice FindNonRawDefaultAudioDevice(SoundIO audioContext, bool fallback = false)
private static SoundIoDeviceContext FindValidAudioDevice(SoundIoContext audioContext, bool fallback = false)
{
SoundIODevice defaultAudioDevice = audioContext.GetOutputDevice(audioContext.DefaultOutputDeviceIndex);
SoundIoDeviceContext defaultAudioDevice = audioContext.GetOutputDevice(audioContext.DefaultOutputDeviceIndex);
if (!defaultAudioDevice.IsRaw)
{
return defaultAudioDevice;
}
for (int i = 0; i < audioContext.BackendCount; i++)
for (int i = 0; i < audioContext.OutputDeviceCount; i++)
{
SoundIODevice audioDevice = audioContext.GetOutputDevice(i);
SoundIoDeviceContext audioDevice = audioContext.GetOutputDevice(i);
if (audioDevice.Id == defaultAudioDevice.Id && !audioDevice.IsRaw)
{
@ -161,22 +154,22 @@ namespace Ryujinx.Audio.Backends.SoundIo
return _sessions.TryRemove(session, out _);
}
public static SoundIOFormat GetSoundIoFormat(SampleFormat format)
public static SoundIoFormat GetSoundIoFormat(SampleFormat format)
{
return format switch
{
SampleFormat.PcmInt8 => SoundIOFormat.S8,
SampleFormat.PcmInt16 => SoundIOFormat.S16LE,
SampleFormat.PcmInt24 => SoundIOFormat.S24LE,
SampleFormat.PcmInt32 => SoundIOFormat.S32LE,
SampleFormat.PcmFloat => SoundIOFormat.Float32LE,
SampleFormat.PcmInt8 => SoundIoFormat.S8,
SampleFormat.PcmInt16 => SoundIoFormat.S16LE,
SampleFormat.PcmInt24 => SoundIoFormat.S24LE,
SampleFormat.PcmInt32 => SoundIoFormat.S32LE,
SampleFormat.PcmFloat => SoundIoFormat.Float32LE,
_ => throw new ArgumentException ($"Unsupported sample format {format}"),
};
}
internal SoundIOOutStream OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount)
internal SoundIoOutStreamContext OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount)
{
SoundIOFormat driverSampleFormat = GetSoundIoFormat(requestedSampleFormat);
SoundIoFormat driverSampleFormat = GetSoundIoFormat(requestedSampleFormat);
if (!_audioDevice.SupportsSampleRate((int)requestedSampleRate))
{
@ -193,10 +186,10 @@ namespace Ryujinx.Audio.Backends.SoundIo
throw new ArgumentException($"This sound device does not support channel count {requestedChannelCount}");
}
SoundIOOutStream result = _audioDevice.CreateOutStream();
SoundIoOutStreamContext result = _audioDevice.CreateOutStream();
result.Name = "Ryujinx";
result.Layout = SoundIOChannelLayout.GetDefault((int)requestedChannelCount);
result.Layout = SoundIoChannelLayout.GetDefaultValue((int)requestedChannelCount);
result.Format = driverSampleFormat;
result.SampleRate = (int)requestedSampleRate;

View File

@ -1,11 +1,12 @@
using Ryujinx.Audio.Backends.Common;
using Ryujinx.Audio.Backends.SoundIo.Native;
using Ryujinx.Audio.Common;
using Ryujinx.Memory;
using SoundIOSharp;
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Threading;
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
namespace Ryujinx.Audio.Backends.SoundIo
{
@ -13,7 +14,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
{
private SoundIoHardwareDeviceDriver _driver;
private ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
private SoundIOOutStream _outputStream;
private SoundIoOutStreamContext _outputStream;
private DynamicRingBuffer _ringBuffer;
private ulong _playedSampleCount;
private ManualResetEvent _updateRequiredEvent;
@ -106,9 +107,9 @@ namespace Ryujinx.Audio.Backends.SoundIo
return;
}
SoundIOChannelAreas areas = _outputStream.BeginWrite(ref frameCount);
Span<SoundIoChannelArea> areas = _outputStream.BeginWrite(ref frameCount);
int channelCount = areas.ChannelCount;
int channelCount = areas.Length;
byte[] samples = new byte[frameCount * bytesPerFrame];
@ -117,12 +118,12 @@ namespace Ryujinx.Audio.Backends.SoundIo
// This is a huge ugly block of code, but we save
// a significant amount of time over the generic
// loop that handles other channel counts.
// TODO: Is this still right in 2021?
// TODO: Is this still right in 2022?
// Mono
if (channelCount == 1)
{
SoundIOChannelArea area = areas.GetArea(0);
ref SoundIoChannelArea area = ref areas[0];
fixed (byte* srcptr = samples)
{
@ -167,8 +168,8 @@ namespace Ryujinx.Audio.Backends.SoundIo
// Stereo
else if (channelCount == 2)
{
SoundIOChannelArea area1 = areas.GetArea(0);
SoundIOChannelArea area2 = areas.GetArea(1);
ref SoundIoChannelArea area1 = ref areas[0];
ref SoundIoChannelArea area2 = ref areas[1];
fixed (byte* srcptr = samples)
{
@ -233,12 +234,12 @@ namespace Ryujinx.Audio.Backends.SoundIo
// Surround
else if (channelCount == 6)
{
SoundIOChannelArea area1 = areas.GetArea(0);
SoundIOChannelArea area2 = areas.GetArea(1);
SoundIOChannelArea area3 = areas.GetArea(2);
SoundIOChannelArea area4 = areas.GetArea(3);
SoundIOChannelArea area5 = areas.GetArea(4);
SoundIOChannelArea area6 = areas.GetArea(5);
ref SoundIoChannelArea area1 = ref areas[0];
ref SoundIoChannelArea area2 = ref areas[1];
ref SoundIoChannelArea area3 = ref areas[2];
ref SoundIoChannelArea area4 = ref areas[3];
ref SoundIoChannelArea area5 = ref areas[4];
ref SoundIoChannelArea area6 = ref areas[5];
fixed (byte* srcptr = samples)
{
@ -367,24 +368,18 @@ namespace Ryujinx.Audio.Backends.SoundIo
// Every other channel count
else
{
SoundIOChannelArea[] channels = new SoundIOChannelArea[channelCount];
// Obtain the channel area for each channel
for (int i = 0; i < channelCount; i++)
{
channels[i] = areas.GetArea(i);
}
fixed (byte* srcptr = samples)
{
for (int frame = 0; frame < frameCount; frame++)
for (int channel = 0; channel < areas.ChannelCount; channel++)
{
for (int channel = 0; channel < areas.Length; channel++)
{
// Copy channel by channel, frame by frame. This is slow!
Unsafe.CopyBlockUnaligned((byte*)channels[channel].Pointer, srcptr + (frame * bytesPerFrame) + (channel * bytesPerSample), bytesPerSample);
Unsafe.CopyBlockUnaligned((byte*)areas[channel].Pointer, srcptr + (frame * bytesPerFrame) + (channel * bytesPerSample), bytesPerSample);
channels[channel].Pointer += channels[channel].Step;
areas[channel].Pointer += areas[channel].Step;
}
}
}
}

View File

@ -17,7 +17,7 @@ using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.System;
using Ryujinx.Common.SystemInterop;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu;

View File

@ -280,7 +280,7 @@
"ControllerSettingsRemoveProfileToolTip": "Remove Profile",
"ControllerSettingsSaveProfileToolTip": "Save Profile",
"MenuBarFileToolsTakeScreenshot": "Take Screenshot",
"MenuBarFileToolsHideUi": "Hide Ui",
"MenuBarFileToolsHideUi": "Hide UI",
"GameListContextMenuToggleFavorite": "Toggle Favorite",
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
"SettingsTabGeneralTheme": "Theme",
@ -315,7 +315,7 @@
"DialogUpdaterConvertFailedMessage": "Failed to convert the current Ryujinx version.",
"DialogUpdaterCancelUpdateMessage": "Cancelling Update!",
"DialogUpdaterAlreadyOnLatestVersionMessage": "You are already using the most updated version of Ryujinx!",
"DialogUpdaterFailedToGetVersionMessage": "An error has occurred when trying to get release information from Github Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes.",
"DialogUpdaterFailedToGetVersionMessage": "An error has occurred when trying to get release information from GitHub Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes.",
"DialogUpdaterConvertFailedGithubMessage": "Failed to convert the received Ryujinx version from Github Release.",
"DialogUpdaterDownloadingMessage": "Downloading Update...",
"DialogUpdaterExtractionMessage": "Extracting Update...",

View File

@ -161,6 +161,7 @@
<Style Selector="MenuItem">
<Setter Property="Height" Value="{DynamicResource MenuItemHeight}" />
<Setter Property="Padding" Value="{DynamicResource MenuItemPadding}" />
<Setter Property="FontSize" Value="12" />
</Style>
<Style Selector="MenuItem:selected /template/ Border#root">
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />

View File

@ -8,7 +8,7 @@ namespace Ryujinx.Ava.Ui.Helper
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
[SupportedOSPlatform("macos")]
static class MetalHelper
static partial class MetalHelper
{
private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
@ -100,28 +100,28 @@ namespace Ryujinx.Ava.Ui.Helper
// TODO
}
[DllImport(LibObjCImport)]
private static unsafe extern IntPtr sel_registerName(byte* data);
[LibraryImport(LibObjCImport)]
private static unsafe partial IntPtr sel_registerName(byte* data);
[DllImport(LibObjCImport)]
private static unsafe extern IntPtr objc_getClass(byte* data);
[LibraryImport(LibObjCImport)]
private static unsafe partial IntPtr objc_getClass(byte* data);
[DllImport(LibObjCImport)]
private static extern void objc_msgSend(IntPtr receiver, Selector selector);
[LibraryImport(LibObjCImport)]
private static partial void objc_msgSend(IntPtr receiver, Selector selector);
[DllImport(LibObjCImport)]
private static extern void objc_msgSend(IntPtr receiver, Selector selector, byte value);
[LibraryImport(LibObjCImport)]
private static partial void objc_msgSend(IntPtr receiver, Selector selector, byte value);
[DllImport(LibObjCImport)]
private static extern void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
[LibraryImport(LibObjCImport)]
private static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
[DllImport(LibObjCImport)]
private static extern void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
[LibraryImport(LibObjCImport)]
private static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
[DllImport(LibObjCImport)]
private static extern void objc_msgSend(IntPtr receiver, Selector selector, double value);
[LibraryImport(LibObjCImport)]
private static partial void objc_msgSend(IntPtr receiver, Selector selector, double value);
[DllImport(LibObjCImport, EntryPoint = "objc_msgSend")]
private static extern IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
[LibraryImport(LibObjCImport, EntryPoint = "objc_msgSend")]
private static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
}
}

View File

@ -7,8 +7,7 @@ namespace Ryujinx.Ava.Input
{
internal static class AvaloniaKeyboardMappingHelper
{
private static readonly AvaKey[] _keyMapping = new AvaKey[(int)Key.Count]
{
private static readonly AvaKey[] _keyMapping = {
// NOTE: Invalid
AvaKey.None,
@ -151,16 +150,16 @@ namespace Ryujinx.Ava.Input
static AvaloniaKeyboardMappingHelper()
{
var inputKeys = Enum.GetValues(typeof(Key));
var inputKeys = Enum.GetValues<Key>();
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
_avaKeyMapping = new Dictionary<AvaKey, Key>();
foreach (var key in inputKeys)
{
if (TryGetAvaKey((Key)key, out var index))
if (TryGetAvaKey(key, out var index))
{
_avaKeyMapping[index] = (Key)key;
_avaKeyMapping[index] = key;
}
}
}

View File

@ -11,6 +11,7 @@ using Ryujinx.Ava.Ui.Controls;
using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Ui.Common.Helper;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -278,14 +279,15 @@ namespace Ryujinx.Modules
{
string ryuName = Path.GetFileName(Environment.ProcessPath);
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
var ryuArg = Environment.GetCommandLineArgs().Skip(1);
if (!OperatingSystem.IsWindows())
if (!Path.Exists(ryuExe))
{
chmod(ryuExe, Convert.ToUInt32("0777", 8));
ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, OperatingSystem.IsWindows() ? "Ryujinx.exe" : "Ryujinx");
}
Process.Start(ryuExe, ryuArg);
SetFileExecutable(ryuExe);
Process.Start(ryuExe, CommandLineState.Arguments);
Environment.Exit(0);
}
@ -355,7 +357,7 @@ namespace Ryujinx.Modules
list[index] = args.Result;
Interlocked.Increment(ref completedRequests);
if (Interlocked.Equals(completedRequests, ConnectionCount))
if (Equals(completedRequests, ConnectionCount))
{
byte[] mergedFileBytes = new byte[_buildSize];
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++)
@ -456,16 +458,19 @@ namespace Ryujinx.Modules
worker.Start();
}
[DllImport("libc", SetLastError = true)]
private static extern int chmod(string path, uint mode);
private static void SetUnixPermissions()
private static void SetFileExecutable(string path)
{
string ryuBin = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
const UnixFileMode ExecutableFileMode = UnixFileMode.UserExecute |
UnixFileMode.UserWrite |
UnixFileMode.UserRead |
UnixFileMode.GroupRead |
UnixFileMode.GroupWrite |
UnixFileMode.OtherRead |
UnixFileMode.OtherWrite;
if (!OperatingSystem.IsWindows())
if (!OperatingSystem.IsWindows() && File.Exists(path))
{
chmod(ryuBin, 493);
File.SetUnixFileMode(path, ExecutableFileMode);
}
}
@ -586,7 +591,7 @@ namespace Ryujinx.Modules
Directory.Delete(UpdateDir, true);
SetUnixPermissions();
SetFileExecutable(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"));
UpdateSuccessful = true;

View File

@ -6,7 +6,7 @@ using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging;
using Ryujinx.Common.System;
using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.SystemInfo;
using Ryujinx.Modules;
using Ryujinx.SDL2.Common;
@ -20,7 +20,7 @@ using System.Threading.Tasks;
namespace Ryujinx.Ava
{
internal class Program
internal partial class Program
{
public static double WindowScaleFactor { get; set; }
public static double DesktopScaleFactor { get; set; } = 1.0;
@ -28,8 +28,8 @@ namespace Ryujinx.Ava
public static string ConfigurationPath { get; private set; }
public static bool PreviewerDetached { get; private set; }
[DllImport("user32.dll", SetLastError = true)]
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
[LibraryImport("user32.dll", SetLastError = true)]
public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
private const uint MB_ICONWARNING = 0x30;
@ -82,8 +82,8 @@ namespace Ryujinx.Ava
Console.Title = $"Ryujinx Console {Version}";
// Hook unhandled exception and process exit events.
AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
AppDomain.CurrentDomain.UnhandledException += (sender, e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.ProcessExit += (sender, e) => Exit();
// Setup base data directory.
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
@ -18,29 +18,31 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.18" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
<PackageReference Include="DynamicData" Version="7.12.8" />
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />
<PackageReference Include="Avalonia" />
<PackageReference Include="Avalonia.Desktop" />
<PackageReference Include="Avalonia.Diagnostics" />
<PackageReference Include="Avalonia.Controls.DataGrid" />
<PackageReference Include="Avalonia.Markup.Xaml.Loader" />
<PackageReference Include="Avalonia.Svg" />
<PackageReference Include="Avalonia.Svg.Skia" />
<PackageReference Include="jp2masa.Avalonia.Flexbox" />
<PackageReference Include="DynamicData" />
<PackageReference Include="FluentAvaloniaUI" />
<PackageReference Include="XamlNameReferenceGenerator" />
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.osx" Version="5.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'" />
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
<PackageReference Include="SPB" Version="0.0.4-build28" />
<PackageReference Include="SharpZipLib" Version="1.4.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
<PackageReference Include="OpenTK.Core" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'" />
<PackageReference Include="Silk.NET.Vulkan" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
<PackageReference Include="SPB" />
<PackageReference Include="SharpZipLib" />
<PackageReference Include="SixLabors.ImageSharp" />
<!--NOTE: DO NOT REMOVE, THIS IS REQUIRED AS A RESULT OF A TRIMMING ISSUE IN AVALONIA -->
<PackageReference Include="System.Drawing.Common" />
</ItemGroup>
<ItemGroup>

View File

@ -66,7 +66,7 @@ namespace Ryujinx.Ava.Ui.Applet
});
}
private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, Avalonia.Input.KeyEventArgs e)
private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, KeyEventArgs e)
{
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);

View File

@ -45,7 +45,7 @@
TextWrapping="Wrap" />
<TextBox
Name="Input"
Grid.Row="2"
Grid.Row="3"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"

View File

@ -111,7 +111,7 @@ namespace Ryujinx.Ava.Ui.Controls
overlay.Position = window.PointToScreen(new Point());
await contentDialog.ShowAsync();
await contentDialog.ShowAsync(overlay);
contentDialog.Closed -= handler;
overlay.Close();
};

View File

@ -222,7 +222,7 @@ namespace Ryujinx.Ava.Ui.Controls
content.MinHeight = 80;
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Avalonia.Thickness(10) };
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Thickness(10) };
icon.FontSize = 40;
icon.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
Grid.SetColumn(icon, 0);
@ -232,15 +232,15 @@ namespace Ryujinx.Ava.Ui.Controls
TextBlock primaryLabel = new TextBlock()
{
Text = primaryText,
Margin = new Avalonia.Thickness(5),
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
Margin = new Thickness(5),
TextWrapping = TextWrapping.Wrap,
MaxWidth = 450
};
TextBlock secondaryLabel = new TextBlock()
{
Text = secondaryText,
Margin = new Avalonia.Thickness(5),
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
Margin = new Thickness(5),
TextWrapping = TextWrapping.Wrap,
MaxWidth = 450
};

View File

@ -39,7 +39,7 @@ namespace Ryujinx.Ava.Ui.Controls
public EmbeddedWindow()
{
var stateObserverable = this.GetObservable(Control.BoundsProperty);
var stateObserverable = this.GetObservable(BoundsProperty);
stateObserverable.Subscribe(StateChanged);
@ -125,9 +125,9 @@ namespace Ryujinx.Ava.Ui.Controls
{
cbSize = Marshal.SizeOf<WNDCLASSEX>(),
hInstance = GetModuleHandle(null),
lpfnWndProc = _wndProcDelegate,
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate),
style = ClassStyles.CS_OWNDC,
lpszClassName = _className,
lpszClassName = Marshal.StringToHGlobalUni(_className),
hCursor = LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IDC_ARROW)
};
@ -148,7 +148,9 @@ namespace Ryujinx.Ava.Ui.Controls
IntPtr.Zero);
WindowHandle = handle;
Marshal.FreeHGlobal(wndClassEx.lpszClassName);
return new PlatformHandle(WindowHandle, "HWND");
}
@ -165,7 +167,7 @@ namespace Ryujinx.Ava.Ui.Controls
isLeft = msg == WindowsMessages.LBUTTONDOWN;
this.RaiseEvent(new PointerPressedEventArgs(
this,
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
new Pointer(0, PointerType.Mouse, true),
root,
this.TranslatePoint(point, root).Value,
(ulong)Environment.TickCount64,
@ -177,7 +179,7 @@ namespace Ryujinx.Ava.Ui.Controls
isLeft = msg == WindowsMessages.LBUTTONUP;
this.RaiseEvent(new PointerReleasedEventArgs(
this,
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
new Pointer(0, PointerType.Mouse, true),
root,
this.TranslatePoint(point, root).Value,
(ulong)Environment.TickCount64,
@ -189,7 +191,7 @@ namespace Ryujinx.Ava.Ui.Controls
this.RaiseEvent(new PointerEventArgs(
PointerMovedEvent,
this,
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
new Pointer(0, PointerType.Mouse, true),
root,
this.TranslatePoint(point, root).Value,
(ulong)Environment.TickCount64,

View File

@ -138,6 +138,9 @@
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
</Style>
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
<Setter Property="MinHeight" Value="100" />
</Style>
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
</Style>

View File

@ -5,7 +5,7 @@ using System.Runtime.Versioning;
namespace Ryujinx.Ava.Ui.Controls
{
[SupportedOSPlatform("windows")]
internal class Win32NativeInterop
internal partial class Win32NativeInterop
{
[Flags]
public enum ClassStyles : uint
@ -48,58 +48,52 @@ namespace Ryujinx.Ava.Ui.Controls
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate IntPtr WindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[StructLayout(LayoutKind.Sequential)]
public struct WNDCLASSEX
{
public int cbSize;
public ClassStyles style;
[MarshalAs(UnmanagedType.FunctionPtr)]
public WindowProc lpfnWndProc; // not WndProc
public IntPtr lpfnWndProc; // not WndProc
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszMenuName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszClassName;
public IntPtr lpszMenuName;
public IntPtr lpszClassName;
public IntPtr hIconSm;
public static WNDCLASSEX Create()
public WNDCLASSEX()
{
return new WNDCLASSEX
{
cbSize = Marshal.SizeOf<WNDCLASSEX>()
};
cbSize = Marshal.SizeOf<WNDCLASSEX>();
}
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern ushort RegisterClassEx(ref WNDCLASSEX param);
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
public static partial ushort RegisterClassEx(ref WNDCLASSEX param);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance);
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "UnregisterClassW")]
public static partial short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
[LibraryImport("user32.dll", EntryPoint = "DefWindowProcW")]
public static partial IntPtr DefWindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[LibraryImport("kernel32.dll", EntryPoint = "GetModuleHandleA")]
public static partial IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPStr)] string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
[LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DestroyWindow(IntPtr hwnd);
public static partial bool DestroyWindow(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName);
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "LoadCursorA")]
public static partial IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateWindowEx(
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowExW")]
public static partial IntPtr CreateWindowEx(
uint dwExStyle,
string lpClassName,
string lpWindowName,
[MarshalAs(UnmanagedType.LPWStr)] string lpClassName,
[MarshalAs(UnmanagedType.LPWStr)] string lpWindowName,
WindowStyles dwStyle,
int x,
int y,

View File

@ -545,7 +545,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
config = new StandardKeyboardInputConfig
{
Version = Ryujinx.Common.Configuration.Hid.InputConfig.CurrentVersion,
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = id,
ControllerType = ControllerType.ProController,
@ -600,7 +600,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
config = new StandardControllerInputConfig
{
Version = Ryujinx.Common.Configuration.Hid.InputConfig.CurrentVersion,
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.GamepadSDL2,
Id = id,
ControllerType = ControllerType.ProController,

View File

@ -104,11 +104,11 @@ namespace Ryujinx.Ava.Ui.Windows
var device = ViewModel.Devices[ViewModel.Device];
if (device.Type == Models.DeviceType.Keyboard)
if (device.Type == DeviceType.Keyboard)
{
assigner = new KeyboardKeyAssigner((IKeyboard)ViewModel.SelectedGamepad);
}
else if (device.Type == Models.DeviceType.Controller)
else if (device.Type == DeviceType.Controller)
{
assigner = new GamepadButtonAssigner(ViewModel.SelectedGamepad, (ViewModel.Config as StandardControllerInputConfig).TriggerThreshold, forStick);
}

View File

@ -12,9 +12,9 @@
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Title="Ryujinx"
Width="1280"
Height="785"
Height="777"
MinWidth="1092"
MinHeight="680"
MinHeight="672"
d:DesignHeight="720"
d:DesignWidth="1280"
x:CompileBindings="True"
@ -552,9 +552,8 @@
<Grid
Name="StatusBar"
Grid.Row="2"
MinHeight="30"
Height="30"
Margin="0,0"
Margin="0"
MinHeight="22"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Background="{DynamicResource ThemeContentBackgroundColor}"
@ -568,7 +567,7 @@
</Grid.ColumnDefinitions>
<StackPanel
Grid.Column="0"
Margin="10,0"
Margin="5"
VerticalAlignment="Center"
IsVisible="{Binding EnableNonGameRunningControls}">
<Grid Margin="0">
@ -610,14 +609,14 @@
</StackPanel>
<StackPanel
Grid.Column="1"
Margin="10,0"
Margin="0,2"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsVisible="{Binding IsGameRunning}"
Orientation="Horizontal">
<TextBlock
Name="VsyncStatus"
Margin="0,0,5,0"
Margin="5,0,5,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="{Binding VsyncColor}"
@ -628,7 +627,7 @@
<Border
Width="2"
Height="12"
Margin="2,0"
Margin="0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
@ -644,7 +643,7 @@
<Border
Width="2"
Height="12"
Margin="2,0"
Margin="0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
@ -660,13 +659,13 @@
<Border
Width="2"
Height="12"
Margin="2,0"
Margin="0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
<ui:ToggleSplitButton
Name="VolumeStatus"
Padding="5"
Padding="5,0,5,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
@ -679,6 +678,7 @@
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
<Grid Margin="0">
<Slider
MaxHeight="40"
Width="150"
Margin="0"
Padding="0"
@ -697,7 +697,7 @@
<Border
Width="2"
Height="12"
Margin="2,0"
Margin="0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
@ -711,7 +711,7 @@
<Border
Width="2"
Height="12"
Margin="2,0"
Margin="0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
@ -725,7 +725,7 @@
<Border
Width="2"
Height="12"
Margin="2,0"
Margin="0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
@ -739,7 +739,7 @@
<Border
Width="2"
Height="12"
Margin="2,0"
Margin="0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
@ -753,7 +753,7 @@
</StackPanel>
<StackPanel
Grid.Column="3"
Margin="10,0"
Margin="0,0,5,0"
VerticalAlignment="Center"
IsVisible="{Binding ShowFirmwareStatus}"
Orientation="Horizontal">

View File

@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Common.GraphicsDriver
{
static class NVThreadedOptimization
static partial class NVThreadedOptimization
{
private const string ProfileName = "Ryujinx Nvidia Profile";
@ -19,8 +19,8 @@ namespace Ryujinx.Common.GraphicsDriver
private const uint NvAPI_DRS_SaveSettings_ID = 0xFCBC7E14;
private const uint NvAPI_DRS_DestroySession_ID = 0x0DAD9CFF8;
[DllImport("nvapi64")]
private static extern IntPtr nvapi_QueryInterface(uint id);
[LibraryImport("nvapi64")]
private static partial IntPtr nvapi_QueryInterface(uint id);
private delegate int NvAPI_InitializeDelegate();
private static NvAPI_InitializeDelegate NvAPI_Initialize;
@ -152,7 +152,7 @@ namespace Ryujinx.Common.GraphicsDriver
if (ptr != IntPtr.Zero)
{
return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T;
return Marshal.GetDelegateForFunctionPointer<T>(ptr);
}
else
{

View File

@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Runtime.Versioning;
using System.Threading;
@ -12,7 +13,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
/// State for partial unmaps. Intended to be used on Windows.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PartialUnmapState
public partial struct PartialUnmapState
{
public NativeReaderWriterLock PartialUnmapLock;
public int PartialUnmapsCount;
@ -25,20 +26,22 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
public readonly static IntPtr GlobalState;
[SupportedOSPlatform("windows")]
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();
[LibraryImport("kernel32.dll")]
public static partial int GetCurrentThreadId();
[SupportedOSPlatform("windows")]
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenThread(int dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[LibraryImport("kernel32.dll", SetLastError = true)]
private static partial IntPtr OpenThread(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwThreadId);
[SupportedOSPlatform("windows")]
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[LibraryImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs (UnmanagedType.Bool)]
public static partial bool CloseHandle(IntPtr hObject);
[SupportedOSPlatform("windows")]
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode);
[LibraryImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode);
/// <summary>
/// Creates a global static PartialUnmapState and populates the field offsets.

View File

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

View File

@ -8,7 +8,7 @@ using Ryujinx.Common.Logging;
namespace Ryujinx.Common.SystemInfo
{
[SupportedOSPlatform("macos")]
class MacOSSystemInfo : SystemInfo
partial class MacOSSystemInfo : SystemInfo
{
internal MacOSSystemInfo()
{
@ -60,8 +60,8 @@ namespace Ryujinx.Common.SystemInfo
private const string SystemLibraryName = "libSystem.dylib";
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
[LibraryImport(SystemLibraryName, SetLastError = true)]
private static partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
private static int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize)
{
@ -116,11 +116,11 @@ namespace Ryujinx.Common.SystemInfo
return res;
}
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern uint mach_host_self();
[LibraryImport(SystemLibraryName, SetLastError = true)]
private static partial uint mach_host_self();
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int host_page_size(uint host, ref uint out_page_size);
[LibraryImport(SystemLibraryName, SetLastError = true)]
private static partial int host_page_size(uint host, ref uint out_page_size);
[StructLayout(LayoutKind.Sequential, Pack = 8)]
struct VMStatistics64
@ -151,7 +151,7 @@ namespace Ryujinx.Common.SystemInfo
public ulong TotalUncompressedPagesInCompressor;
}
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
[LibraryImport(SystemLibraryName, SetLastError = true)]
private static partial int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
}
}

View File

@ -7,7 +7,7 @@ using Ryujinx.Common.Logging;
namespace Ryujinx.Common.SystemInfo
{
[SupportedOSPlatform("windows")]
class WindowsSystemInfo : SystemInfo
partial class WindowsSystemInfo : SystemInfo
{
internal WindowsSystemInfo()
{
@ -18,7 +18,7 @@ namespace Ryujinx.Common.SystemInfo
private static (ulong Total, ulong Available) GetMemoryStats()
{
MemoryStatusEx memStatus = new MemoryStatusEx();
if (GlobalMemoryStatusEx(memStatus))
if (GlobalMemoryStatusEx(ref memStatus))
{
return (memStatus.TotalPhys, memStatus.AvailPhys); // Bytes
}
@ -45,8 +45,8 @@ namespace Ryujinx.Common.SystemInfo
return Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER").Trim();
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private class MemoryStatusEx
[StructLayout(LayoutKind.Sequential)]
private struct MemoryStatusEx
{
public uint Length;
public uint MemoryLoad;
@ -60,13 +60,13 @@ namespace Ryujinx.Common.SystemInfo
public MemoryStatusEx()
{
Length = (uint)Marshal.SizeOf(typeof(MemoryStatusEx));
Length = (uint)Marshal.SizeOf<MemoryStatusEx>();
}
}
[LibraryImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GlobalMemoryStatusEx([In, Out] MemoryStatusEx lpBuffer);
private static partial bool GlobalMemoryStatusEx(ref MemoryStatusEx lpBuffer);
private static ManagementObjectCollection GetWMIObjects(string scope, string query)
{

View File

@ -1,9 +1,9 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Common.System
namespace Ryujinx.Common.SystemInterop
{
public class DisplaySleep
public partial class DisplaySleep
{
[Flags]
enum EXECUTION_STATE : uint
@ -13,8 +13,8 @@ namespace Ryujinx.Common.System
ES_SYSTEM_REQUIRED = 0x00000001
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
[LibraryImport("kernel32.dll", SetLastError = true)]
private static partial EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
static public void Prevent()
{

View File

@ -1,32 +1,32 @@
using Ryujinx.Common.Logging;
using System;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
namespace Ryujinx.Common.System
namespace Ryujinx.Common.SystemInterop
{
public static class ForceDpiAware
public static partial class ForceDpiAware
{
[DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool SetProcessDPIAware();
private const string X11LibraryName = "libX11.so.6";
[DllImport(X11LibraryName)]
private static extern IntPtr XOpenDisplay(string display);
[LibraryImport(X11LibraryName)]
private static partial IntPtr XOpenDisplay([MarshalAs(UnmanagedType.LPStr)] string display);
[DllImport(X11LibraryName)]
private static extern IntPtr XGetDefault(IntPtr display, string program, string option);
[LibraryImport(X11LibraryName)]
private static partial IntPtr XGetDefault(IntPtr display, [MarshalAs(UnmanagedType.LPStr)] string program, [MarshalAs(UnmanagedType.LPStr)] string option);
[DllImport(X11LibraryName)]
private static extern int XDisplayWidth(IntPtr display, int screenNumber);
[LibraryImport(X11LibraryName)]
private static partial int XDisplayWidth(IntPtr display, int screenNumber);
[DllImport(X11LibraryName)]
private static extern int XDisplayWidthMM(IntPtr display, int screenNumber);
[LibraryImport(X11LibraryName)]
private static partial int XDisplayWidthMM(IntPtr display, int screenNumber);
[DllImport(X11LibraryName)]
private static extern int XCloseDisplay(IntPtr display);
[LibraryImport(X11LibraryName)]
private static partial int XCloseDisplay(IntPtr display);
private static readonly double _standardDpiScale = 96.0;
private static readonly double _maxScaleFactor = 1.25;
@ -51,7 +51,7 @@ namespace Ryujinx.Common.System
{
if (OperatingSystem.IsWindows())
{
userDpiScale = Graphics.FromHwnd(IntPtr.Zero).DpiX;
userDpiScale = GdiPlusHelper.GetDpiX(IntPtr.Zero);
}
else if (OperatingSystem.IsLinux())
{

View File

@ -0,0 +1,76 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Common.SystemInterop
{
[SupportedOSPlatform("windows")]
public static partial class GdiPlusHelper
{
private const string LibraryName = "gdiplus.dll";
private static readonly IntPtr _initToken;
static GdiPlusHelper()
{
CheckStatus(GdiplusStartup(out _initToken, StartupInputEx.Default, out _));
}
private static void CheckStatus(int gdiStatus)
{
if (gdiStatus != 0)
{
throw new Exception($"GDI Status Error: {gdiStatus}");
}
}
private struct StartupInputEx
{
public int GdiplusVersion;
#pragma warning disable CS0649
public IntPtr DebugEventCallback;
public int SuppressBackgroundThread;
public int SuppressExternalCodecs;
public int StartupParameters;
#pragma warning restore CS0649
public static StartupInputEx Default => new StartupInputEx
{
// We assume Windows 8 and upper
GdiplusVersion = 2,
DebugEventCallback = IntPtr.Zero,
SuppressBackgroundThread = 0,
SuppressExternalCodecs = 0,
StartupParameters = 0,
};
}
private struct StartupOutput
{
public IntPtr NotificationHook;
public IntPtr NotificationUnhook;
}
[LibraryImport(LibraryName)]
private static partial int GdiplusStartup(out IntPtr token, in StartupInputEx input, out StartupOutput output);
[LibraryImport(LibraryName)]
private static partial int GdipCreateFromHWND(IntPtr hwnd, out IntPtr graphics);
[LibraryImport(LibraryName)]
private static partial int GdipDeleteGraphics(IntPtr graphics);
[LibraryImport(LibraryName)]
private static partial int GdipGetDpiX(IntPtr graphics, out float dpi);
public static float GetDpiX(IntPtr hwnd)
{
CheckStatus(GdipCreateFromHWND(hwnd, out IntPtr graphicsHandle));
CheckStatus(GdipGetDpiX(graphicsHandle, out float result));
CheckStatus(GdipDeleteGraphics(graphicsHandle));
return result;
}
}
}

View File

@ -4,13 +4,13 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Common.System
namespace Ryujinx.Common.SystemInterop
{
/// <summary>
/// Handle Windows Multimedia timer resolution.
/// </summary>
[SupportedOSPlatform("windows")]
public class WindowsMultimediaTimerResolution : IDisposable
public partial class WindowsMultimediaTimerResolution : IDisposable
{
[StructLayout(LayoutKind.Sequential)]
public struct TimeCaps
@ -19,14 +19,14 @@ namespace Ryujinx.Common.System
public uint wPeriodMax;
};
[DllImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
private static extern uint TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
[LibraryImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
private static partial uint TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
private static extern uint TimeBeginPeriod(uint uMilliseconds);
[LibraryImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
private static partial uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod")]
private static extern uint TimeEndPeriod(uint uMilliseconds);
[LibraryImport("winmm.dll", EntryPoint = "timeEndPeriod")]
private static partial uint TimeEndPeriod(uint uMilliseconds);
private uint _targetResolutionInMilliseconds;
private bool _isActive;

View File

@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Device
{
public class DeviceState<TState> : IDeviceState where TState : unmanaged
public class DeviceState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged
{
private const int RegisterSize = sizeof(int);

View File

@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsBc123Compression;
public readonly bool SupportsBc45Compression;
public readonly bool SupportsBc67Compression;
public readonly bool SupportsEtc2Compression;
public readonly bool Supports3DTextureCompression;
public readonly bool SupportsBgraFormat;
public readonly bool SupportsR4G4Format;
@ -50,6 +51,7 @@ namespace Ryujinx.Graphics.GAL
bool supportsBc123Compression,
bool supportsBc45Compression,
bool supportsBc67Compression,
bool supportsEtc2Compression,
bool supports3DTextureCompression,
bool supportsBgraFormat,
bool supportsR4G4Format,
@ -83,6 +85,7 @@ namespace Ryujinx.Graphics.GAL
SupportsBc123Compression = supportsBc123Compression;
SupportsBc45Compression = supportsBc45Compression;
SupportsBc67Compression = supportsBc67Compression;
SupportsEtc2Compression = supportsEtc2Compression;
Supports3DTextureCompression = supports3DTextureCompression;
SupportsBgraFormat = supportsBgraFormat;
SupportsR4G4Format = supportsR4G4Format;

View File

@ -516,6 +516,27 @@ namespace Ryujinx.Graphics.GAL
return false;
}
/// <summary>
/// Checks if the texture format is an ETC2 format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is an ETC2 format, false otherwise</returns>
public static bool IsEtc2(this Format format)
{
switch (format)
{
case Format.Etc2RgbaSrgb:
case Format.Etc2RgbaUnorm:
case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm:
case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is a BGR format.
/// </summary>

View File

@ -50,186 +50,186 @@ namespace Ryujinx.Graphics.GAL.Multithreading
private static void InitLookup()
{
_lookup[(int)CommandType.Action] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.Action] = (memory, threaded, renderer) =>
ActionCommand.Run(ref GetCommand<ActionCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CreateBuffer] = (memory, threaded, renderer) =>
CreateBufferCommand.Run(ref GetCommand<CreateBufferCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateProgram] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CreateProgram] = (memory, threaded, renderer) =>
CreateProgramCommand.Run(ref GetCommand<CreateProgramCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateSampler] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CreateSampler] = (memory, threaded, renderer) =>
CreateSamplerCommand.Run(ref GetCommand<CreateSamplerCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateSync] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CreateSync] = (memory, threaded, renderer) =>
CreateSyncCommand.Run(ref GetCommand<CreateSyncCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CreateTexture] = (memory, threaded, renderer) =>
CreateTextureCommand.Run(ref GetCommand<CreateTextureCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.GetCapabilities] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.GetCapabilities] = (memory, threaded, renderer) =>
GetCapabilitiesCommand.Run(ref GetCommand<GetCapabilitiesCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.PreFrame] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.PreFrame] = (memory, threaded, renderer) =>
PreFrameCommand.Run(ref GetCommand<PreFrameCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ReportCounter] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.ReportCounter] = (memory, threaded, renderer) =>
ReportCounterCommand.Run(ref GetCommand<ReportCounterCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ResetCounter] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.ResetCounter] = (memory, threaded, renderer) =>
ResetCounterCommand.Run(ref GetCommand<ResetCounterCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.UpdateCounters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.UpdateCounters] = (memory, threaded, renderer) =>
UpdateCountersCommand.Run(ref GetCommand<UpdateCountersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.BufferDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.BufferDispose] = (memory, threaded, renderer) =>
BufferDisposeCommand.Run(ref GetCommand<BufferDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.BufferGetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.BufferGetData] = (memory, threaded, renderer) =>
BufferGetDataCommand.Run(ref GetCommand<BufferGetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.BufferSetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.BufferSetData] = (memory, threaded, renderer) =>
BufferSetDataCommand.Run(ref GetCommand<BufferSetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CounterEventDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CounterEventDispose] = (memory, threaded, renderer) =>
CounterEventDisposeCommand.Run(ref GetCommand<CounterEventDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CounterEventFlush] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CounterEventFlush] = (memory, threaded, renderer) =>
CounterEventFlushCommand.Run(ref GetCommand<CounterEventFlushCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ProgramDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.ProgramDispose] = (memory, threaded, renderer) =>
ProgramDisposeCommand.Run(ref GetCommand<ProgramDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ProgramGetBinary] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.ProgramGetBinary] = (memory, threaded, renderer) =>
ProgramGetBinaryCommand.Run(ref GetCommand<ProgramGetBinaryCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ProgramCheckLink] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.ProgramCheckLink] = (memory, threaded, renderer) =>
ProgramCheckLinkCommand.Run(ref GetCommand<ProgramCheckLinkCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SamplerDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SamplerDispose] = (memory, threaded, renderer) =>
SamplerDisposeCommand.Run(ref GetCommand<SamplerDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureCopyTo] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureCopyTo] = (memory, threaded, renderer) =>
TextureCopyToCommand.Run(ref GetCommand<TextureCopyToCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureCopyToScaled] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureCopyToScaled] = (memory, threaded, renderer) =>
TextureCopyToScaledCommand.Run(ref GetCommand<TextureCopyToScaledCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureCopyToSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureCopyToSlice] = (memory, threaded, renderer) =>
TextureCopyToSliceCommand.Run(ref GetCommand<TextureCopyToSliceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureCreateView] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureCreateView] = (memory, threaded, renderer) =>
TextureCreateViewCommand.Run(ref GetCommand<TextureCreateViewCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureGetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureGetData] = (memory, threaded, renderer) =>
TextureGetDataCommand.Run(ref GetCommand<TextureGetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureGetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureGetDataSlice] = (memory, threaded, renderer) =>
TextureGetDataSliceCommand.Run(ref GetCommand<TextureGetDataSliceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureRelease] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureRelease] = (memory, threaded, renderer) =>
TextureReleaseCommand.Run(ref GetCommand<TextureReleaseCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureSetData] = (memory, threaded, renderer) =>
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureSetDataSlice] = (memory, threaded, renderer) =>
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetDataSliceRegion] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureSetDataSliceRegion] = (memory, threaded, renderer) =>
TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetStorage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureSetStorage] = (memory, threaded, renderer) =>
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.WindowPresent] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.WindowPresent] = (memory, threaded, renderer) =>
WindowPresentCommand.Run(ref GetCommand<WindowPresentCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.Barrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.Barrier] = (memory, threaded, renderer) =>
BarrierCommand.Run(ref GetCommand<BarrierCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.BeginTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.BeginTransformFeedback] = (memory, threaded, renderer) =>
BeginTransformFeedbackCommand.Run(ref GetCommand<BeginTransformFeedbackCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ClearBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.ClearBuffer] = (memory, threaded, renderer) =>
ClearBufferCommand.Run(ref GetCommand<ClearBufferCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ClearRenderTargetColor] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.ClearRenderTargetColor] = (memory, threaded, renderer) =>
ClearRenderTargetColorCommand.Run(ref GetCommand<ClearRenderTargetColorCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (memory, threaded, renderer) =>
ClearRenderTargetDepthStencilCommand.Run(ref GetCommand<ClearRenderTargetDepthStencilCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CommandBufferBarrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CommandBufferBarrier] = (memory, threaded, renderer) =>
CommandBufferBarrierCommand.Run(ref GetCommand<CommandBufferBarrierCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CopyBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.CopyBuffer] = (memory, threaded, renderer) =>
CopyBufferCommand.Run(ref GetCommand<CopyBufferCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DispatchCompute] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.DispatchCompute] = (memory, threaded, renderer) =>
DispatchComputeCommand.Run(ref GetCommand<DispatchComputeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.Draw] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.Draw] = (memory, threaded, renderer) =>
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndexed] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.DrawIndexed] = (memory, threaded, renderer) =>
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndexedIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.DrawIndexedIndirect] = (memory, threaded, renderer) =>
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (memory, threaded, renderer) =>
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.DrawIndirect] = (memory, threaded, renderer) =>
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.DrawIndirectCount] = (memory, threaded, renderer) =>
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.DrawTexture] = (memory, threaded, renderer) =>
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.EndHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.EndHostConditionalRendering] = (memory, threaded, renderer) =>
EndHostConditionalRenderingCommand.Run(renderer);
_lookup[(int)CommandType.EndTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.EndTransformFeedback] = (memory, threaded, renderer) =>
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetAlphaTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetAlphaTest] = (memory, threaded, renderer) =>
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetBlendState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetBlendState] = (memory, threaded, renderer) =>
SetBlendStateCommand.Run(ref GetCommand<SetBlendStateCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetDepthBias] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetDepthBias] = (memory, threaded, renderer) =>
SetDepthBiasCommand.Run(ref GetCommand<SetDepthBiasCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetDepthClamp] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetDepthClamp] = (memory, threaded, renderer) =>
SetDepthClampCommand.Run(ref GetCommand<SetDepthClampCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetDepthMode] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetDepthMode] = (memory, threaded, renderer) =>
SetDepthModeCommand.Run(ref GetCommand<SetDepthModeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetDepthTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetDepthTest] = (memory, threaded, renderer) =>
SetDepthTestCommand.Run(ref GetCommand<SetDepthTestCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetFaceCulling] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetFaceCulling] = (memory, threaded, renderer) =>
SetFaceCullingCommand.Run(ref GetCommand<SetFaceCullingCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetFrontFace] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetFrontFace] = (memory, threaded, renderer) =>
SetFrontFaceCommand.Run(ref GetCommand<SetFrontFaceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetStorageBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetStorageBuffers] = (memory, threaded, renderer) =>
SetStorageBuffersCommand.Run(ref GetCommand<SetStorageBuffersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetTransformFeedbackBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetTransformFeedbackBuffers] = (memory, threaded, renderer) =>
SetTransformFeedbackBuffersCommand.Run(ref GetCommand<SetTransformFeedbackBuffersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetUniformBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetUniformBuffers] = (memory, threaded, renderer) =>
SetUniformBuffersCommand.Run(ref GetCommand<SetUniformBuffersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetImage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetImage] = (memory, threaded, renderer) =>
SetImageCommand.Run(ref GetCommand<SetImageCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetIndexBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetIndexBuffer] = (memory, threaded, renderer) =>
SetIndexBufferCommand.Run(ref GetCommand<SetIndexBufferCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetLineParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetLineParameters] = (memory, threaded, renderer) =>
SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetLogicOpState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetLogicOpState] = (memory, threaded, renderer) =>
SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetMultisampleState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetMultisampleState] = (memory, threaded, renderer) =>
SetMultisampleStateCommand.Run(ref GetCommand<SetMultisampleStateCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPatchParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetPatchParameters] = (memory, threaded, renderer) =>
SetPatchParametersCommand.Run(ref GetCommand<SetPatchParametersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPointParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetPointParameters] = (memory, threaded, renderer) =>
SetPointParametersCommand.Run(ref GetCommand<SetPointParametersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPolygonMode] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetPolygonMode] = (memory, threaded, renderer) =>
SetPolygonModeCommand.Run(ref GetCommand<SetPolygonModeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPrimitiveRestart] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetPrimitiveRestart] = (memory, threaded, renderer) =>
SetPrimitiveRestartCommand.Run(ref GetCommand<SetPrimitiveRestartCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPrimitiveTopology] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetPrimitiveTopology] = (memory, threaded, renderer) =>
SetPrimitiveTopologyCommand.Run(ref GetCommand<SetPrimitiveTopologyCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetProgram] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetProgram] = (memory, threaded, renderer) =>
SetProgramCommand.Run(ref GetCommand<SetProgramCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetRasterizerDiscard] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetRasterizerDiscard] = (memory, threaded, renderer) =>
SetRasterizerDiscardCommand.Run(ref GetCommand<SetRasterizerDiscardCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetRenderTargetColorMasks] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetRenderTargetColorMasks] = (memory, threaded, renderer) =>
SetRenderTargetColorMasksCommand.Run(ref GetCommand<SetRenderTargetColorMasksCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetRenderTargetScale] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetRenderTargetScale] = (memory, threaded, renderer) =>
SetRenderTargetScaleCommand.Run(ref GetCommand<SetRenderTargetScaleCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetRenderTargets] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetRenderTargets] = (memory, threaded, renderer) =>
SetRenderTargetsCommand.Run(ref GetCommand<SetRenderTargetsCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetScissor] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetScissor] = (memory, threaded, renderer) =>
SetScissorsCommand.Run(ref GetCommand<SetScissorsCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetStencilTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetStencilTest] = (memory, threaded, renderer) =>
SetStencilTestCommand.Run(ref GetCommand<SetStencilTestCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetTextureAndSampler] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetTextureAndSampler] = (memory, threaded, renderer) =>
SetTextureAndSamplerCommand.Run(ref GetCommand<SetTextureAndSamplerCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetUserClipDistance] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetUserClipDistance] = (memory, threaded, renderer) =>
SetUserClipDistanceCommand.Run(ref GetCommand<SetUserClipDistanceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetVertexAttribs] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetVertexAttribs] = (memory, threaded, renderer) =>
SetVertexAttribsCommand.Run(ref GetCommand<SetVertexAttribsCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetVertexBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetVertexBuffers] = (memory, threaded, renderer) =>
SetVertexBuffersCommand.Run(ref GetCommand<SetVertexBuffersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetViewports] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.SetViewports] = (memory, threaded, renderer) =>
SetViewportsCommand.Run(ref GetCommand<SetViewportsCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureBarrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureBarrier] = (memory, threaded, renderer) =>
TextureBarrierCommand.Run(ref GetCommand<TextureBarrierCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureBarrierTiled] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TextureBarrierTiled] = (memory, threaded, renderer) =>
TextureBarrierTiledCommand.Run(ref GetCommand<TextureBarrierTiledCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TryHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TryHostConditionalRendering] = (memory, threaded, renderer) =>
TryHostConditionalRenderingCommand.Run(ref GetCommand<TryHostConditionalRenderingCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (memory, threaded, renderer) =>
TryHostConditionalRenderingFlushCommand.Run(ref GetCommand<TryHostConditionalRenderingFlushCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.UpdateRenderScale] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
_lookup[(int)CommandType.UpdateRenderScale] = (memory, threaded, renderer) =>
UpdateRenderScaleCommand.Run(ref GetCommand<UpdateRenderScaleCommand>(memory), threaded, renderer);
}

View File

@ -72,7 +72,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
{
_baseRenderer = renderer;
renderer.ScreenCaptured += (object sender, ScreenCaptureImageInfo info) => ScreenCaptured?.Invoke(this, info);
renderer.ScreenCaptured += (sender, info) => ScreenCaptured?.Invoke(this, info);
Pipeline = new ThreadedPipeline(this, renderer.Pipeline);
Window = new ThreadedWindow(this, renderer);

View File

@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.GAL
AddressMode.ClampToEdge,
AddressMode.ClampToEdge,
CompareMode.None,
GAL.CompareOp.Always,
CompareOp.Always,
new ColorF(0f, 0f, 0f, 0f),
0f,
0f,

View File

@ -2,6 +2,7 @@ using Ryujinx.Graphics.Device;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Gpu.Engine
@ -21,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// Represents a device's state, with a additional shadow state.
/// </summary>
/// <typeparam name="TState">Type of the state</typeparam>
class DeviceStateWithShadow<TState> : IDeviceState where TState : unmanaged, IShadowState
class DeviceStateWithShadow<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged, IShadowState
{
private readonly DeviceState<TState> _state;
private readonly DeviceState<TState> _shadowState;

View File

@ -98,7 +98,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="argument">Method call argument</param>
public void DrawEnd(ThreedClass engine, int argument)
{
DrawEnd(engine, _state.State.IndexBufferState.First, (int)_state.State.IndexBufferCount);
DrawEnd(
engine,
_state.State.IndexBufferState.First,
(int)_state.State.IndexBufferCount,
_state.State.VertexBufferDrawState.First,
_state.State.VertexBufferDrawState.Count);
}
/// <summary>
@ -108,7 +113,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
/// <param name="indexCount">Number of index buffer elements used on the draw</param>
private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount)
/// <param name="drawFirstVertex">Index of the first vertex used on the draw</param>
/// <param name="drawVertexCount">Number of vertices used on the draw</param>
private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount, int drawFirstVertex, int drawVertexCount)
{
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
_context,
@ -135,6 +142,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.FirstIndex = firstIndex;
_drawState.IndexCount = indexCount;
_drawState.DrawFirstVertex = drawFirstVertex;
_drawState.DrawVertexCount = drawVertexCount;
_currentSpecState.SetHasConstantBufferDrawParameters(false);
engine.UpdateState();
@ -156,10 +165,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_instancedIndexCount = ibCount != 0 ? ibCount : indexCount;
var drawState = _state.State.VertexBufferDrawState;
_instancedDrawStateFirst = drawState.First;
_instancedDrawStateCount = drawState.Count;
_instancedDrawStateFirst = drawFirstVertex;
_instancedDrawStateCount = drawVertexCount;
_drawState.DrawIndexed = false;
@ -195,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
var drawState = _state.State.VertexBufferDrawState;
_context.Renderer.Pipeline.Draw(drawState.Count, 1, drawState.First, firstInstance);
_context.Renderer.Pipeline.Draw(drawVertexCount, 1, drawFirstVertex, firstInstance);
}
_drawState.DrawIndexed = false;
@ -216,16 +223,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
bool incrementInstance = (argument & (1 << 26)) != 0;
bool resetInstance = (argument & (1 << 27)) == 0;
if (_state.State.PrimitiveTypeOverrideEnable)
{
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
DrawBegin(incrementInstance, resetInstance, typeOverride.Convert());
}
else
{
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
DrawBegin(incrementInstance, resetInstance, type.Convert());
}
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
DrawBegin(incrementInstance, resetInstance, type);
}
/// <summary>
@ -234,8 +233,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
/// <param name="incrementInstance">Indicates if the current instance should be incremented</param>
/// <param name="resetInstance">Indicates if the current instance should be set to zero</param>
/// <param name="topology">Primitive topology</param>
private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveTopology topology)
/// <param name="primitiveType">Primitive type</param>
private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveType primitiveType)
{
if (incrementInstance)
{
@ -248,6 +247,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_instanceIndex = 0;
}
PrimitiveTopology topology;
if (_state.State.PrimitiveTypeOverrideEnable)
{
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
topology = typeOverride.Convert();
}
else
{
topology = primitiveType.Convert();
}
UpdateTopology(topology);
}
@ -276,46 +287,70 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.DrawIndexed = true;
}
// TODO: Verify if the index type is implied from the method that is called,
// or if it uses the state index type on hardware.
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements.
/// Performs a indexed draw with 8-bit index buffer elements.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexedSmall(ThreedClass engine, int argument)
public void DrawIndexBuffer8BeginEndInstanceFirst(ThreedClass engine, int argument)
{
DrawIndexedSmall(engine, argument, false);
DrawIndexBufferBeginEndInstance(engine, argument, false);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements.
/// Performs a indexed draw with 16-bit index buffer elements.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexedSmall2(ThreedClass engine, int argument)
public void DrawIndexBuffer16BeginEndInstanceFirst(ThreedClass engine, int argument)
{
DrawIndexedSmall(engine, argument);
DrawIndexBufferBeginEndInstance(engine, argument, false);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// Performs a indexed draw with 32-bit index buffer elements.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexBuffer32BeginEndInstanceFirst(ThreedClass engine, int argument)
{
DrawIndexBufferBeginEndInstance(engine, argument, false);
}
/// <summary>
/// Performs a indexed draw with 8-bit index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexedSmallIncInstance(ThreedClass engine, int argument)
public void DrawIndexBuffer8BeginEndInstanceSubsequent(ThreedClass engine, int argument)
{
DrawIndexedSmall(engine, argument, true);
DrawIndexBufferBeginEndInstance(engine, argument, true);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// Performs a indexed draw with 16-bit index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexedSmallIncInstance2(ThreedClass engine, int argument)
public void DrawIndexBuffer16BeginEndInstanceSubsequent(ThreedClass engine, int argument)
{
DrawIndexedSmallIncInstance(engine, argument);
DrawIndexBufferBeginEndInstance(engine, argument, true);
}
/// <summary>
/// Performs a indexed draw with 32-bit index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexBuffer32BeginEndInstanceSubsequent(ThreedClass engine, int argument)
{
DrawIndexBufferBeginEndInstance(engine, argument, true);
}
/// <summary>
@ -325,11 +360,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
private void DrawIndexedSmall(ThreedClass engine, int argument, bool instanced)
private void DrawIndexBufferBeginEndInstance(ThreedClass engine, int argument, bool instanced)
{
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
DrawBegin(instanced, !instanced, typeOverride.Convert());
DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf));
int firstIndex = argument & 0xffff;
int indexCount = (argument >> 16) & 0xfff;
@ -339,7 +372,52 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.DrawIndexed = true;
engine.ForceStateDirty(IndexBufferCountMethodOffset * 4);
DrawEnd(engine, firstIndex, indexCount);
DrawEnd(engine, firstIndex, indexCount, 0, 0);
_drawState.DrawIndexed = oldDrawIndexed;
}
/// <summary>
/// Performs a non-indexed draw with the specified topology, index and count.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawVertexArrayBeginEndInstanceFirst(ThreedClass engine, int argument)
{
DrawVertexArrayBeginEndInstance(engine, argument, false);
}
/// <summary>
/// Performs a non-indexed draw with the specified topology, index and count,
/// while incrementing the current instance.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawVertexArrayBeginEndInstanceSubsequent(ThreedClass engine, int argument)
{
DrawVertexArrayBeginEndInstance(engine, argument, true);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// while optionally also pre-incrementing the current instance value.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
private void DrawVertexArrayBeginEndInstance(ThreedClass engine, int argument, bool instanced)
{
DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf));
int firstVertex = argument & 0xffff;
int vertexCount = (argument >> 16) & 0xfff;
bool oldDrawIndexed = _drawState.DrawIndexed;
_drawState.DrawIndexed = false;
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
DrawEnd(engine, 0, 0, firstVertex, vertexCount);
_drawState.DrawIndexed = oldDrawIndexed;
}
@ -449,8 +527,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
else
{
_state.State.VertexBufferDrawState.First = firstVertex;
_state.State.VertexBufferDrawState.Count = count;
_drawState.DrawFirstVertex = firstVertex;
_drawState.DrawVertexCount = count;
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
}

View File

@ -17,6 +17,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
public int IndexCount;
/// <summary>
/// First vertex used on non-indexed draws. This value is stored somewhere else on indexed draws.
/// </summary>
public int DrawFirstVertex;
/// <summary>
/// Vertex count used on non-indexed draws. Indexed draws have a index count instead.
/// </summary>
public int DrawVertexCount;
/// <summary>
/// Indicates if the next draw will be a indexed draw.
/// </summary>

View File

@ -253,14 +253,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// Indicates that any storage buffer use is unaligned.
/// </summary>
/// <param name="value">The new value</param>
public void SetHasUnalignedStorageBuffer(bool value)
/// <returns>True if the unaligned state changed, false otherwise</returns>
public bool SetHasUnalignedStorageBuffer(bool value)
{
if (value != _graphics.HasUnalignedStorageBuffer)
{
_graphics.HasUnalignedStorageBuffer = value;
Signal();
return true;
}
return false;
}
/// <summary>

View File

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -39,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// GPU state update tracker.
/// </summary>
/// <typeparam name="TState">State type</typeparam>
class StateUpdateTracker<TState>
class StateUpdateTracker<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState>
{
private const int BlockSize = 0xe00;
private const int RegisterSize = sizeof(uint);

View File

@ -1,7 +1,5 @@
using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Shader;
@ -304,14 +302,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
private void CommitBindings()
{
var buffers = _channel.BufferManager;
var hasUnaligned = buffers.HasUnalignedStorageBuffers;
UpdateStorageBuffers();
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned))
bool unalignedChanged = _currentSpecState.SetHasUnalignedStorageBuffer(_channel.BufferManager.HasUnalignedStorageBuffers);
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || unalignedChanged)
{
_currentSpecState.SetHasUnalignedStorageBuffer(buffers.HasUnalignedStorageBuffers);
// Shader must be reloaded. _vtgWritesRtLayer should not change.
UpdateShaderState();
}
@ -993,6 +989,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
bool drawIndexed = _drawState.DrawIndexed;
bool drawIndirect = _drawState.DrawIndirect;
int drawFirstVertex = _drawState.DrawFirstVertex;
int drawVertexCount = _drawState.DrawVertexCount;
uint vbEnableMask = 0;
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
@ -1054,9 +1052,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
int firstInstance = (int)_state.State.FirstInstance;
var drawState = _state.State.VertexBufferDrawState;
size = Math.Min(vbSize, (ulong)((firstInstance + drawState.First + drawState.Count) * stride));
size = Math.Min(vbSize, (ulong)((firstInstance + drawFirstVertex + drawVertexCount) * stride));
}
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
@ -1297,7 +1293,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
{
_currentProgramInfo[stageIndex] = gs.Shaders[stageIndex + 1]?.Info;
ShaderProgramInfo info = gs.Shaders[stageIndex + 1]?.Info;
if (info?.UsesRtLayer == true)
{
_vtgWritesRtLayer = true;
}
_currentProgramInfo[stageIndex] = info;
}
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);

View File

@ -42,6 +42,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{ nameof(ThreedClassState.TextureBarrier), new RwCallback(TextureBarrier, null) },
{ nameof(ThreedClassState.TextureBarrierTiled), new RwCallback(TextureBarrierTiled, null) },
{ nameof(ThreedClassState.DrawTextureSrcY), new RwCallback(DrawTexture, null) },
{ nameof(ThreedClassState.DrawVertexArrayBeginEndInstanceFirst), new RwCallback(DrawVertexArrayBeginEndInstanceFirst, null) },
{ nameof(ThreedClassState.DrawVertexArrayBeginEndInstanceSubsequent), new RwCallback(DrawVertexArrayBeginEndInstanceSubsequent, null) },
{ nameof(ThreedClassState.VbElementU8), new RwCallback(VbElementU8, null) },
{ nameof(ThreedClassState.VbElementU16), new RwCallback(VbElementU16, null) },
{ nameof(ThreedClassState.VbElementU32), new RwCallback(VbElementU32, null) },
@ -49,10 +51,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{ nameof(ThreedClassState.RenderEnableCondition), new RwCallback(null, Zero) },
{ nameof(ThreedClassState.DrawEnd), new RwCallback(DrawEnd, null) },
{ nameof(ThreedClassState.DrawBegin), new RwCallback(DrawBegin, null) },
{ nameof(ThreedClassState.DrawIndexedSmall), new RwCallback(DrawIndexedSmall, null) },
{ nameof(ThreedClassState.DrawIndexedSmall2), new RwCallback(DrawIndexedSmall2, null) },
{ nameof(ThreedClassState.DrawIndexedSmallIncInstance), new RwCallback(DrawIndexedSmallIncInstance, null) },
{ nameof(ThreedClassState.DrawIndexedSmallIncInstance2), new RwCallback(DrawIndexedSmallIncInstance2, null) },
{ nameof(ThreedClassState.DrawIndexBuffer32BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer32BeginEndInstanceFirst, null) },
{ nameof(ThreedClassState.DrawIndexBuffer16BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer16BeginEndInstanceFirst, null) },
{ nameof(ThreedClassState.DrawIndexBuffer8BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer8BeginEndInstanceFirst, null) },
{ nameof(ThreedClassState.DrawIndexBuffer32BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer32BeginEndInstanceSubsequent, null) },
{ nameof(ThreedClassState.DrawIndexBuffer16BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer16BeginEndInstanceSubsequent, null) },
{ nameof(ThreedClassState.DrawIndexBuffer8BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer8BeginEndInstanceSubsequent, null) },
{ nameof(ThreedClassState.IndexBufferCount), new RwCallback(SetIndexBufferCount, null) },
{ nameof(ThreedClassState.Clear), new RwCallback(Clear, null) },
{ nameof(ThreedClassState.SemaphoreControl), new RwCallback(Report, null) },
@ -303,6 +307,25 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawManager.DrawTexture(this, argument);
}
/// <summary>
/// Performs a non-indexed draw with the specified topology, index and count.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawVertexArrayBeginEndInstanceFirst(int argument)
{
_drawManager.DrawVertexArrayBeginEndInstanceFirst(this, argument);
}
/// <summary>
/// Performs a non-indexed draw with the specified topology, index and count,
/// while incrementing the current instance.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawVertexArrayBeginEndInstanceSubsequent(int argument)
{
_drawManager.DrawVertexArrayBeginEndInstanceSubsequent(this, argument);
}
/// <summary>
/// Pushes four 8-bit index buffer elements.
/// </summary>
@ -370,41 +393,60 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements.
/// Performs a indexed draw with 8-bit index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexedSmall(int argument)
private void DrawIndexBuffer8BeginEndInstanceFirst(int argument)
{
_drawManager.DrawIndexedSmall(this, argument);
_drawManager.DrawIndexBuffer8BeginEndInstanceFirst(this, argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements.
/// Performs a indexed draw with 16-bit index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexedSmall2(int argument)
private void DrawIndexBuffer16BeginEndInstanceFirst(int argument)
{
_drawManager.DrawIndexedSmall2(this, argument);
_drawManager.DrawIndexBuffer16BeginEndInstanceFirst(this, argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// Performs a indexed draw with 32-bit index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexBuffer32BeginEndInstanceFirst(int argument)
{
_drawManager.DrawIndexBuffer32BeginEndInstanceFirst(this, argument);
}
/// <summary>
/// Performs a indexed draw with 8-bit index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexedSmallIncInstance(int argument)
private void DrawIndexBuffer8BeginEndInstanceSubsequent(int argument)
{
_drawManager.DrawIndexedSmallIncInstance(this, argument);
_drawManager.DrawIndexBuffer8BeginEndInstanceSubsequent(this, argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// Performs a indexed draw with 16-bit index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexedSmallIncInstance2(int argument)
private void DrawIndexBuffer16BeginEndInstanceSubsequent(int argument)
{
_drawManager.DrawIndexedSmallIncInstance2(this, argument);
_drawManager.DrawIndexBuffer16BeginEndInstanceSubsequent(this, argument);
}
/// <summary>
/// Performs a indexed draw with 32-bit index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexBuffer32BeginEndInstanceSubsequent(int argument)
{
_drawManager.DrawIndexBuffer32BeginEndInstanceSubsequent(this, argument);
}
/// <summary>

View File

@ -813,7 +813,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public uint ClearFlags;
public fixed uint Reserved10FC[25];
public Array32<VertexAttribState> VertexAttribState;
public fixed uint Reserved11E0[15];
public fixed uint Reserved11E0[13];
public uint DrawVertexArrayBeginEndInstanceFirst;
public uint DrawVertexArrayBeginEndInstanceSubsequent;
public RtControl RtControl;
public fixed uint Reserved1220[2];
public Size3D RtDepthStencilSize;
@ -888,12 +890,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public fixed uint Reserved164C[95];
public IndexBufferState IndexBufferState;
public uint IndexBufferCount;
public uint DrawIndexedSmall;
public uint DrawIndexedSmall2;
public uint Reserved17EC;
public uint DrawIndexedSmallIncInstance;
public uint DrawIndexedSmallIncInstance2;
public fixed uint Reserved17F8[33];
public uint DrawIndexBuffer32BeginEndInstanceFirst;
public uint DrawIndexBuffer16BeginEndInstanceFirst;
public uint DrawIndexBuffer8BeginEndInstanceFirst;
public uint DrawIndexBuffer32BeginEndInstanceSubsequent;
public uint DrawIndexBuffer16BeginEndInstanceSubsequent;
public uint DrawIndexBuffer8BeginEndInstanceSubsequent;
public fixed uint Reserved17FC[32];
public float DepthBiasClamp;
public Array16<Boolean32> VertexBufferInstanced;
public fixed uint Reserved18C0[20];

View File

@ -208,8 +208,10 @@ namespace Ryujinx.Graphics.Gpu.Image
Bc6HSf16Float = Bc6HSf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff90
Bc6HUf16Float = Bc6HUf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff91
Etc2RgbUnorm = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24906
Etc2RgbPtaUnorm = Etc2RgbPta | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490a
Etc2RgbaUnorm = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490b
Etc2RgbUnormSrgb = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa4906
Etc2RgbPtaUnormSrgb = Etc2RgbPta | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490a
Etc2RgbaUnormSrgb = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490b
Astc2D4x4Unorm = Astc2D4x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24940
Astc2D5x4Unorm = Astc2D5x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24950
@ -429,8 +431,10 @@ namespace Ryujinx.Graphics.Gpu.Image
{ TextureFormat.Bc6HSf16Float, new FormatInfo(Format.Bc6HSfloat, 4, 4, 16, 4) },
{ TextureFormat.Bc6HUf16Float, new FormatInfo(Format.Bc6HUfloat, 4, 4, 16, 4) },
{ TextureFormat.Etc2RgbUnorm, new FormatInfo(Format.Etc2RgbUnorm, 4, 4, 8, 3) },
{ TextureFormat.Etc2RgbPtaUnorm, new FormatInfo(Format.Etc2RgbPtaUnorm, 4, 4, 8, 4) },
{ TextureFormat.Etc2RgbaUnorm, new FormatInfo(Format.Etc2RgbaUnorm, 4, 4, 16, 4) },
{ TextureFormat.Etc2RgbUnormSrgb, new FormatInfo(Format.Etc2RgbSrgb, 4, 4, 8, 3) },
{ TextureFormat.Etc2RgbPtaUnormSrgb, new FormatInfo(Format.Etc2RgbPtaSrgb, 4, 4, 8, 4) },
{ TextureFormat.Etc2RgbaUnormSrgb, new FormatInfo(Format.Etc2RgbaSrgb, 4, 4, 16, 4) },
{ TextureFormat.Astc2D4x4Unorm, new FormatInfo(Format.Astc4x4Unorm, 4, 4, 16, 4) },
{ TextureFormat.Astc2D5x4Unorm, new FormatInfo(Format.Astc5x4Unorm, 5, 4, 16, 4) },

View File

@ -857,9 +857,23 @@ namespace Ryujinx.Graphics.Gpu.Image
result = decoded;
}
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
{
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
switch (Format)
{
case Format.Etc2RgbaSrgb:
case Format.Etc2RgbaUnorm:
result = ETC2Decoder.DecodeRgba(result, width, height, depth, levels, layers);
break;
case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm:
result = ETC2Decoder.DecodePta(result, width, height, depth, levels, layers);
break;
case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm:
result = ETC2Decoder.DecodeRgb(result, width, height, depth, levels, layers);
break;
}
}
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
{
@ -895,6 +909,10 @@ namespace Ryujinx.Graphics.Gpu.Image
break;
}
}
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
{
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
}
return result;
}

View File

@ -320,10 +320,15 @@ namespace Ryujinx.Graphics.Gpu.Image
// Check if the texture pool has been modified since bindings were last committed.
// If it wasn't, then it's possible to avoid looking up textures again when the handle remains the same.
bool poolModified = _cachedTexturePool != texturePool || _cachedSamplerPool != samplerPool;
if (_cachedTexturePool != texturePool || _cachedSamplerPool != samplerPool)
{
Rebind();
_cachedTexturePool = texturePool;
_cachedSamplerPool = samplerPool;
_cachedTexturePool = texturePool;
_cachedSamplerPool = samplerPool;
}
bool poolModified = false;
if (texturePool != null)
{

View File

@ -67,6 +67,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>A host compatible format</returns>
public static FormatInfo ToHostCompatibleFormat(TextureInfo info, Capabilities caps)
{
// The host API does not support those compressed formats.
// We assume software decompression will be done for those textures,
// and so we adjust the format here to match the decompressor output.
if (!caps.SupportsAstcCompression)
{
if (info.FormatInfo.Format.IsAstcUnorm())
@ -83,16 +87,8 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
if (!caps.SupportsR4G4Format && info.FormatInfo.Format == Format.R4G4Unorm)
{
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
}
if (!HostSupportsBcFormat(info.FormatInfo.Format, info.Target, caps))
{
// The host API does not this compressed format.
// We assume software decompression will be done for those textures,
// and so we adjust the format here to match the decompressor output.
switch (info.FormatInfo.Format)
{
case Format.Bc1RgbaSrgb:
@ -119,6 +115,26 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
if (!caps.SupportsEtc2Compression)
{
switch (info.FormatInfo.Format)
{
case Format.Etc2RgbaSrgb:
case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbSrgb:
return new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4);
case Format.Etc2RgbaUnorm:
case Format.Etc2RgbPtaUnorm:
case Format.Etc2RgbUnorm:
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
}
}
if (!caps.SupportsR4G4Format && info.FormatInfo.Format == Format.R4G4Unorm)
{
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
}
return info.FormatInfo;
}

View File

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 4028;
private const uint CodeGenVersion = 4106;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
CachedShaderStage currentStage = stages[i];
if (currentStage != null && currentStage.Info.Stage == stage && currentStage.Info != null)
if (currentStage?.Info != null && currentStage.Info.Stage == stage)
{
return ShaderCache.GetBindings(currentStage.Info);
}

View File

@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Texture target.
/// </summary>
public Image.TextureTarget TextureTarget;
public TextureTarget TextureTarget;
/// <summary>
/// Indicates if the coordinates used to sample the texture are normalized or not (0.0..1.0 or 0..Width/Height).
@ -331,7 +331,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
int cbufSlot,
uint format,
bool formatSrgb,
Image.TextureTarget target,
TextureTarget target,
bool coordNormalized)
{
Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
@ -415,7 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <param name="stageIndex">Shader stage where the texture is used</param>
/// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
/// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
public Image.TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot)
public TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot)
{
return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget;
}

View File

@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
static class FFmpegApi
static partial class FFmpegApi
{
public const string AvCodecLibraryName = "avcodec";
public const string AvUtilLibraryName = "avutil";
@ -78,52 +78,52 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
public unsafe delegate void av_log_set_callback_callback(void* a0, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string a2, byte* a3);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVFrame* av_frame_alloc();
[LibraryImport(AvUtilLibraryName)]
internal static unsafe partial AVFrame* av_frame_alloc();
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_frame_unref(AVFrame* frame);
[LibraryImport(AvUtilLibraryName)]
internal static unsafe partial void av_frame_unref(AVFrame* frame);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_free(AVFrame* frame);
[LibraryImport(AvUtilLibraryName)]
internal static unsafe partial void av_free(AVFrame* frame);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_log_set_level(AVLog level);
[LibraryImport(AvUtilLibraryName)]
internal static unsafe partial void av_log_set_level(AVLog level);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_log_set_callback(av_log_set_callback_callback callback);
[LibraryImport(AvUtilLibraryName)]
internal static unsafe partial void av_log_set_callback(av_log_set_callback_callback callback);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVLog av_log_get_level();
[LibraryImport(AvUtilLibraryName)]
internal static unsafe partial AVLog av_log_get_level();
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_log_format_line(void* ptr, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string fmt, byte* vl, byte* line, int lineSize, int* printPrefix);
[LibraryImport(AvUtilLibraryName)]
internal static unsafe partial void av_log_format_line(void* ptr, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string fmt, byte* vl, byte* line, int lineSize, int* printPrefix);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVCodec* avcodec_find_decoder(AVCodecID id);
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial AVCodec* avcodec_find_decoder(AVCodecID id);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVCodecContext* avcodec_alloc_context3(AVCodec* codec);
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial AVCodecContext* avcodec_alloc_context3(AVCodec* codec);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern int avcodec_open2(AVCodecContext* avctx, AVCodec* codec, void **options);
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial int avcodec_open2(AVCodecContext* avctx, AVCodec* codec, void **options);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern int avcodec_close(AVCodecContext* avctx);
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial int avcodec_close(AVCodecContext* avctx);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void avcodec_free_context(AVCodecContext** avctx);
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial void avcodec_free_context(AVCodecContext** avctx);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVPacket* av_packet_alloc();
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial AVPacket* av_packet_alloc();
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_packet_unref(AVPacket* pkt);
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial void av_packet_unref(AVPacket* pkt);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_packet_free(AVPacket** pkt);
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial void av_packet_free(AVPacket** pkt);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern int avcodec_version();
[LibraryImport(AvCodecLibraryName)]
internal static unsafe partial int avcodec_version();
}
}

View File

@ -5,7 +5,7 @@ using System.Runtime.Versioning;
namespace Ryujinx.Graphics.OpenGL.Helper
{
[SupportedOSPlatform("linux")]
internal static class GLXHelper
internal static partial class GLXHelper
{
private const string LibraryName = "glx.dll";
@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.OpenGL.Helper
});
}
[DllImport(LibraryName, EntryPoint = "glXGetCurrentContext")]
public static extern IntPtr GetCurrentContext();
[LibraryImport(LibraryName, EntryPoint = "glXGetCurrentContext")]
public static partial IntPtr GetCurrentContext();
}
}

View File

@ -5,11 +5,11 @@ using System.Runtime.Versioning;
namespace Ryujinx.Graphics.OpenGL.Helper
{
[SupportedOSPlatform("windows")]
internal static class WGLHelper
internal static partial class WGLHelper
{
private const string LibraryName = "OPENGL32.DLL";
[DllImport(LibraryName, EntryPoint = "wglGetCurrentContext")]
public extern static IntPtr GetCurrentContext();
[LibraryImport(LibraryName, EntryPoint = "wglGetCurrentContext")]
public static partial IntPtr GetCurrentContext();
}
}

View File

@ -110,6 +110,7 @@ namespace Ryujinx.Graphics.OpenGL
supportsBc123Compression: HwCapabilities.SupportsTextureCompressionS3tc,
supportsBc45Compression: HwCapabilities.SupportsTextureCompressionRgtc,
supportsBc67Compression: true, // Should check BPTC extension, but for some reason NVIDIA is not exposing the extension.
supportsEtc2Compression: true,
supports3DTextureCompression: false,
supportsBgraFormat: false,
supportsR4G4Format: false,

View File

@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Graphics" Version="4.7.5" />
<PackageReference Include="OpenTK.Graphics" />
</ItemGroup>
<ItemGroup>

View File

@ -2,6 +2,6 @@ float Helper_SwizzleAdd(float x, float y, int mask)
{
vec4 xLut = vec4(1.0, -1.0, 1.0, 0.0);
vec4 yLut = vec4(1.0, 1.0, -1.0, 1.0);
int lutIdx = mask >> int($SUBGROUP_INVOCATION$ & 3u) * 2;
int lutIdx = (mask >> (int($SUBGROUP_INVOCATION$ & 3u) * 2)) & 3;
return x * xLut[lutIdx] + y * yLut[lutIdx];
}

View File

@ -10,8 +10,6 @@ using static Spv.Specification;
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{
using SpvInstruction = Spv.Generator.Instruction;
static class Declarations
{
// At least 16 attributes are guaranteed by the spec.
@ -60,7 +58,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
{
StructuredFunction function = functions[funcIndex];
SpvInstruction[] locals = new SpvInstruction[function.InArguments.Length];
Instruction[] locals = new Instruction[function.InArguments.Length];
for (int i = 0; i < function.InArguments.Length; i++)
{
@ -122,7 +120,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size);
}
private static SpvInstruction DeclareMemory(CodeGenContext context, StorageClass storage, int size)
private static Instruction DeclareMemory(CodeGenContext context, StorageClass storage, int size)
{
var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size));
var pointerType = context.TypePointer(storage, arrayType);

View File

@ -1449,10 +1449,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var xLut = context.ConstantComposite(v4float, one, minusOne, one, zero);
var yLut = context.ConstantComposite(v4float, one, one, minusOne, one);
var three = context.Constant(context.TypeU32(), 3);
var threadId = context.GetAttribute(AggregateType.U32, AttributeConsts.LaneId, false);
var shift = context.BitwiseAnd(context.TypeU32(), threadId, context.Constant(context.TypeU32(), 3));
var shift = context.BitwiseAnd(context.TypeU32(), threadId, three);
shift = context.ShiftLeftLogical(context.TypeU32(), shift, context.Constant(context.TypeU32(), 1));
var lutIdx = context.ShiftRightLogical(context.TypeU32(), mask, shift);
lutIdx = context.BitwiseAnd(context.TypeU32(), lutIdx, three);
var xLutValue = context.VectorExtractDynamic(context.TypeFP32(), xLut, lutIdx);
var yLutValue = context.VectorExtractDynamic(context.TypeFP32(), yLut, lutIdx);

View File

@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public const int TessLevelOuter3 = 0x00c;
public const int TessLevelInner0 = 0x010;
public const int TessLevelInner1 = 0x014;
public const int PrimitiveId = 0x060;
public const int Layer = 0x064;
public const int ViewportIndex = 0x068;
public const int PointSize = 0x06c;
@ -85,8 +86,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public const int LaneId = 0x2000020;
public const int InvocationId = 0x2000024;
public const int PrimitiveId = 0x2000028;
public const int PatchVerticesIn = 0x200002c;
public const int PatchVerticesIn = 0x2000028;
public const int EqMask = 0x2000030;
public const int GeMask = 0x2000034;

View File

@ -262,7 +262,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
value = (value >> operation.Index * 16) & 0xffff;
operation.TurnIntoCopy(ConstF(HalfConversion.HalfToSingle(value)));
operation.TurnIntoCopy(ConstF((float)BitConverter.UInt16BitsToHalf((ushort)value)));
}
private static void FPNegate(Operation operation)

View File

@ -1,47 +0,0 @@
using System;
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
static class HalfConversion
{
public static float HalfToSingle(int value)
{
int mantissa = (value >> 0) & 0x3ff;
int exponent = (value >> 10) & 0x1f;
int sign = (value >> 15) & 0x1;
if (exponent == 0x1f)
{
// NaN or Infinity.
mantissa <<= 13;
exponent = 0xff;
}
else if (exponent != 0 || mantissa != 0 )
{
if (exponent == 0)
{
// Denormal.
int e = -1;
int m = mantissa;
do
{
e++;
m <<= 1;
}
while ((m & 0x400) == 0);
mantissa = m & 0x3ff;
exponent = e;
}
mantissa <<= 13;
exponent = 127 - 15 + exponent;
}
int output = (sign << 31) | (exponent << 23) | mantissa;
return BitConverter.Int32BitsToSingle(output);
}
}
}

View File

@ -0,0 +1,682 @@
using Ryujinx.Common;
using System;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Texture
{
public static class ETC2Decoder
{
private const uint AlphaMask = 0xff000000u;
private const int BlockWidth = 4;
private const int BlockHeight = 4;
private static readonly int[][] _etc1Lut =
{
new int[] { 2, 8, -2, -8 },
new int[] { 5, 17, -5, -17 },
new int[] { 9, 29, -9, -29 },
new int[] { 13, 42, -13, -42 },
new int[] { 18, 60, -18, -60 },
new int[] { 24, 80, -24, -80 },
new int[] { 33, 106, -33, -106 },
new int[] { 47, 183, -47, -183 }
};
private static readonly int[] _etc2Lut =
{
3, 6, 11, 16, 23, 32, 41, 64
};
private static readonly int[][] _etc2AlphaLut =
{
new int[] { -3, -6, -9, -15, 2, 5, 8, 14 },
new int[] { -3, -7, -10, -13, 2, 6, 9, 12 },
new int[] { -2, -5, -8, -13, 1, 4, 7, 12 },
new int[] { -2, -4, -6, -13, 1, 3, 5, 12 },
new int[] { -3, -6, -8, -12, 2, 5, 7, 11 },
new int[] { -3, -7, -9, -11, 2, 6, 8, 10 },
new int[] { -4, -7, -8, -11, 3, 6, 7, 10 },
new int[] { -3, -5, -8, -11, 2, 4, 7, 10 },
new int[] { -2, -6, -8, -10, 1, 5, 7, 9 },
new int[] { -2, -5, -8, -10, 1, 4, 7, 9 },
new int[] { -2, -4, -8, -10, 1, 3, 7, 9 },
new int[] { -2, -5, -7, -10, 1, 4, 6, 9 },
new int[] { -3, -4, -7, -10, 2, 3, 6, 9 },
new int[] { -1, -2, -3, -10, 0, 1, 2, 9 },
new int[] { -4, -6, -8, -9, 3, 5, 7, 8 },
new int[] { -3, -5, -7, -9, 2, 4, 6, 8 }
};
public static byte[] DecodeRgb(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0;
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;
for (int l = 0; l < levels; l++)
{
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
for (int l2 = 0; l2 < layers; l2++)
{
for (int z = 0; z < depth; z++)
{
for (int y = 0; y < hInBlocks; y++)
{
int ty = y * BlockHeight;
int bh = Math.Min(BlockHeight, height - ty);
for (int x = 0; x < wInBlocks; x++)
{
int tx = x * BlockWidth;
int bw = Math.Min(BlockWidth, width - tx);
ulong colorBlock = dataUlong[inputOffset++];
DecodeBlock(tile, colorBlock);
for (int py = 0; py < bh; py++)
{
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
for (int px = 0; px < bw; px++)
{
int oOffs = oOffsBase + px;
outputUint[oOffs] = tile[py * BlockWidth + px] | AlphaMask;
}
}
}
}
imageBaseOOffs += width * height;
}
}
width = Math.Max(1, width >> 1);
height = Math.Max(1, height >> 1);
depth = Math.Max(1, depth >> 1);
}
return output;
}
public static byte[] DecodePta(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0;
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;
for (int l = 0; l < levels; l++)
{
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
for (int l2 = 0; l2 < layers; l2++)
{
for (int z = 0; z < depth; z++)
{
for (int y = 0; y < hInBlocks; y++)
{
int ty = y * BlockHeight;
int bh = Math.Min(BlockHeight, height - ty);
for (int x = 0; x < wInBlocks; x++)
{
int tx = x * BlockWidth;
int bw = Math.Min(BlockWidth, width - tx);
ulong colorBlock = dataUlong[inputOffset++];
DecodeBlockPta(tile, colorBlock);
for (int py = 0; py < bh; py++)
{
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
tile.Slice(py * BlockWidth, bw).CopyTo(outputUint.Slice(oOffsBase, bw));
}
}
}
imageBaseOOffs += width * height;
}
}
width = Math.Max(1, width >> 1);
height = Math.Max(1, height >> 1);
depth = Math.Max(1, depth >> 1);
}
return output;
}
public static byte[] DecodeRgba(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0;
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;
for (int l = 0; l < levels; l++)
{
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
for (int l2 = 0; l2 < layers; l2++)
{
for (int z = 0; z < depth; z++)
{
for (int y = 0; y < hInBlocks; y++)
{
int ty = y * BlockHeight;
int bh = Math.Min(BlockHeight, height - ty);
for (int x = 0; x < wInBlocks; x++)
{
int tx = x * BlockWidth;
int bw = Math.Min(BlockWidth, width - tx);
ulong alphaBlock = dataUlong[inputOffset];
ulong colorBlock = dataUlong[inputOffset + 1];
inputOffset += 2;
DecodeBlock(tile, colorBlock);
byte alphaBase = (byte)alphaBlock;
int[] alphaTable = _etc2AlphaLut[(alphaBlock >> 8) & 0xf];
int alphaMultiplier = (int)(alphaBlock >> 12) & 0xf;
ulong alphaIndices = BinaryPrimitives.ReverseEndianness(alphaBlock);
if (alphaMultiplier != 0)
{
for (int py = 0; py < bh; py++)
{
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
for (int px = 0; px < bw; px++)
{
int oOffs = oOffsBase + px;
int alphaIndex = (int)((alphaIndices >> (((px * BlockHeight + py) ^ 0xf) * 3)) & 7);
byte a = Saturate(alphaBase + alphaTable[alphaIndex] * alphaMultiplier);
outputUint[oOffs] = tile[py * BlockWidth + px] | ((uint)a << 24);
}
}
}
else
{
uint a = (uint)alphaBase << 24;
for (int py = 0; py < bh; py++)
{
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
for (int px = 0; px < bw; px++)
{
int oOffs = oOffsBase + px;
outputUint[oOffs] = tile[py * BlockWidth + px] | a;
}
}
}
}
}
imageBaseOOffs += width * height;
}
}
width = Math.Max(1, width >> 1);
height = Math.Max(1, height >> 1);
depth = Math.Max(1, depth >> 1);
}
return output;
}
private static void DecodeBlock(Span<uint> tile, ulong block)
{
uint blockLow = (uint)(block >> 0);
uint blockHigh = (uint)(block >> 32);
uint r1, g1, b1;
uint r2, g2, b2;
bool differentialMode = (blockLow & 0x2000000) != 0;
if (differentialMode)
{
(r1, g1, b1, r2, g2, b2) = UnpackRgb555DiffEndPoints(blockLow);
if (r2 > 31)
{
DecodeBlock59T(tile, blockLow, blockHigh);
}
else if (g2 > 31)
{
DecodeBlock58H(tile, blockLow, blockHigh);
}
else if (b2 > 31)
{
DecodeBlock57P(tile, block);
}
else
{
r1 |= r1 >> 5;
g1 |= g1 >> 5;
b1 |= b1 >> 5;
r2 = (r2 << 3) | (r2 >> 2);
g2 = (g2 << 3) | (g2 >> 2);
b2 = (b2 << 3) | (b2 >> 2);
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
}
}
else
{
r1 = (blockLow & 0x0000f0) >> 0;
g1 = (blockLow & 0x00f000) >> 8;
b1 = (blockLow & 0xf00000) >> 16;
r2 = (blockLow & 0x00000f) << 4;
g2 = (blockLow & 0x000f00) >> 4;
b2 = (blockLow & 0x0f0000) >> 12;
r1 |= r1 >> 4;
g1 |= g1 >> 4;
b1 |= b1 >> 4;
r2 |= r2 >> 4;
g2 |= g2 >> 4;
b2 |= b2 >> 4;
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
}
}
private static void DecodeBlockPta(Span<uint> tile, ulong block)
{
uint blockLow = (uint)(block >> 0);
uint blockHigh = (uint)(block >> 32);
(uint r1, uint g1, uint b1, uint r2, uint g2, uint b2) = UnpackRgb555DiffEndPoints(blockLow);
bool fullyOpaque = (blockLow & 0x2000000) != 0;
if (fullyOpaque)
{
if (r2 > 31)
{
DecodeBlock59T(tile, blockLow, blockHigh);
}
else if (g2 > 31)
{
DecodeBlock58H(tile, blockLow, blockHigh);
}
else if (b2 > 31)
{
DecodeBlock57P(tile, block);
}
else
{
r1 |= r1 >> 5;
g1 |= g1 >> 5;
b1 |= b1 >> 5;
r2 = (r2 << 3) | (r2 >> 2);
g2 = (g2 << 3) | (g2 >> 2);
b2 = (b2 << 3) | (b2 >> 2);
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
}
for (int i = 0; i < tile.Length; i++)
{
tile[i] |= AlphaMask;
}
}
else
{
if (r2 > 31)
{
DecodeBlock59T(tile, blockLow, blockHigh, AlphaMask);
}
else if (g2 > 31)
{
DecodeBlock58H(tile, blockLow, blockHigh, AlphaMask);
}
else if (b2 > 31)
{
DecodeBlock57P(tile, block);
for (int i = 0; i < tile.Length; i++)
{
tile[i] |= AlphaMask;
}
}
else
{
r1 |= r1 >> 5;
g1 |= g1 >> 5;
b1 |= b1 >> 5;
r2 = (r2 << 3) | (r2 >> 2);
g2 = (g2 << 3) | (g2 >> 2);
b2 = (b2 << 3) | (b2 >> 2);
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2, AlphaMask);
}
}
}
private static (uint, uint, uint, uint, uint, uint) UnpackRgb555DiffEndPoints(uint blockLow)
{
uint r1 = (blockLow & 0x0000f8) >> 0;
uint g1 = (blockLow & 0x00f800) >> 8;
uint b1 = (blockLow & 0xf80000) >> 16;
uint r2 = (uint)((sbyte)(r1 >> 3) + ((sbyte)((blockLow & 0x000007) << 5) >> 5));
uint g2 = (uint)((sbyte)(g1 >> 3) + ((sbyte)((blockLow & 0x000700) >> 3) >> 5));
uint b2 = (uint)((sbyte)(b1 >> 3) + ((sbyte)((blockLow & 0x070000) >> 11) >> 5));
return (r1, g1, b1, r2, g2, b2);
}
private static void DecodeBlock59T(Span<uint> tile, uint blockLow, uint blockHigh, uint alphaMask = 0)
{
uint r1 = (blockLow & 3) | ((blockLow >> 1) & 0xc);
uint g1 = (blockLow >> 12) & 0xf;
uint b1 = (blockLow >> 8) & 0xf;
uint r2 = (blockLow >> 20) & 0xf;
uint g2 = (blockLow >> 16) & 0xf;
uint b2 = (blockLow >> 28) & 0xf;
r1 |= r1 << 4;
g1 |= g1 << 4;
b1 |= b1 << 4;
r2 |= r2 << 4;
g2 |= g2 << 4;
b2 |= b2 << 4;
int dist = _etc2Lut[((blockLow >> 24) & 1) | ((blockLow >> 25) & 6)];
Span<uint> palette = stackalloc uint[4];
palette[0] = Pack(r1, g1, b1);
palette[1] = Pack(r2, g2, b2, dist);
palette[2] = Pack(r2, g2, b2);
palette[3] = Pack(r2, g2, b2, -dist);
blockHigh = BinaryPrimitives.ReverseEndianness(blockHigh);
for (int y = 0; y < BlockHeight; y++)
{
for (int x = 0; x < BlockWidth; x++)
{
int offset = (y * 4) + x;
int index = (x * 4) + y;
int paletteIndex = (int)((blockHigh >> index) & 1) | (int)((blockHigh >> (index + 15)) & 2);
tile[offset] = palette[paletteIndex];
if (alphaMask != 0)
{
if (paletteIndex == 2)
{
tile[offset] = 0;
}
else
{
tile[offset] |= alphaMask;
}
}
}
}
}
private static void DecodeBlock58H(Span<uint> tile, uint blockLow, uint blockHigh, uint alphaMask = 0)
{
uint r1 = (blockLow >> 3) & 0xf;
uint g1 = ((blockLow << 1) & 0xe) | ((blockLow >> 12) & 1);
uint b1 = ((blockLow >> 23) & 1) | ((blockLow >> 7) & 6) | ((blockLow >> 8) & 8);
uint r2 = (blockLow >> 19) & 0xf;
uint g2 = ((blockLow >> 31) & 1) | ((blockLow >> 15) & 0xe);
uint b2 = (blockLow >> 27) & 0xf;
uint rgb1 = Pack4Be(r1, g1, b1);
uint rgb2 = Pack4Be(r2, g2, b2);
r1 |= r1 << 4;
g1 |= g1 << 4;
b1 |= b1 << 4;
r2 |= r2 << 4;
g2 |= g2 << 4;
b2 |= b2 << 4;
int dist = _etc2Lut[(rgb1 >= rgb2 ? 1u : 0u) | ((blockLow >> 23) & 2) | ((blockLow >> 24) & 4)];
Span<uint> palette = stackalloc uint[4];
palette[0] = Pack(r1, g1, b1, dist);
palette[1] = Pack(r1, g1, b1, -dist);
palette[2] = Pack(r2, g2, b2, dist);
palette[3] = Pack(r2, g2, b2, -dist);
blockHigh = BinaryPrimitives.ReverseEndianness(blockHigh);
for (int y = 0; y < BlockHeight; y++)
{
for (int x = 0; x < BlockWidth; x++)
{
int offset = (y * 4) + x;
int index = (x * 4) + y;
int paletteIndex = (int)((blockHigh >> index) & 1) | (int)((blockHigh >> (index + 15)) & 2);
tile[offset] = palette[paletteIndex];
if (alphaMask != 0)
{
if (paletteIndex == 2)
{
tile[offset] = 0;
}
else
{
tile[offset] |= alphaMask;
}
}
}
}
}
private static void DecodeBlock57P(Span<uint> tile, ulong block)
{
int r0 = (int)((block >> 1) & 0x3f);
int g0 = (int)(((block >> 9) & 0x3f) | ((block & 1) << 6));
int b0 = (int)(((block >> 31) & 1) | ((block >> 15) & 6) | ((block >> 16) & 0x18) | ((block >> 3) & 0x20));
int rh = (int)(((block >> 24) & 1) | ((block >> 25) & 0x3e));
int gh = (int)((block >> 33) & 0x7f);
int bh = (int)(((block >> 43) & 0x1f) | ((block >> 27) & 0x20));
int rv = (int)(((block >> 53) & 7) | ((block >> 37) & 0x38));
int gv = (int)(((block >> 62) & 3) | ((block >> 46) & 0x7c));
int bv = (int)((block >> 56) & 0x3f);
r0 = (r0 << 2) | (r0 >> 4);
g0 = (g0 << 1) | (g0 >> 6);
b0 = (b0 << 2) | (b0 >> 4);
rh = (rh << 2) | (rh >> 4);
gh = (gh << 1) | (gh >> 6);
bh = (bh << 2) | (bh >> 4);
rv = (rv << 2) | (rv >> 4);
gv = (gv << 1) | (gv >> 6);
bv = (bv << 2) | (bv >> 4);
for (int y = 0; y < BlockHeight; y++)
{
for (int x = 0; x < BlockWidth; x++)
{
int offset = y * BlockWidth + x;
byte r = Saturate(((x * (rh - r0)) + (y * (rv - r0)) + (r0 * 4) + 2) >> 2);
byte g = Saturate(((x * (gh - g0)) + (y * (gv - g0)) + (g0 * 4) + 2) >> 2);
byte b = Saturate(((x * (bh - b0)) + (y * (bv - b0)) + (b0 * 4) + 2) >> 2);
tile[offset] = Pack(r, g, b);
}
}
}
private static void DecodeBlockETC1(
Span<uint> tile,
uint blockLow,
uint blockHigh,
uint r1,
uint g1,
uint b1,
uint r2,
uint g2,
uint b2,
uint alphaMask = 0)
{
int[] table1 = _etc1Lut[(blockLow >> 29) & 7];
int[] table2 = _etc1Lut[(blockLow >> 26) & 7];
bool flip = (blockLow & 0x1000000) != 0;
if (!flip)
{
for (int y = 0; y < BlockHeight; y++)
{
for (int x = 0; x < BlockWidth / 2; x++)
{
uint color1 = CalculatePixel(r1, g1, b1, x + 0, y, blockHigh, table1, alphaMask);
uint color2 = CalculatePixel(r2, g2, b2, x + 2, y, blockHigh, table2, alphaMask);
int offset1 = y * BlockWidth + x;
int offset2 = y * BlockWidth + x + 2;
tile[offset1] = color1;
tile[offset2] = color2;
}
}
}
else
{
for (int y = 0; y < BlockHeight / 2; y++)
{
for (int x = 0; x < BlockWidth; x++)
{
uint color1 = CalculatePixel(r1, g1, b1, x, y + 0, blockHigh, table1, alphaMask);
uint color2 = CalculatePixel(r2, g2, b2, x, y + 2, blockHigh, table2, alphaMask);
int offset1 = (y * BlockWidth) + x;
int offset2 = ((y + 2) * BlockWidth) + x;
tile[offset1] = color1;
tile[offset2] = color2;
}
}
}
}
private static uint CalculatePixel(uint r, uint g, uint b, int x, int y, uint block, int[] table, uint alphaMask)
{
int index = x * BlockHeight + y;
uint msb = block << 1;
uint tableIndex = index < 8
? ((block >> (index + 24)) & 1) + ((msb >> (index + 8)) & 2)
: ((block >> (index + 8)) & 1) + ((msb >> (index - 8)) & 2);
if (alphaMask != 0)
{
if (tableIndex == 0)
{
return Pack(r, g, b) | alphaMask;
}
else if (tableIndex == 2)
{
return 0;
}
else
{
return Pack(r, g, b, table[tableIndex]) | alphaMask;
}
}
return Pack(r, g, b, table[tableIndex]);
}
private static uint Pack(uint r, uint g, uint b, int offset)
{
r = Saturate((int)(r + offset));
g = Saturate((int)(g + offset));
b = Saturate((int)(b + offset));
return Pack(r, g, b);
}
private static uint Pack(uint r, uint g, uint b)
{
return r | (g << 8) | (b << 16);
}
private static uint Pack4Be(uint r, uint g, uint b)
{
return (r << 8) | (g << 4) | b;
}
private static byte Saturate(int value)
{
return value > byte.MaxValue ? byte.MaxValue : value < byte.MinValue ? byte.MinValue : (byte)value;
}
private static int CalculateOutputSize(int width, int height, int depth, int levels, int layers)
{
int size = 0;
for (int l = 0; l < levels; l++)
{
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
return size;
}
}
}

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