feat(linux): add graphical platform services

This commit is contained in:
Erik 2026-07-27 11:54:59 +02:00
parent 1628d9f587
commit 66f114b258
28 changed files with 1328 additions and 155 deletions

View file

@ -0,0 +1,102 @@
using System.Runtime.InteropServices;
using AcDream.App.Rendering;
using AcDream.Runtime.Platform;
namespace AcDream.App.Platform;
internal enum GraphicalHostOperatingSystem
{
Windows,
Linux,
}
internal sealed record GraphicalNativeDependency(
string Feature,
string PublishedFileName);
internal sealed record GraphicalHostPlatformServices(
GraphicalHostOperatingSystem OperatingSystem,
Architecture ProcessArchitecture,
string RuntimeIdentifier,
ApplicationPathSet Paths,
IFramePacingWaiterFactory FramePacingWaiters,
IReadOnlyList<GraphicalNativeDependency> NativeDependencies)
{
internal static GraphicalHostPlatformServices Resolve()
{
GraphicalHostOperatingSystem operatingSystem =
DetectOperatingSystem();
Architecture architecture = RuntimeInformation.ProcessArchitecture;
string runtimeIdentifier = ResolveRuntimeIdentifier(
operatingSystem,
architecture);
return new GraphicalHostPlatformServices(
operatingSystem,
architecture,
runtimeIdentifier,
ApplicationPathSet.Resolve(),
new PlatformFramePacingWaiterFactory(operatingSystem),
ResolveNativeDependencies(operatingSystem));
}
internal static GraphicalHostOperatingSystem DetectOperatingSystem()
{
if (System.OperatingSystem.IsWindows())
return GraphicalHostOperatingSystem.Windows;
if (System.OperatingSystem.IsLinux())
return GraphicalHostOperatingSystem.Linux;
throw new PlatformNotSupportedException(
"acdream graphical hosting supports Windows and Linux.");
}
private static string ResolveRuntimeIdentifier(
GraphicalHostOperatingSystem operatingSystem,
Architecture architecture)
{
string architectureName = architecture switch
{
Architecture.X64 => "x64",
Architecture.Arm64 => "arm64",
Architecture.X86 => "x86",
Architecture.Arm => "arm",
_ => throw new PlatformNotSupportedException(
$"Unsupported graphical process architecture {architecture}."),
};
if (operatingSystem == GraphicalHostOperatingSystem.Linux
&& architecture != Architecture.X64)
{
throw new PlatformNotSupportedException(
"The first acdream Linux graphical package supports linux-x64 only.");
}
string operatingSystemName =
operatingSystem == GraphicalHostOperatingSystem.Windows
? "win"
: "linux";
return $"{operatingSystemName}-{architectureName}";
}
private static IReadOnlyList<GraphicalNativeDependency>
ResolveNativeDependencies(
GraphicalHostOperatingSystem operatingSystem) =>
operatingSystem switch
{
GraphicalHostOperatingSystem.Windows =>
[
new("window/input", "glfw3.dll"),
new("developer UI", "cimgui.dll"),
new("audio", "soft_oal.dll"),
],
GraphicalHostOperatingSystem.Linux =>
[
new("window/input", "libglfw.so.3"),
new("developer UI", "libcimgui.so"),
new("audio", "libopenal.so"),
],
_ => throw new ArgumentOutOfRangeException(
nameof(operatingSystem)),
};
}

View file

@ -0,0 +1,50 @@
using AcDream.Runtime.Platform;
namespace AcDream.App.Platform;
internal static class GraphicalLegacyConfigurationMigrator
{
private static readonly string[] FileNames =
[
"settings.json",
"keybinds.json",
];
internal static IReadOnlyList<string> Migrate(
ApplicationPathSet paths)
{
ArgumentNullException.ThrowIfNull(paths);
if (paths.LegacyConfigDirectory is not { } legacyDirectory
|| PathsEqual(legacyDirectory, paths.ConfigDirectory))
{
return [];
}
List<string>? migrated = null;
foreach (string fileName in FileNames)
{
string source = Path.Combine(legacyDirectory, fileName);
string destination = Path.Combine(
paths.ConfigDirectory,
fileName);
if (!File.Exists(source) || File.Exists(destination))
continue;
Directory.CreateDirectory(paths.ConfigDirectory);
File.Copy(source, destination, overwrite: false);
(migrated ??= []).Add(destination);
}
return migrated ?? [];
}
private static bool PathsEqual(string left, string right) =>
string.Equals(
Path.TrimEndingDirectorySeparator(
Path.GetFullPath(left)),
Path.TrimEndingDirectorySeparator(
Path.GetFullPath(right)),
OperatingSystem.IsWindows()
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal);
}