mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Core - Made graphics context providable by UI
Windows - Implemented Vulkan graphics context Splash screen - Tweaked design
This commit is contained in:
1 parent
b2987b5190
commit
34407aaeec
18 files changed
+346
-25
No files matched your search
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Artemis.UI.Windows.SkiaSharp.Vulkan;
|
||||
|
||||
internal class Kernel32
|
||||
{
|
||||
private const string kernel32 = "kernel32.dll";
|
||||
|
||||
static Kernel32()
|
||||
{
|
||||
CurrentModuleHandle = GetModuleHandle(null);
|
||||
if (CurrentModuleHandle == IntPtr.Zero)
|
||||
throw new Exception("Could not get module handle.");
|
||||
}
|
||||
|
||||
public static IntPtr CurrentModuleHandle { get; }
|
||||
|
||||
[DllImport(kernel32, CallingConvention = CallingConvention.Winapi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
public static extern IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPTStr)] string lpModuleName);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using SharpVk;
|
||||
using SharpVk.Khronos;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.UI.Windows.SkiaSharp.Vulkan;
|
||||
|
||||
internal class VkContext : IDisposable
|
||||
{
|
||||
public virtual Instance Instance { get; protected set; }
|
||||
|
||||
public virtual PhysicalDevice PhysicalDevice { get; protected set; }
|
||||
|
||||
public virtual Surface Surface { get; protected set; }
|
||||
|
||||
public virtual Device Device { get; protected set; }
|
||||
|
||||
public virtual Queue GraphicsQueue { get; protected set; }
|
||||
|
||||
public virtual Queue PresentQueue { get; protected set; }
|
||||
|
||||
public virtual uint GraphicsFamily { get; protected set; }
|
||||
|
||||
public virtual uint PresentFamily { get; protected set; }
|
||||
|
||||
public virtual GRVkGetProcedureAddressDelegate GetProc { get; protected set; }
|
||||
|
||||
public virtual GRSharpVkGetProcedureAddressDelegate SharpVkGetProc { get; protected set; }
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
Instance?.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Avalonia.Win32;
|
||||
using SharpVk;
|
||||
using SharpVk.Khronos;
|
||||
|
||||
namespace Artemis.UI.Windows.SkiaSharp.Vulkan;
|
||||
|
||||
internal sealed class Win32VkContext : VkContext
|
||||
{
|
||||
public Win32VkContext()
|
||||
{
|
||||
Window = new WindowImpl();
|
||||
Instance = Instance.Create(null, new[] {"VK_KHR_surface", "VK_KHR_win32_surface"});
|
||||
PhysicalDevice = Instance.EnumeratePhysicalDevices().First();
|
||||
Surface = Instance.CreateWin32Surface(Kernel32.CurrentModuleHandle, Window.Handle.Handle);
|
||||
|
||||
(GraphicsFamily, PresentFamily) = FindQueueFamilies();
|
||||
|
||||
DeviceQueueCreateInfo[] queueInfos =
|
||||
{
|
||||
new() {QueueFamilyIndex = GraphicsFamily, QueuePriorities = new[] {1f}},
|
||||
new() {QueueFamilyIndex = PresentFamily, QueuePriorities = new[] {1f}}
|
||||
};
|
||||
Device = PhysicalDevice.CreateDevice(queueInfos, null, null);
|
||||
GraphicsQueue = Device.GetQueue(GraphicsFamily, 0);
|
||||
PresentQueue = Device.GetQueue(PresentFamily, 0);
|
||||
|
||||
GetProc = Proc;
|
||||
|
||||
SharpVkGetProc = (name, instance, device) =>
|
||||
{
|
||||
if (device != null)
|
||||
return device.GetProcedureAddress(name);
|
||||
if (instance != null)
|
||||
return instance.GetProcedureAddress(name);
|
||||
|
||||
// SharpVk includes the static functions on Instance, but this is not actually correct
|
||||
// since the functions are static, they are not tied to an instance. For example,
|
||||
// VkCreateInstance is not found on an instance, it is creating said instance.
|
||||
// Other libraries, such as VulkanCore, use another type to do this.
|
||||
return Instance.GetProcedureAddress(name);
|
||||
};
|
||||
}
|
||||
|
||||
public WindowImpl Window { get; }
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
Window.Dispose();
|
||||
}
|
||||
|
||||
private IntPtr Proc(string name, IntPtr instanceHandle, IntPtr deviceHandle)
|
||||
{
|
||||
if (deviceHandle != IntPtr.Zero)
|
||||
return Device.GetProcedureAddress(name);
|
||||
|
||||
return Instance.GetProcedureAddress(name);
|
||||
}
|
||||
|
||||
private (uint, uint) FindQueueFamilies()
|
||||
{
|
||||
QueueFamilyProperties[] queueFamilyProperties = PhysicalDevice.GetQueueFamilyProperties();
|
||||
|
||||
var graphicsFamily = queueFamilyProperties
|
||||
.Select((properties, index) => new {properties, index})
|
||||
.SkipWhile(pair => !pair.properties.QueueFlags.HasFlag(QueueFlags.Graphics))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (graphicsFamily == null)
|
||||
throw new Exception("Unable to find graphics queue");
|
||||
|
||||
uint? presentFamily = default;
|
||||
|
||||
for (uint i = 0; i < queueFamilyProperties.Length; ++i)
|
||||
{
|
||||
if (PhysicalDevice.GetSurfaceSupport(i, Surface))
|
||||
presentFamily = i;
|
||||
}
|
||||
|
||||
if (!presentFamily.HasValue)
|
||||
throw new Exception("Unable to find present queue");
|
||||
|
||||
return ((uint) graphicsFamily.index, presentFamily.Value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using Artemis.Core.SkiaSharp;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Windows.SkiaSharp.Vulkan;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.UI.Windows.SkiaSharp
|
||||
{
|
||||
public class VulkanContext : IManagedGraphicsContext
|
||||
{
|
||||
private readonly GRVkBackendContext _vulkanBackendContext;
|
||||
private readonly Win32VkContext _vulkanContext;
|
||||
|
||||
public VulkanContext()
|
||||
{
|
||||
// Try everything in separate try-catch blocks to provide some accuracy in error reporting
|
||||
try
|
||||
{
|
||||
_vulkanContext = new Win32VkContext();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ArtemisGraphicsContextException("Failed to create Vulkan context", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_vulkanBackendContext = new GRVkBackendContext
|
||||
{
|
||||
VkInstance = (IntPtr) _vulkanContext.Instance.RawHandle.ToUInt64(),
|
||||
VkPhysicalDevice = (IntPtr) _vulkanContext.PhysicalDevice.RawHandle.ToUInt64(),
|
||||
VkDevice = (IntPtr) _vulkanContext.Device.RawHandle.ToUInt64(),
|
||||
VkQueue = (IntPtr) _vulkanContext.GraphicsQueue.RawHandle.ToUInt64(),
|
||||
GraphicsQueueIndex = _vulkanContext.GraphicsFamily,
|
||||
GetProcedureAddress = _vulkanContext.GetProc
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ArtemisGraphicsContextException("Failed to create Vulkan backend context", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
GraphicsContext = GRContext.CreateVulkan(_vulkanBackendContext);
|
||||
if (GraphicsContext == null)
|
||||
throw new ArtemisGraphicsContextException("GRContext.CreateVulkan returned null");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ArtemisGraphicsContextException("Failed to create Vulkan graphics context", e);
|
||||
}
|
||||
|
||||
GraphicsContext.Flush();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public GRContext GraphicsContext { get; }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user