Skip to content

Commit

Permalink
Add stopwatch to measure startup time
Browse files Browse the repository at this point in the history
KHRSurfaceKHR
Query ExtDebugUtils
Device creation
Use custom logger
Stop recompiling shaders (afaik)
Remove unnecessary Program.Main()
  • Loading branch information
SupinePandora43 committed Jul 19, 2023
1 parent 09fc4f6 commit 4c99bb9
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 52 deletions.
7 changes: 2 additions & 5 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,8 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildVulkan",
"program": "${workspaceFolder}/Examples/gpu/UltralightNet.Vulkan.TestApp/bin/Debug/net6.0/UltralightNet.Vulkan.TestApp.dll",
"args": [],
"cwd": "${workspaceFolder}/Examples/gpu/UltralightNet.Vulkan.TestApp/bin/Debug/net6.0",
"console": "internalConsole",
"stopAtEntry": false,
"program": "${workspaceFolder}/Examples/gpu/UltralightNet.Vulkan.TestApp/bin/Debug/net7.0/UltralightNet.Vulkan.TestApp.dll",
"cwd": "${workspaceFolder}/Examples/gpu/UltralightNet.Vulkan.TestApp/bin/Debug/net7.0",
"envFile": "${workspaceFolder}/.env"
},
{
Expand Down
10 changes: 0 additions & 10 deletions Examples/gpu/UltralightNet.Vulkan.TestApp/Program2.cs

This file was deleted.

64 changes: 36 additions & 28 deletions Examples/gpu/UltralightNet.Vulkan.TestApp/Startup/Utils.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,59 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Silk.NET.Core;
using Silk.NET.Core.Native;
using Silk.NET.Vulkan;

internal unsafe static class Utils
{
const bool Debug =
#if DEBUG
true;
#else
false;
#endif

public static void Check(this Result result)
{
if (result is not Result.Success) throw new Exception("Result is not OK");
}
private static byte* ToPointer(this ReadOnlySpan<byte> span) => (byte*)Unsafe.AsPointer(ref Unsafe.AsRef(in span[0]));

private static bool HasInstanceLayer(this Vk vk, ReadOnlySpan<byte> layer)
{
uint propertyCount = 0;
vk.EnumerateInstanceLayerProperties(ref propertyCount, null).Check();
var properties = stackalloc LayerProperties[(int)propertyCount];
vk.EnumerateInstanceLayerProperties(ref propertyCount, properties).Check();
for (int i = 0; i < propertyCount; i++)
if (layer.SequenceEqual(MemoryMarshal.CreateReadOnlySpanFromNullTerminated(properties[i].LayerName))) return true;
return false;
}
public static void CreateInstance(Vk vk, uint extensionCount, byte** extensions, out Instance instance)
public static void CreateInstance(Vk vk, string[] extensions, out Instance instance)
{
ApplicationInfo applicationInfo = new(
pApplicationName: "VulkanExample"u8.ToPointer(),
apiVersion: Vk.Version11
);

ReadOnlySpan<byte> validationLayer = "VK_LAYER_KHRONOS_validation"u8;
byte** layers = stackalloc byte*[1] { ToPointer(validationLayer) };

delegate* unmanaged[Cdecl]<DebugUtilsMessageSeverityFlagsEXT, DebugUtilsMessageTypeFlagsEXT, DebugUtilsMessengerCallbackDataEXT*, void*, Bool32> a = &DebugLogger;
DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = new(
messageSeverity: DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt | DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt,
messageType: DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt,
pfnUserCallback: (delegate* unmanaged[Cdecl]<DebugUtilsMessageSeverityFlagsEXT, DebugUtilsMessageTypeFlagsEXT, DebugUtilsMessengerCallbackDataEXT*, void*, Bool32>)&DebugLogger
);
void* next = null;

vk.CreateInstance(new InstanceCreateInfo(
pNext: vk.HasInstanceLayer(validationLayer) ? &debugUtilsMessengerCreateInfo : null,
pApplicationInfo: &applicationInfo,
enabledLayerCount: vk.HasInstanceLayer(validationLayer) ? 1u : 0u,
ppEnabledLayerNames: layers,
enabledExtensionCount: 0,
ppEnabledExtensionNames: extensions
), null, out instance).Check();
if (Debug)
{
DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = new(
messageSeverity: DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt | DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt,
messageType: DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt | DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeGeneralBitExt | DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypePerformanceBitExt,
pfnUserCallback: (delegate* unmanaged[Cdecl]<DebugUtilsMessageSeverityFlagsEXT, DebugUtilsMessageTypeFlagsEXT, DebugUtilsMessengerCallbackDataEXT*, void*, Bool32>)&DebugLogger
);
next = &debugUtilsMessengerCreateInfo;
}
byte** extensionsPtr = (byte**)SilkMarshal.StringArrayToPtr(extensions);
try
{
vk.CreateInstance(new InstanceCreateInfo(
pNext: next,
pApplicationInfo: &applicationInfo,
enabledLayerCount: 0u,
ppEnabledLayerNames: null,
enabledExtensionCount: (uint)extensions.Length,
ppEnabledExtensionNames: extensionsPtr
), null, out instance).Check();
}
finally
{
for (uint i = 0; i < extensions.Length; i++) SilkMarshal.FreeString((nint)extensionsPtr[i]);
SilkMarshal.Free((nint)extensionsPtr);
}
}

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,14 @@
<EmbeddedResource Include="shaders/spirv/*" />
</ItemGroup>
<ItemGroup Label="Shaders">
<VertexShader Include="shaders/**/*.vert" />
<FragmentShader Include="shaders/**/*.frag" />
<VertexShader Include="shaders/*.vert" />
<FragmentShader Include="shaders/*.frag" />
</ItemGroup>
<Target Name="CompileVertexShaders" Inputs="@(VertexShader)" Outputs="@(VertexShader -> '%(RelativeDir)vertex/%(filename).spv')" BeforeTargets="ResolveReferences">
<Target Name="CompileVertexShaders" Inputs="@(VertexShader)" Outputs="@(VertexShader -> '%(RelativeDir)spirv/%(filename).vert.spv')" BeforeTargets="Build">
<MakeDir Directories="@(VertexShader -> '%(RelativeDir)spirv')" />
<Exec Command="glslc -O -o @(VertexShader -> '%(RelativeDir)spirv/%(filename).vert.spv') %(VertexShader.Identity)" EchoOff="false" />
<Exec Command="echo $(BuildDir)" />
</Target>
<Target Name="CompileFragmentShaders" Inputs="@(FragmentShader)" Outputs="@(FragmentShader -> '%(RelativeDir)fragment/%(filename).spv')" BeforeTargets="ResolveReferences">
<Target Name="CompileFragmentShaders" Inputs="@(FragmentShader)" Outputs="@(FragmentShader -> '%(RelativeDir)spirv/%(filename).frag.spv')" BeforeTargets="Build">
<MakeDir Directories="@(FragmentShader -> '%(RelativeDir)spirv')" />
<Exec Command="glslc -O -o @(FragmentShader -> '%(RelativeDir)spirv/%(filename).frag.spv') %(FragmentShader.Identity)" EchoOff="false" />
</Target>
Expand Down
86 changes: 82 additions & 4 deletions Examples/gpu/UltralightNet.Vulkan.TestApp/VulkanExample.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,55 @@
//namespace VulkanExample;

using System.Diagnostics;
using Silk.NET.Core;
using Silk.NET.Core.Native;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT;
using Silk.NET.Vulkan.Extensions.KHR;
using Silk.NET.Windowing;

using Application app = new();
app.Run();

internal unsafe partial class Application : IDisposable
{
//static Application() => Window.PrioritizeSdl();
readonly Stopwatch stopwatch = Stopwatch.StartNew();

readonly IWindow window = Window.Create(WindowOptions.DefaultVulkan);
readonly Vk vk = Vk.GetApi();
readonly Instance instance;

readonly KhrSurface khrSurface;
readonly ExtDebugUtils? debugUtils;

readonly SurfaceKHR surface;
readonly PhysicalDevice physicalDevice;

readonly uint graphicsQueueFamily = uint.MaxValue;
readonly uint presentQueueFamily = uint.MaxValue;

readonly Device device;
readonly Queue graphicsQueue;
readonly Queue presentQueue;

public Application()
{
{ // Window
window.Initialize();
if (window.VkSurface is null) throw new PlatformNotSupportedException("Vulkan surface not found.");
}
{ // Instance
var extensions = window.VkSurface.GetRequiredExtensions(out uint extensionCount);
Utils.CreateInstance(vk, extensionCount, extensions, out instance);
var extensions = SilkMarshal.PtrToStringArray((nint)window.VkSurface.GetRequiredExtensions(out uint surfaceExtensionCount), (int)surfaceExtensionCount).ToList();
extensions.Add(KhrSurface.ExtensionName);
if (vk.IsInstanceExtensionPresent(ExtDebugUtils.ExtensionName)) extensions.Add(ExtDebugUtils.ExtensionName);

Utils.CreateInstance(vk, extensions.ToArray(), out instance);
}
{ // Instance extensions
if (!vk.TryGetInstanceExtension(instance, out khrSurface)) throw new Exception($"{KhrSurface.ExtensionName} extension not found.");
surface = window.VkSurface.Create<AllocationCallbacks>(instance.ToHandle(), null).ToSurface();

vk.TryGetInstanceExtension(instance, out debugUtils);
}
{ // Physical Device
uint deviceCount = 0;
Expand All @@ -32,8 +58,57 @@ public Application()
var devices = stackalloc PhysicalDevice[(int)deviceCount];
vk.EnumeratePhysicalDevices(instance, ref deviceCount, devices).Check();
physicalDevice = devices[0]; // idc
if (!vk.IsDeviceExtensionPresent(physicalDevice, KhrSwapchain.ExtensionName)) throw new Exception($"Physical device doesn't support ${KhrSwapchain.ExtensionName}");

uint queueFamilityCount = 0;
vk.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilityCount, null);
var queueFamilyProperties = stackalloc QueueFamilyProperties[(int)queueFamilityCount];
vk.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilityCount, queueFamilyProperties);

for (uint i = 0; i < queueFamilityCount; i++)
{
if (graphicsQueueFamily is uint.MaxValue && queueFamilyProperties[i].QueueFlags.HasFlag(QueueFlags.QueueGraphicsBit)) graphicsQueueFamily = i;
if (presentQueueFamily is uint.MaxValue)
{
khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice, i, surface, out Bool32 supported).Check();
if ((bool)supported is true) presentQueueFamily = i;
}
if ((graphicsQueueFamily | presentQueueFamily) is not uint.MaxValue) break;
}
if ((graphicsQueueFamily | presentQueueFamily) is uint.MaxValue) throw new Exception("Suitable queue families not found.");
}
{ // Device + Queues
float priority = 1.0f;
var queueCreateInfos = stackalloc DeviceQueueCreateInfo[2];
queueCreateInfos[0] = new(queueFamilyIndex: graphicsQueueFamily, queueCount: 1, pQueuePriorities: &priority);
queueCreateInfos[1] = new(queueFamilyIndex: presentQueueFamily, queueCount: 1, pQueuePriorities: &priority);

PhysicalDeviceFeatures physicalDeviceFeatures = new() { SamplerAnisotropy = true };

var extensions = new string[] { KhrSwapchain.ExtensionName };
byte** extensionsPtr = (byte**)SilkMarshal.StringArrayToPtr(extensions);

try
{
DeviceCreateInfo deviceCreateInfo = new(
queueCreateInfoCount: graphicsQueueFamily == presentQueueFamily ? 1u : 2u, pQueueCreateInfos: queueCreateInfos,
enabledExtensionCount: (uint)extensions.Length, ppEnabledExtensionNames: extensionsPtr,
pEnabledFeatures: &physicalDeviceFeatures);

vk.CreateDevice(physicalDevice, &deviceCreateInfo, null, out device).Check();

vk.GetDeviceQueue(device, graphicsQueueFamily, 0, out graphicsQueue);
if (graphicsQueueFamily == presentQueueFamily) presentQueue = graphicsQueue;
else vk.GetDeviceQueue(device, presentQueueFamily, 0, out presentQueue);
}
finally
{
for (uint i = 0; i < extensions.Length; i++) SilkMarshal.FreeString((nint)extensionsPtr[i]);
SilkMarshal.Free((nint)extensionsPtr);
}
}
Console.WriteLine();

Console.WriteLine($"Initialized Application in {stopwatch.Elapsed}");
}


Expand All @@ -45,7 +120,10 @@ public void Run()

void IDisposable.Dispose()
{
vk.DestroyDevice(device, null);
khrSurface.DestroySurface(instance, surface, null);
vk.DestroyInstance(instance, null);
vk.Dispose();
window.Dispose();
}
}

0 comments on commit 4c99bb9

Please sign in to comment.