mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-02-23 17:40:19 +00:00
* add avalonia support * only lock around skia flush * addressed review * cleanup * add fallback size if avalonia attempts to render but the window size is 0. read desktop scale after enabling dpi check * fix getting window handle on linux. skip render is size is 0
203 lines
7.7 KiB
C#
203 lines
7.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using Ryujinx.Graphics.Vulkan;
|
|
using Silk.NET.Core;
|
|
using Silk.NET.Vulkan;
|
|
using Silk.NET.Vulkan.Extensions.KHR;
|
|
|
|
namespace Ryujinx.Ava.Ui.Vulkan
|
|
{
|
|
public unsafe class VulkanPhysicalDevice
|
|
{
|
|
private VulkanPhysicalDevice(PhysicalDevice apiHandle, Vk api, uint queueCount, uint queueFamilyIndex)
|
|
{
|
|
InternalHandle = apiHandle;
|
|
Api = api;
|
|
QueueCount = queueCount;
|
|
QueueFamilyIndex = queueFamilyIndex;
|
|
|
|
api.GetPhysicalDeviceProperties(apiHandle, out var properties);
|
|
|
|
DeviceName = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName);
|
|
|
|
var version = (Version32)properties.ApiVersion;
|
|
ApiVersion = new Version((int)version.Major, (int)version.Minor, 0, (int)version.Patch);
|
|
}
|
|
|
|
internal PhysicalDevice InternalHandle { get; }
|
|
internal Vk Api { get; }
|
|
public uint QueueCount { get; }
|
|
public uint QueueFamilyIndex { get; }
|
|
public IntPtr Handle => InternalHandle.Handle;
|
|
|
|
public string DeviceName { get; }
|
|
public Version ApiVersion { get; }
|
|
|
|
internal static unsafe VulkanPhysicalDevice FindSuitablePhysicalDevice(VulkanInstance instance,
|
|
VulkanSurface surface, bool preferDiscreteGpu, uint? preferredDevice)
|
|
{
|
|
uint physicalDeviceCount;
|
|
|
|
instance.Api.EnumeratePhysicalDevices(instance.InternalHandle, &physicalDeviceCount, null).ThrowOnError();
|
|
|
|
var physicalDevices = new PhysicalDevice[physicalDeviceCount];
|
|
|
|
fixed (PhysicalDevice* pPhysicalDevices = physicalDevices)
|
|
{
|
|
instance.Api.EnumeratePhysicalDevices(instance.InternalHandle, &physicalDeviceCount, pPhysicalDevices)
|
|
.ThrowOnError();
|
|
}
|
|
|
|
var physicalDeviceProperties = new Dictionary<PhysicalDevice, PhysicalDeviceProperties>();
|
|
|
|
foreach (var physicalDevice in physicalDevices)
|
|
{
|
|
instance.Api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
|
|
physicalDeviceProperties.Add(physicalDevice, properties);
|
|
}
|
|
|
|
if (preferredDevice.HasValue && preferredDevice != 0)
|
|
{
|
|
var physicalDevice = physicalDeviceProperties.FirstOrDefault(x => x.Value.DeviceID == preferredDevice);
|
|
if (physicalDevice.Key.Handle != 0 && IsSuitableDevice(instance.Api, physicalDevice.Key,
|
|
physicalDevice.Value, surface.ApiHandle, out var queueCount,
|
|
out var queueFamilyIndex))
|
|
return new VulkanPhysicalDevice(physicalDevice.Key, instance.Api, queueCount, queueFamilyIndex);
|
|
}
|
|
|
|
if (preferDiscreteGpu)
|
|
{
|
|
var discreteGpus = physicalDeviceProperties.Where(p => p.Value.DeviceType == PhysicalDeviceType.DiscreteGpu);
|
|
|
|
foreach (var gpu in discreteGpus)
|
|
{
|
|
if (IsSuitableDevice(
|
|
instance.Api,
|
|
gpu.Key,
|
|
gpu.Value,
|
|
surface.ApiHandle,
|
|
out var queueCount,
|
|
out var queueFamilyIndex))
|
|
{
|
|
return new VulkanPhysicalDevice(gpu.Key, instance.Api, queueCount, queueFamilyIndex);
|
|
}
|
|
|
|
physicalDeviceProperties.Remove(gpu.Key);
|
|
}
|
|
}
|
|
|
|
foreach (var physicalDevice in physicalDeviceProperties)
|
|
if (IsSuitableDevice(
|
|
instance.Api,
|
|
physicalDevice.Key,
|
|
physicalDevice.Value,
|
|
surface.ApiHandle,
|
|
out var queueCount,
|
|
out var queueFamilyIndex))
|
|
{
|
|
return new VulkanPhysicalDevice(physicalDevice.Key, instance.Api, queueCount, queueFamilyIndex);
|
|
}
|
|
|
|
throw new Exception("No suitable physical device found");
|
|
}
|
|
|
|
private static unsafe bool IsSuitableDevice(Vk api, PhysicalDevice physicalDevice, PhysicalDeviceProperties properties, SurfaceKHR surface,
|
|
out uint queueCount, out uint familyIndex)
|
|
{
|
|
queueCount = 0;
|
|
familyIndex = 0;
|
|
|
|
if (properties.DeviceType == PhysicalDeviceType.Cpu) return false;
|
|
|
|
var extensionMatches = 0;
|
|
uint propertiesCount;
|
|
|
|
api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, null).ThrowOnError();
|
|
|
|
var extensionProperties = new ExtensionProperties[propertiesCount];
|
|
|
|
fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
|
|
{
|
|
api.EnumerateDeviceExtensionProperties(
|
|
physicalDevice,
|
|
(byte*)null,
|
|
&propertiesCount,
|
|
pExtensionProperties).ThrowOnError();
|
|
|
|
for (var i = 0; i < propertiesCount; i++)
|
|
{
|
|
var extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName);
|
|
|
|
if (VulkanInitialization.RequiredExtensions.Contains(extensionName))
|
|
{
|
|
extensionMatches++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (extensionMatches == VulkanInitialization.RequiredExtensions.Length)
|
|
{
|
|
familyIndex = FindSuitableQueueFamily(api, physicalDevice, surface, out queueCount);
|
|
|
|
return familyIndex != uint.MaxValue;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
internal unsafe string[] GetSupportedExtensions()
|
|
{
|
|
uint propertiesCount;
|
|
|
|
Api.EnumerateDeviceExtensionProperties(InternalHandle, (byte*)null, &propertiesCount, null).ThrowOnError();
|
|
|
|
var extensionProperties = new ExtensionProperties[propertiesCount];
|
|
|
|
fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
|
|
{
|
|
Api.EnumerateDeviceExtensionProperties(InternalHandle, (byte*)null, &propertiesCount, pExtensionProperties)
|
|
.ThrowOnError();
|
|
}
|
|
|
|
return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray();
|
|
}
|
|
|
|
private static unsafe uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface,
|
|
out uint queueCount)
|
|
{
|
|
const QueueFlags RequiredFlags = QueueFlags.QueueGraphicsBit | QueueFlags.QueueComputeBit;
|
|
|
|
var khrSurface = new KhrSurface(api.Context);
|
|
|
|
uint propertiesCount;
|
|
|
|
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, null);
|
|
|
|
var properties = new QueueFamilyProperties[propertiesCount];
|
|
|
|
fixed (QueueFamilyProperties* pProperties = properties)
|
|
{
|
|
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, pProperties);
|
|
}
|
|
|
|
for (uint index = 0; index < propertiesCount; index++)
|
|
{
|
|
var queueFlags = properties[index].QueueFlags;
|
|
|
|
khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice, index, surface, out var surfaceSupported)
|
|
.ThrowOnError();
|
|
|
|
if (queueFlags.HasFlag(RequiredFlags) && surfaceSupported)
|
|
{
|
|
queueCount = properties[index].QueueCount;
|
|
return index;
|
|
}
|
|
}
|
|
|
|
queueCount = 0;
|
|
return uint.MaxValue;
|
|
}
|
|
}
|
|
}
|