diff options
Diffstat (limited to 'Ryujinx.Headless.SDL2')
-rw-r--r-- | Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs | 13 | ||||
-rw-r--r-- | Ryujinx.Headless.SDL2/Options.cs | 9 | ||||
-rw-r--r-- | Ryujinx.Headless.SDL2/Program.cs | 53 | ||||
-rw-r--r-- | Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj | 2 | ||||
-rw-r--r-- | Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs | 83 | ||||
-rw-r--r-- | Ryujinx.Headless.SDL2/WindowBase.cs | 19 |
6 files changed, 161 insertions, 18 deletions
diff --git a/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs b/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs index a6995143..aa2e86d9 100644 --- a/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs +++ b/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs @@ -108,14 +108,9 @@ namespace Ryujinx.Headless.SDL2.OpenGL _glLogLevel = glLogLevel; } - protected override string GetGpuVendorName() - { - return ((Renderer)Renderer).GpuVendor; - } - public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_OPENGL; - protected override void InitializeRenderer() + protected override void InitializeWindowRenderer() { // Ensure to not share this context with other contexts before this point. SetupOpenGLAttributes(false, _glLogLevel); @@ -135,7 +130,7 @@ namespace Ryujinx.Headless.SDL2.OpenGL _openGLContext = new SDL2OpenGLContext(context, WindowHandle, false); // First take exclusivity on the OpenGL context. - ((Renderer)Renderer).InitializeBackgroundContext(SDL2OpenGLContext.CreateBackgroundContext(_openGLContext)); + ((OpenGLRenderer)Renderer).InitializeBackgroundContext(SDL2OpenGLContext.CreateBackgroundContext(_openGLContext)); _openGLContext.MakeCurrent(); @@ -147,7 +142,9 @@ namespace Ryujinx.Headless.SDL2.OpenGL MouseDriver.SetClientSize(DefaultWidth, DefaultHeight); } - protected override void FinalizeRenderer() + protected override void InitializeRenderer() { } + + protected override void FinalizeWindowRenderer() { // Try to bind the OpenGL context before calling the gpu disposal. _openGLContext.MakeCurrent(); diff --git a/Ryujinx.Headless.SDL2/Options.cs b/Ryujinx.Headless.SDL2/Options.cs index 4c9b83c4..95694179 100644 --- a/Ryujinx.Headless.SDL2/Options.cs +++ b/Ryujinx.Headless.SDL2/Options.cs @@ -94,6 +94,9 @@ namespace Ryujinx.Headless.SDL2 [Option("enable-shader-cache", Required = false, Default = true, HelpText = "Enables Shader cache.")] public bool? EnableShaderCache { get; set; } + [Option("enable-texture-recompression", Required = false, Default = false, HelpText = "Enables Texture recompression.")] + public bool? EnableTextureRecompression { get; set; } + [Option("enable-docked-mode", Required = false, Default = true, HelpText = "Enables Docked Mode.")] public bool? EnableDockedMode { get; set; } @@ -164,6 +167,12 @@ namespace Ryujinx.Headless.SDL2 [Option("graphics-shaders-dump-path", Required = false, HelpText = "Dumps shaders in this local directory. (Developer only)")] public string GraphicsShadersDumpPath { get; set; } + [Option("graphics-backend", Required = false, Default = GraphicsBackend.OpenGl, HelpText = "Change Graphics Backend to use.")] + public GraphicsBackend GraphicsBackend { get; set; } + + [Option("preferred-gpu-vendor", Required = false, Default = "", HelpText = "When using the Vulkan backend, prefer using the GPU from the specified vendor.")] + public string PreferredGpuVendor { get; set; } + // Hacks [Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GB to 6GB.")] diff --git a/Ryujinx.Headless.SDL2/Program.cs b/Ryujinx.Headless.SDL2/Program.cs index 1d64a8c6..5c24095e 100644 --- a/Ryujinx.Headless.SDL2/Program.cs +++ b/Ryujinx.Headless.SDL2/Program.cs @@ -17,7 +17,9 @@ using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.OpenGL; +using Ryujinx.Graphics.Vulkan; using Ryujinx.Headless.SDL2.OpenGL; +using Ryujinx.Headless.SDL2.Vulkan; using Ryujinx.HLE; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; @@ -25,6 +27,7 @@ using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.Input; using Ryujinx.Input.HLE; using Ryujinx.Input.SDL2; +using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.IO; @@ -404,6 +407,7 @@ namespace Ryujinx.Headless.SDL2 // Setup graphics configuration GraphicsConfig.EnableShaderCache = (bool)option.EnableShaderCache; + GraphicsConfig.EnableTextureRecompression = (bool)option.EnableTextureRecompression; GraphicsConfig.ResScale = option.ResScale; GraphicsConfig.MaxAnisotropy = option.MaxAnisotropy; GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath; @@ -449,10 +453,47 @@ namespace Ryujinx.Headless.SDL2 Logger.Info?.Print(LogClass.Application, label); } - private static Switch InitializeEmulationContext(WindowBase window, Options options) + private static WindowBase CreateWindow(Options options) { - IRenderer renderer = new Renderer(); + return options.GraphicsBackend == GraphicsBackend.Vulkan + ? new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, (bool)options.EnableMouse) + : new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, (bool)options.EnableMouse); + } + + private static IRenderer CreateRenderer(Options options, WindowBase window) + { + if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow) + { + string preferredGpuId = string.Empty; + + if (!string.IsNullOrEmpty(options.PreferredGpuVendor)) + { + string preferredGpuVendor = options.PreferredGpuVendor.ToLowerInvariant(); + var devices = VulkanRenderer.GetPhysicalDevices(); + foreach (var device in devices) + { + if (device.Vendor.ToLowerInvariant() == preferredGpuVendor) + { + preferredGpuId = device.Id; + break; + } + } + } + + return new VulkanRenderer( + (instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))), + vulkanWindow.GetRequiredInstanceExtensions, + preferredGpuId); + } + else + { + return new OpenGLRenderer(); + } + } + + private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options) + { BackendThreading threadingMode = options.BackendThreading; bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading); @@ -521,8 +562,12 @@ namespace Ryujinx.Headless.SDL2 Logger.RestartTime(); - _window = new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, (bool)options.EnableMouse); - _emulationContext = InitializeEmulationContext(_window, options); + WindowBase window = CreateWindow(options); + IRenderer renderer = CreateRenderer(options, window); + + _window = window; + + _emulationContext = InitializeEmulationContext(window, renderer, options); SetupProgressHandler(); diff --git a/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj b/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj index 2e9fd1a0..929b4131 100644 --- a/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj +++ b/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj @@ -10,10 +10,12 @@ </PropertyGroup> <ItemGroup> + <PackageReference Include="OpenTK.Core" Version="4.7.2" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" /> <ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" /> <ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" /> <ProjectReference Include="..\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" /> diff --git a/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs b/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs new file mode 100644 index 00000000..d8eafba4 --- /dev/null +++ b/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs @@ -0,0 +1,83 @@ +using Ryujinx.Common.Configuration; +using Ryujinx.Common.Logging; +using Ryujinx.Input.HLE; +using System; +using System.Runtime.InteropServices; +using System.Text; +using static SDL2.SDL; + +namespace Ryujinx.Headless.SDL2.Vulkan +{ + class VulkanWindow : WindowBase + { + private GraphicsDebugLevel _glLogLevel; + + public VulkanWindow(InputManager inputManager, GraphicsDebugLevel glLogLevel, AspectRatio aspectRatio, bool enableMouse) : base(inputManager, glLogLevel, aspectRatio, enableMouse) + { + _glLogLevel = glLogLevel; + } + + public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_VULKAN; + + protected override void InitializeWindowRenderer() { } + + protected override void InitializeRenderer() + { + Renderer?.Window.SetSize(DefaultWidth, DefaultHeight); + MouseDriver.SetClientSize(DefaultWidth, DefaultHeight); + } + + public unsafe IntPtr CreateWindowSurface(IntPtr instance) + { + if (SDL_Vulkan_CreateSurface(WindowHandle, instance, out ulong surfaceHandle) == SDL_bool.SDL_FALSE) + { + string errorMessage = $"SDL_Vulkan_CreateSurface failed with error \"{SDL_GetError()}\""; + + Logger.Error?.Print(LogClass.Application, errorMessage); + + throw new Exception(errorMessage); + } + + return (IntPtr)surfaceHandle; + } + + // TODO: Fix this in SDL2-CS. + [DllImport("SDL2", EntryPoint = "SDL_Vulkan_GetInstanceExtensions", CallingConvention = CallingConvention.Cdecl)] + public static extern SDL_bool SDL_Vulkan_GetInstanceExtensions_Workaround(IntPtr window, out uint count, IntPtr names); + + public unsafe string[] GetRequiredInstanceExtensions() + { + if (SDL_Vulkan_GetInstanceExtensions_Workaround(WindowHandle, out uint extensionsCount, IntPtr.Zero) == SDL_bool.SDL_TRUE) + { + IntPtr[] rawExtensions = new IntPtr[(int)extensionsCount]; + string[] extensions = new string[(int)extensionsCount]; + + fixed (IntPtr* rawExtensionsPtr = rawExtensions) + { + if (SDL_Vulkan_GetInstanceExtensions_Workaround(WindowHandle, out extensionsCount, (IntPtr)rawExtensionsPtr) == SDL_bool.SDL_TRUE) + { + for (int i = 0; i < extensions.Length; i++) + { + extensions[i] = Marshal.PtrToStringUTF8(rawExtensions[i]); + } + + return extensions; + } + } + } + + string errorMessage = $"SDL_Vulkan_GetInstanceExtensions failed with error \"{SDL_GetError()}\""; + + Logger.Error?.Print(LogClass.Application, errorMessage); + + throw new Exception(errorMessage); + } + + protected override void FinalizeWindowRenderer() + { + Device.DisposeGpu(); + } + + protected override void SwapBuffers(object texture) { } + } +} diff --git a/Ryujinx.Headless.SDL2/WindowBase.cs b/Ryujinx.Headless.SDL2/WindowBase.cs index 58aa8d07..cc0986a0 100644 --- a/Ryujinx.Headless.SDL2/WindowBase.cs +++ b/Ryujinx.Headless.SDL2/WindowBase.cs @@ -151,22 +151,29 @@ namespace Ryujinx.Headless.SDL2 } } + protected abstract void InitializeWindowRenderer(); + protected abstract void InitializeRenderer(); - protected abstract void FinalizeRenderer(); + protected abstract void FinalizeWindowRenderer(); protected abstract void SwapBuffers(object image); - protected abstract string GetGpuVendorName(); - public abstract SDL_WindowFlags GetWindowFlags(); + private string GetGpuVendorName() + { + return Renderer.GetHardwareInfo().GpuVendor; + } + public void Render() { - InitializeRenderer(); + InitializeWindowRenderer(); Device.Gpu.Renderer.Initialize(_glLogLevel); + InitializeRenderer(); + _gpuVendorName = GetGpuVendorName(); Device.Gpu.Renderer.RunLoop(() => @@ -220,7 +227,7 @@ namespace Ryujinx.Headless.SDL2 } }); - FinalizeRenderer(); + FinalizeWindowRenderer(); } public void Exit() @@ -323,7 +330,7 @@ namespace Ryujinx.Headless.SDL2 renderLoopThread.Start(); Thread nvStutterWorkaround = null; - if (Renderer is Graphics.OpenGL.Renderer) + if (Renderer is Graphics.OpenGL.OpenGLRenderer) { nvStutterWorkaround = new Thread(NVStutterWorkaround) { |