parent
562882ad0d
commit
33da7b7761
60 changed files with 11439 additions and 30 deletions
24
OpenTK.sln
24
OpenTK.sln
|
@ -11,10 +11,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator.Rewrite", "src\Ge
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTK", "src\OpenTK\OpenTK.csproj", "{A37A7E14-0000-0000-0000-000000000000}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTK.Android", "src\OpenTK\OpenTK.Android.csproj", "{1648ACE1-E7D0-41CB-9A0E-C2A9D76C13A9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTK.iOS", "src\OpenTK\OpenTK.iOS.csproj", "{88368190-E3DF-4EBE-ACAA-7B1779F376CA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTK.GLControl", "src\OpenTK.GLControl\OpenTK.GLControl.csproj", "{A625BE88-0000-0000-0000-000000000000}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTK.GLWidget", "src\OpenTK.GLWidget\OpenTK.GLWidget.csproj", "{A625BE87-0000-0000-0000-000000000000}"
|
||||
|
@ -45,6 +41,10 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "OpenTK.Tests.Generators", "
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTK.Standard", "src\OpenTK\OpenTK.Standard.csproj", "{67F02FD3-8F7F-4D89-8551-359993271CA3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vk.generator", "src\vk.generator\vk.generator.csproj", "{3766DF33-E28B-402D-9EE1-975C2AFB5EAF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vk.rewrite", "src\vk.rewrite\vk.rewrite.csproj", "{3E9B1C4D-BCB4-418A-A94E-DD164A19C6A2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -67,14 +67,6 @@ Global
|
|||
{A37A7E14-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A37A7E14-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A37A7E14-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1648ACE1-E7D0-41CB-9A0E-C2A9D76C13A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1648ACE1-E7D0-41CB-9A0E-C2A9D76C13A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1648ACE1-E7D0-41CB-9A0E-C2A9D76C13A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1648ACE1-E7D0-41CB-9A0E-C2A9D76C13A9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{88368190-E3DF-4EBE-ACAA-7B1779F376CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{88368190-E3DF-4EBE-ACAA-7B1779F376CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{88368190-E3DF-4EBE-ACAA-7B1779F376CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{88368190-E3DF-4EBE-ACAA-7B1779F376CA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A625BE88-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A625BE88-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A625BE88-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -103,6 +95,14 @@ Global
|
|||
{67F02FD3-8F7F-4D89-8551-359993271CA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67F02FD3-8F7F-4D89-8551-359993271CA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{67F02FD3-8F7F-4D89-8551-359993271CA3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3766DF33-E28B-402D-9EE1-975C2AFB5EAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3766DF33-E28B-402D-9EE1-975C2AFB5EAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3766DF33-E28B-402D-9EE1-975C2AFB5EAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3766DF33-E28B-402D-9EE1-975C2AFB5EAF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3E9B1C4D-BCB4-418A-A94E-DD164A19C6A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3E9B1C4D-BCB4-418A-A94E-DD164A19C6A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3E9B1C4D-BCB4-418A-A94E-DD164A19C6A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3E9B1C4D-BCB4-418A-A94E-DD164A19C6A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
OpenTK
|
||||
======
|
||||
|
||||
This fork contains modified dependencies from mellinoe's Vulkan bindings, you can get the original from [here](https://github.com/mellinoe/vk).
|
||||
|
||||
|
||||
### MAINTAINERS WANTED
|
||||
|
||||
|
|
|
@ -164,9 +164,9 @@ namespace OpenTK
|
|||
return t != null;
|
||||
}
|
||||
|
||||
#if SDL2
|
||||
private static bool DetectSdl2()
|
||||
{
|
||||
#if SDL2
|
||||
bool supported = false;
|
||||
|
||||
// Detect whether SDL2 is supported
|
||||
|
@ -220,8 +220,10 @@ namespace OpenTK
|
|||
}
|
||||
|
||||
return supported;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void DetectUnix(out bool unix, out bool linux, out bool macos)
|
||||
{
|
||||
|
@ -298,7 +300,7 @@ namespace OpenTK
|
|||
|
||||
initialized = true;
|
||||
#endif
|
||||
Debug.Print("Detected configuration: {0} / {1}",
|
||||
Debug.Print("Detected configuration: {0} / {1}",
|
||||
RunningOnWindows ? "Windows" : RunningOnLinux ? "Linux" : RunningOnMacOS ? "MacOS" :
|
||||
runningOnUnix ? "Unix" : RunningOnX11 ? "X11" : "Unknown Platform",
|
||||
RunningOnMono ? "Mono" : ".Net");
|
||||
|
|
1
src/OpenTK/Graphics/Vulkan/.gitignore
vendored
Normal file
1
src/OpenTK/Graphics/Vulkan/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
Generated/
|
33
src/OpenTK/Graphics/Vulkan/BindingsHelpers.cs
Normal file
33
src/OpenTK/Graphics/Vulkan/BindingsHelpers.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public static class BindingsHelpers
|
||||
{
|
||||
public static unsafe StringHandle StringToHGlobalUtf8(string s)
|
||||
{
|
||||
int byteCount = Encoding.UTF8.GetByteCount(s);
|
||||
IntPtr retPtr = Marshal.AllocHGlobal(byteCount);
|
||||
fixed (char* stringPtr = s)
|
||||
{
|
||||
Encoding.UTF8.GetBytes(stringPtr, s.Length, (byte*)retPtr.ToPointer(), byteCount);
|
||||
}
|
||||
|
||||
return new StringHandle() { Handle = retPtr };
|
||||
}
|
||||
|
||||
public static void FreeHGlobal(StringHandle ptr)
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public struct StringHandle
|
||||
{
|
||||
public IntPtr Handle;
|
||||
}
|
||||
}
|
8
src/OpenTK/Graphics/Vulkan/CalliRewriteAttribute.cs
Normal file
8
src/OpenTK/Graphics/Vulkan/CalliRewriteAttribute.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan.Generator
|
||||
{
|
||||
internal class CalliRewriteAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
179
src/OpenTK/Graphics/Vulkan/Commands.cs
Normal file
179
src/OpenTK/Graphics/Vulkan/Commands.cs
Normal file
|
@ -0,0 +1,179 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public static partial class VK
|
||||
{
|
||||
private static NativeLibrary s_nativeLib;
|
||||
|
||||
static public void LoadFunctions()
|
||||
{
|
||||
if (s_nativeLib == null)
|
||||
{
|
||||
s_nativeLib = LoadNativeLibrary();
|
||||
}
|
||||
|
||||
LoadFunctionPointers();
|
||||
}
|
||||
|
||||
public static IntPtr LoadFunctionPointer(string functionName)
|
||||
{
|
||||
if (s_nativeLib == null)
|
||||
{
|
||||
s_nativeLib = LoadNativeLibrary();
|
||||
}
|
||||
|
||||
return s_nativeLib.LoadFunctionPointer(functionName);
|
||||
}
|
||||
|
||||
private static NativeLibrary LoadNativeLibrary()
|
||||
{
|
||||
return NativeLibrary.Load(GetVulkanName());
|
||||
}
|
||||
|
||||
private static string GetVulkanName()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return "vulkan-1.dll";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
if (RuntimeInformation.OSDescription.Contains("Unix"))
|
||||
{
|
||||
// Android
|
||||
return "libvulkan.so";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Desktop Linux
|
||||
return "libvulkan.so.1";
|
||||
}
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return "libvulkan.dylib";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static Exception CreateMissingFunctionException()
|
||||
{
|
||||
return new InvalidOperationException("The function does not exist or could not be loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class NativeLibrary : IDisposable
|
||||
{
|
||||
private readonly string _libraryName;
|
||||
private readonly IntPtr _libraryHandle;
|
||||
|
||||
public IntPtr NativeHandle => _libraryHandle;
|
||||
|
||||
public NativeLibrary(string libraryName)
|
||||
{
|
||||
_libraryName = libraryName;
|
||||
_libraryHandle = LoadLibrary(_libraryName);
|
||||
if (_libraryHandle == IntPtr.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("Could not load " + libraryName);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract IntPtr LoadLibrary(string libraryName);
|
||||
protected abstract void FreeLibrary(IntPtr libraryHandle);
|
||||
protected abstract IntPtr LoadFunction(string functionName);
|
||||
|
||||
public IntPtr LoadFunctionPointer(string functionName)
|
||||
{
|
||||
if (functionName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(functionName));
|
||||
}
|
||||
|
||||
return LoadFunction(functionName);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
FreeLibrary(_libraryHandle);
|
||||
}
|
||||
|
||||
|
||||
public static NativeLibrary Load(string libraryName)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return new WindowsNativeLibrary(libraryName);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|
||||
|| RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return new UnixNativeLibrary(libraryName);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException("Cannot load native libraries on this platform: " + RuntimeInformation.OSDescription);
|
||||
}
|
||||
}
|
||||
|
||||
private class WindowsNativeLibrary : NativeLibrary
|
||||
{
|
||||
public WindowsNativeLibrary(string libraryName) : base(libraryName)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IntPtr LoadLibrary(string libraryName)
|
||||
{
|
||||
return Kernel32.LoadLibrary(libraryName);
|
||||
}
|
||||
|
||||
protected override void FreeLibrary(IntPtr libraryHandle)
|
||||
{
|
||||
Kernel32.FreeLibrary(libraryHandle);
|
||||
}
|
||||
|
||||
protected override IntPtr LoadFunction(string functionName)
|
||||
{
|
||||
Debug.WriteLine("Loading " + functionName);
|
||||
return Kernel32.GetProcAddress(NativeHandle, functionName);
|
||||
}
|
||||
}
|
||||
|
||||
private class UnixNativeLibrary : NativeLibrary
|
||||
{
|
||||
public UnixNativeLibrary(string libraryName) : base(libraryName)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IntPtr LoadLibrary(string libraryName)
|
||||
{
|
||||
Libdl.dlerror();
|
||||
IntPtr handle = Libdl.dlopen(libraryName, Libdl.RTLD_NOW);
|
||||
if (handle == IntPtr.Zero && !Path.IsPathRooted(libraryName))
|
||||
{
|
||||
string localPath = Path.Combine(AppContext.BaseDirectory, libraryName);
|
||||
handle = Libdl.dlopen(localPath, Libdl.RTLD_NOW);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
protected override void FreeLibrary(IntPtr libraryHandle)
|
||||
{
|
||||
Libdl.dlclose(libraryHandle);
|
||||
}
|
||||
|
||||
protected override IntPtr LoadFunction(string functionName)
|
||||
{
|
||||
return Libdl.dlsym(NativeHandle, functionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
src/OpenTK/Graphics/Vulkan/Constants.cs
Normal file
9
src/OpenTK/Graphics/Vulkan/Constants.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public static partial class VK
|
||||
{
|
||||
public static readonly IntPtr NullHandle = IntPtr.Zero;
|
||||
}
|
||||
}
|
45
src/OpenTK/Graphics/Vulkan/Delegates.cs
Normal file
45
src/OpenTK/Graphics/Vulkan/Delegates.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public unsafe delegate void* PFN_vkAllocationFunction(
|
||||
void* pUserData,
|
||||
UIntPtr size,
|
||||
UIntPtr alignment,
|
||||
VkSystemAllocationScope allocationScope);
|
||||
|
||||
public unsafe delegate void* PFN_vkReallocationFunction(
|
||||
void* pUserData,
|
||||
void* pOriginal,
|
||||
UIntPtr size,
|
||||
UIntPtr alignment,
|
||||
VkSystemAllocationScope allocationScope);
|
||||
|
||||
public unsafe delegate void PFN_vkFreeFunction(
|
||||
void* pUserData,
|
||||
void* pMemory);
|
||||
|
||||
public unsafe delegate void PFN_vkInternalAllocationNotification(
|
||||
void* pUserData,
|
||||
UIntPtr size,
|
||||
VkInternalAllocationType allocationType,
|
||||
VkSystemAllocationScope allocationScope);
|
||||
|
||||
public unsafe delegate void PFN_vkInternalFreeNotification(
|
||||
void* pUserData,
|
||||
UIntPtr size,
|
||||
VkInternalAllocationType allocationType,
|
||||
VkSystemAllocationScope allocationScope);
|
||||
|
||||
public unsafe delegate void PFN_vkVoidFunction();
|
||||
|
||||
public unsafe delegate uint PFN_vkDebugReportCallbackEXT(
|
||||
uint flags,
|
||||
VkDebugReportObjectTypeEXT objectType,
|
||||
ulong @object,
|
||||
UIntPtr location,
|
||||
int messageCode,
|
||||
byte* pLayerPrefix,
|
||||
byte* pMessage,
|
||||
void* pUserData);
|
||||
}
|
83
src/OpenTK/Graphics/Vulkan/ExternalTypes.cs
Normal file
83
src/OpenTK/Graphics/Vulkan/ExternalTypes.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
// Windows
|
||||
|
||||
namespace Win32
|
||||
{
|
||||
public struct HINSTANCE
|
||||
{
|
||||
public IntPtr Handle;
|
||||
public static implicit operator IntPtr(HINSTANCE hinst) => hinst.Handle;
|
||||
public static implicit operator HINSTANCE(IntPtr handle) => new HINSTANCE() { Handle = handle };
|
||||
}
|
||||
|
||||
public struct HWND
|
||||
{
|
||||
public IntPtr Handle;
|
||||
public static implicit operator IntPtr(HWND hwnd) => hwnd.Handle;
|
||||
public static implicit operator HWND(IntPtr handle) => new HWND() { Handle = handle };
|
||||
}
|
||||
|
||||
public struct HANDLE
|
||||
{
|
||||
public IntPtr Handle;
|
||||
public static implicit operator IntPtr(HANDLE handle) => handle.Handle;
|
||||
public static implicit operator HANDLE(IntPtr handle) => new HANDLE() { Handle = handle };
|
||||
}
|
||||
|
||||
public struct SECURITY_ATTRIBUTES
|
||||
{
|
||||
public uint nLength;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public uint bInheritHandle;
|
||||
}
|
||||
}
|
||||
|
||||
// Android
|
||||
namespace Android
|
||||
{
|
||||
public struct ANativeWindow { }
|
||||
}
|
||||
|
||||
// Linux
|
||||
namespace Mir
|
||||
{
|
||||
public struct MirConnection { }
|
||||
public struct MirSurface { }
|
||||
}
|
||||
|
||||
namespace Wayland
|
||||
{
|
||||
public struct wl_display { }
|
||||
public struct wl_surface { }
|
||||
}
|
||||
|
||||
namespace Xlib
|
||||
{
|
||||
public struct Display { }
|
||||
public struct Window
|
||||
{
|
||||
public IntPtr Value;
|
||||
}
|
||||
public struct VisualID
|
||||
{
|
||||
public ulong ID;
|
||||
public static implicit operator VisualID(ulong value) => new VisualID() { ID = value };
|
||||
public static implicit operator ulong(VisualID id) => id.ID;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Xcb
|
||||
{
|
||||
public struct xcb_connection_t { }
|
||||
public struct xcb_window_t { }
|
||||
public struct xcb_visualid_t
|
||||
{
|
||||
public uint ID;
|
||||
public static implicit operator xcb_visualid_t(uint value) => new xcb_visualid_t() { ID = value };
|
||||
public static implicit operator uint(xcb_visualid_t id) => id.ID;
|
||||
}
|
||||
}
|
||||
}
|
15
src/OpenTK/Graphics/Vulkan/FunctionPointer.cs
Normal file
15
src/OpenTK/Graphics/Vulkan/FunctionPointer.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public struct FunctionPointer<TFunc>
|
||||
{
|
||||
public IntPtr Pointer;
|
||||
|
||||
public FunctionPointer(TFunc func)
|
||||
{
|
||||
Pointer = Marshal.GetFunctionPointerForDelegate(func);
|
||||
}
|
||||
}
|
||||
}
|
17
src/OpenTK/Graphics/Vulkan/Kernel32.cs
Normal file
17
src/OpenTK/Graphics/Vulkan/Kernel32.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
internal static class Kernel32
|
||||
{
|
||||
[DllImport("kernel32")]
|
||||
public static extern IntPtr LoadLibrary(string fileName);
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern IntPtr GetProcAddress(IntPtr module, string procName);
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern int FreeLibrary(IntPtr module);
|
||||
}
|
||||
}
|
22
src/OpenTK/Graphics/Vulkan/Libdl.cs
Normal file
22
src/OpenTK/Graphics/Vulkan/Libdl.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
internal static class Libdl
|
||||
{
|
||||
[DllImport("libdl")]
|
||||
public static extern IntPtr dlopen(string fileName, int flags);
|
||||
|
||||
[DllImport("libdl")]
|
||||
public static extern IntPtr dlsym(IntPtr handle, string name);
|
||||
|
||||
[DllImport("libdl")]
|
||||
public static extern int dlclose(IntPtr handle);
|
||||
|
||||
[DllImport("libdl")]
|
||||
public static extern string dlerror();
|
||||
|
||||
public const int RTLD_NOW = 0x002;
|
||||
}
|
||||
}
|
68
src/OpenTK/Graphics/Vulkan/VkBool32.cs
Normal file
68
src/OpenTK/Graphics/Vulkan/VkBool32.cs
Normal file
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
/// <summary>
|
||||
/// A boolean value stored in a 4-byte unsigned integer.
|
||||
/// </summary>
|
||||
public struct VkBool32 : IEquatable<VkBool32>
|
||||
{
|
||||
/// <summary>
|
||||
/// The raw value of the <see cref="VkBool32"/>. A value of 0 represents "false", all other values represent "true".
|
||||
/// </summary>
|
||||
public uint Value;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <see cref="VkBool32"/> with the given raw value.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public VkBool32(uint value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the boolean "true" value. Has a raw value of 1.
|
||||
/// </summary>
|
||||
public static readonly VkBool32 True = new VkBool32(1);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the boolean "true" value. Has a raw value of 0.
|
||||
/// </summary>
|
||||
public static readonly VkBool32 False = new VkBool32(0);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether another <see cref="VkBool32"/> value is considered equal to this one.
|
||||
/// Two <see cref="VkBool32"/>s are considered equal when their raw values are equal.
|
||||
/// </summary>
|
||||
/// <param name="other">The value to compare to.</param>
|
||||
/// <returns>True if the other value's underlying raw value is equal to this instance's. False otherwise.</returns>
|
||||
public bool Equals(VkBool32 other)
|
||||
{
|
||||
return Value.Equals(other.Value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is VkBool32 b && Equals(b);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{(this ? "True" : "False")} ({Value})";
|
||||
}
|
||||
|
||||
public static implicit operator bool(VkBool32 b) => b.Value != 0;
|
||||
public static implicit operator uint(VkBool32 b) => b.Value;
|
||||
public static implicit operator VkBool32(bool b) => b ? True : False;
|
||||
public static implicit operator VkBool32(uint value) => new VkBool32(value);
|
||||
|
||||
public static bool operator ==(VkBool32 left, VkBool32 right) => left.Value == right.Value;
|
||||
public static bool operator !=(VkBool32 left, VkBool32 right) => left.Value != right.Value;
|
||||
}
|
||||
}
|
33
src/OpenTK/Graphics/Vulkan/VkClearColorValue.cs
Normal file
33
src/OpenTK/Graphics/Vulkan/VkClearColorValue.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public partial struct VkClearColorValue
|
||||
{
|
||||
public VkClearColorValue(float r, float g, float b, float a = 1.0f) : this()
|
||||
{
|
||||
float32_0 = r;
|
||||
float32_1 = g;
|
||||
float32_2 = b;
|
||||
float32_3 = a;
|
||||
}
|
||||
|
||||
public VkClearColorValue(int r, int g, int b, int a = 255) : this()
|
||||
{
|
||||
int32_0 = r;
|
||||
int32_1 = g;
|
||||
int32_2 = b;
|
||||
int32_3 = a;
|
||||
}
|
||||
|
||||
public VkClearColorValue(uint r, uint g, uint b, uint a = 255) : this()
|
||||
{
|
||||
uint32_0 = r;
|
||||
uint32_1 = g;
|
||||
uint32_2 = b;
|
||||
uint32_3 = a;
|
||||
}
|
||||
}
|
||||
}
|
16
src/OpenTK/Graphics/Vulkan/VkClearDepthStencilValue.cs
Normal file
16
src/OpenTK/Graphics/Vulkan/VkClearDepthStencilValue.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public unsafe partial struct VkClearDepthStencilValue
|
||||
{
|
||||
public VkClearDepthStencilValue(float depth, uint stencil)
|
||||
{
|
||||
this.depth = depth;
|
||||
this.stencil = stencil;
|
||||
}
|
||||
}
|
||||
}
|
107
src/OpenTK/Graphics/Vulkan/VkExtent2D.cs
Normal file
107
src/OpenTK/Graphics/Vulkan/VkExtent2D.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure specifying a two-dimensional extent.
|
||||
/// </summary>
|
||||
public unsafe partial struct VkExtent2D : IEquatable<VkExtent2D>
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="VkExtent2D"/> with all of its components set to zero.
|
||||
/// </summary>
|
||||
public static readonly VkExtent2D Zero = new VkExtent2D(0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="VkExtent2D"/> structure.
|
||||
/// </summary>
|
||||
/// <param name="width">The width component of the extent.</param>
|
||||
/// <param name="height">The height component of the extent.</param>
|
||||
public VkExtent2D(uint width, uint height)
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="VkExtent2D"/> structure.
|
||||
/// </summary>
|
||||
/// <param name="width">The width component of the extent.</param>
|
||||
/// <param name="height">The height component of the extent.</param>
|
||||
public VkExtent2D(int width, int height)
|
||||
{
|
||||
this.width = (uint)width;
|
||||
this.height = (uint)height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VkExtent2D"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The <see cref="VkExtent2D"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="VkExtent2D"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool Equals(ref VkExtent2D other)
|
||||
{
|
||||
return other.width == width && other.height == height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VkExtent2D"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The <see cref="VkExtent2D"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="VkExtent2D"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool Equals(VkExtent2D other)
|
||||
{
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="object"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is VkExtent2D && Equals((VkExtent2D)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>The hash code.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hashCode = width.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ height.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a boolean indicating whether the two given extents are equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first extent to compare.</param>
|
||||
/// <param name="right">The second extent to compare.</param>
|
||||
/// <returns><c>true</c> if the extents are equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator ==(VkExtent2D left, VkExtent2D right) => left.Equals(ref right);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a boolean indicating whether the two given extents are not equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first extent to compare.</param>
|
||||
/// <param name="right">The second extent to compare.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the extents are not equal; <c>false</c> if they are equal.
|
||||
/// </returns>
|
||||
public static bool operator !=(VkExtent2D left, VkExtent2D right) => !left.Equals(ref right);
|
||||
}
|
||||
}
|
27
src/OpenTK/Graphics/Vulkan/VkImageMemoryBarrier.cs
Normal file
27
src/OpenTK/Graphics/Vulkan/VkImageMemoryBarrier.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public unsafe partial struct VkImageMemoryBarrier
|
||||
{
|
||||
public VkImageMemoryBarrier(
|
||||
VkImage image,
|
||||
VkImageSubresourceRange subresourceRange,
|
||||
VkAccessFlags srcAccessMask,
|
||||
VkAccessFlags dstAccessMask,
|
||||
VkImageLayout oldLayout,
|
||||
VkImageLayout newLayout,
|
||||
uint srcQueueFamilyIndex = VK.QueueFamilyIgnored,
|
||||
uint dstQueueFamilyIndex = VK.QueueFamilyIgnored)
|
||||
{
|
||||
sType = VkStructureType.ImageMemoryBarrier;
|
||||
pNext = null;
|
||||
this.srcAccessMask = srcAccessMask;
|
||||
this.dstAccessMask = dstAccessMask;
|
||||
this.oldLayout = oldLayout;
|
||||
this.newLayout = newLayout;
|
||||
this.srcQueueFamilyIndex = srcQueueFamilyIndex;
|
||||
this.dstQueueFamilyIndex = dstQueueFamilyIndex;
|
||||
this.image = image;
|
||||
this.subresourceRange = subresourceRange;
|
||||
}
|
||||
}
|
||||
}
|
17
src/OpenTK/Graphics/Vulkan/VkImageSubresourceRange.cs
Normal file
17
src/OpenTK/Graphics/Vulkan/VkImageSubresourceRange.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public unsafe partial struct VkImageSubresourceRange
|
||||
{
|
||||
public VkImageSubresourceRange(
|
||||
VkImageAspectFlags aspectMask,
|
||||
uint baseMipLevel = 0, uint levelCount = 1,
|
||||
uint baseArrayLayer = 0, uint layerCount = 1)
|
||||
{
|
||||
this.aspectMask = aspectMask;
|
||||
this.baseMipLevel = baseMipLevel;
|
||||
this.levelCount = levelCount;
|
||||
this.baseArrayLayer = baseArrayLayer;
|
||||
this.layerCount = layerCount;
|
||||
}
|
||||
}
|
||||
}
|
91
src/OpenTK/Graphics/Vulkan/VkOffset2D.cs
Normal file
91
src/OpenTK/Graphics/Vulkan/VkOffset2D.cs
Normal file
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure specifying a two-dimensional offset.
|
||||
/// </summary>
|
||||
public unsafe partial struct VkOffset2D : IEquatable<VkOffset2D>
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="VkOffset2D"/> with all of its components set to zero.
|
||||
/// </summary>
|
||||
public static readonly VkOffset2D Zero;
|
||||
|
||||
public VkOffset2D(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VkOffset2D"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The <see cref="VkOffset2D"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="VkOffset2D"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool Equals(ref VkOffset2D other)
|
||||
{
|
||||
return other.x == x && other.y == y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VkOffset2D"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The <see cref="VkOffset2D"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="VkOffset2D"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool Equals(VkOffset2D other)
|
||||
{
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="object"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is VkOffset2D && Equals((VkOffset2D)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>The hash code.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hashCode = x;
|
||||
hashCode = (hashCode * 397) ^ y;
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a boolean indicating whether the two given offsets are equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first offset to compare.</param>
|
||||
/// <param name="right">The second offset to compare.</param>
|
||||
/// <returns><c>true</c> if the offsets are equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator ==(VkOffset2D left, VkOffset2D right) => left.Equals(ref right);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a boolean indicating whether the two given offsets are not equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first offset to compare.</param>
|
||||
/// <param name="right">The second offset to compare.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the offsets are not equal; <c>false</c> if they are equal.
|
||||
/// </returns>
|
||||
public static bool operator !=(VkOffset2D left, VkOffset2D right) => !left.Equals(ref right);
|
||||
}
|
||||
}
|
143
src/OpenTK/Graphics/Vulkan/VkRect2D.cs
Normal file
143
src/OpenTK/Graphics/Vulkan/VkRect2D.cs
Normal file
|
@ -0,0 +1,143 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure specifying a two-dimensional subregion.
|
||||
/// </summary>
|
||||
public unsafe partial struct VkRect2D : IEquatable<VkRect2D>
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="VkRect2D"/> with all of its components set to zero.
|
||||
/// </summary>
|
||||
public static readonly VkRect2D Zero = new VkRect2D(VkOffset2D.Zero, VkExtent2D.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VkRect2D"/> structure.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset component of the rectangle.</param>
|
||||
/// <param name="extent">The extent component of the rectangle.</param>
|
||||
public VkRect2D(VkOffset2D offset, VkExtent2D extent)
|
||||
{
|
||||
this.offset = offset;
|
||||
this.extent = extent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VkRect2D"/> structure.
|
||||
/// </summary>
|
||||
/// <param name="extent">The extent component of the rectangle.</param>
|
||||
public VkRect2D(VkExtent2D extent)
|
||||
{
|
||||
this.offset = default(VkOffset2D);
|
||||
this.extent = extent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Rect2D"/> structure.
|
||||
/// </summary>
|
||||
/// <param name="x">The X component of the offset.</param>
|
||||
/// <param name="y">The Y component of the offset.</param>
|
||||
/// <param name="width">The width component of the extent.</param>
|
||||
/// <param name="height">The height component of the extent.</param>
|
||||
public VkRect2D(int x, int y, uint width, uint height)
|
||||
{
|
||||
this.offset = new VkOffset2D(x, y);
|
||||
this.extent = new VkExtent2D(width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Rect2D"/> structure.
|
||||
/// </summary>
|
||||
/// <param name="x">The X component of the offset.</param>
|
||||
/// <param name="y">The Y component of the offset.</param>
|
||||
/// <param name="width">The width component of the extent.</param>
|
||||
/// <param name="height">The height component of the extent.</param>
|
||||
public VkRect2D(int x, int y, int width, int height)
|
||||
{
|
||||
this.offset = new VkOffset2D(x, y);
|
||||
this.extent = new VkExtent2D(width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Rect2D"/> structure.
|
||||
/// </summary>
|
||||
/// <param name="width">The width component of the extent.</param>
|
||||
/// <param name="height">The height component of the extent.</param>
|
||||
public VkRect2D(uint width, uint height)
|
||||
{
|
||||
this.offset = default(VkOffset2D);
|
||||
this.extent = new VkExtent2D(width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VkRect2D"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The <see cref="VkRect2D"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="VkOffset2D"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool Equals(ref VkRect2D other)
|
||||
{
|
||||
return other.offset.Equals(ref offset) && other.extent.Equals(ref extent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VkRect2D"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The <see cref="VkRect2D"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="VkRect2D"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool Equals(VkRect2D other)
|
||||
{
|
||||
return Equals(ref other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="object"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is VkRect2D && Equals((VkRect2D)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>The hash code.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hashCode = extent.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ offset.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a boolean indicating whether the two given rectangles are equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first rectangle to compare.</param>
|
||||
/// <param name="right">The second rectangle to compare.</param>
|
||||
/// <returns><c>true</c> if the rectangles are equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator ==(VkRect2D left, VkRect2D right) => left.Equals(right);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a boolean indicating whether the two given rectangles are not equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first rectangle to compare.</param>
|
||||
/// <param name="right">The second rectangle to compare.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the rectangles are not equal; <c>false</c> if they are equal.
|
||||
/// </returns>
|
||||
public static bool operator !=(VkRect2D left, VkRect2D right) => !left.Equals(right);
|
||||
}
|
||||
}
|
552
src/OpenTK/Graphics/Vulkan/VulkanList.cs
Normal file
552
src/OpenTK/Graphics/Vulkan/VulkanList.cs
Normal file
|
@ -0,0 +1,552 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
#if !VALIDATE
|
||||
using System.Diagnostics;
|
||||
#endif
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
|
||||
public unsafe class VulkanList<T> : IEnumerable<T>, IDisposable where T : struct
|
||||
{
|
||||
private byte* _dataPtr;
|
||||
private uint _elementCapacity;
|
||||
private uint _count;
|
||||
|
||||
public const int DefaultCapacity = 4;
|
||||
private const float GrowthFactor = 2f;
|
||||
private static readonly uint s_elementByteSize = InitializeTypeSize();
|
||||
|
||||
public VulkanList() : this(DefaultCapacity) { }
|
||||
public VulkanList(uint capacity)
|
||||
{
|
||||
Allocate(capacity);
|
||||
}
|
||||
|
||||
public VulkanList(uint capacity, uint count)
|
||||
{
|
||||
Allocate(capacity);
|
||||
Count = count;
|
||||
}
|
||||
|
||||
public VulkanList(VulkanList<T> existingList)
|
||||
{
|
||||
Allocate(existingList._elementCapacity);
|
||||
Unsafe.CopyBlock(_dataPtr, existingList._dataPtr, existingList._count * s_elementByteSize);
|
||||
}
|
||||
|
||||
public static VulkanList<T> New(uint count)
|
||||
{
|
||||
return new VulkanList<T>(count, count);
|
||||
}
|
||||
|
||||
public IntPtr Data
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return new IntPtr(_dataPtr);
|
||||
}
|
||||
}
|
||||
|
||||
public uint Count
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return _count;
|
||||
}
|
||||
set
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (value > _elementCapacity)
|
||||
{
|
||||
uint newLements = value - Count;
|
||||
CoreResize(value);
|
||||
Unsafe.InitBlock(_dataPtr + _count * s_elementByteSize, 0, newLements * s_elementByteSize);
|
||||
}
|
||||
|
||||
_count = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ref T this[uint index]
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
#if VALIDATE
|
||||
if (index >= _count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
#else
|
||||
Debug.Assert(index < _count);
|
||||
#endif
|
||||
return ref Unsafe.AsRef<T>(_dataPtr + index * s_elementByteSize);
|
||||
}
|
||||
}
|
||||
|
||||
public ref T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
#if VALIDATE
|
||||
if (index < 0 || index >= _count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
#else
|
||||
Debug.Assert(index >= 0 && index < _count);
|
||||
#endif
|
||||
return ref Unsafe.AsRef<T>(_dataPtr + index * s_elementByteSize);
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyNativeListView<T> GetReadOnlyView()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return new ReadOnlyNativeListView<T>(this, 0, _count);
|
||||
}
|
||||
|
||||
public ReadOnlyNativeListView<T> GetReadOnlyView(uint start, uint count)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
#if VALIDATE
|
||||
if (start + count > _count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
#else
|
||||
Debug.Assert(start + count <= _count);
|
||||
#endif
|
||||
return new ReadOnlyNativeListView<T>(this, start, count);
|
||||
}
|
||||
|
||||
public View<ViewType> GetView<ViewType>() where ViewType : struct
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return new View<ViewType>(this);
|
||||
}
|
||||
|
||||
public bool IsDisposed => _dataPtr == null;
|
||||
|
||||
public void Add(ref T item)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (_count == _elementCapacity)
|
||||
{
|
||||
CoreResize((uint)(_elementCapacity * GrowthFactor));
|
||||
}
|
||||
|
||||
Unsafe.Copy(_dataPtr + _count * s_elementByteSize, ref item);
|
||||
_count += 1;
|
||||
}
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (_count == _elementCapacity)
|
||||
{
|
||||
CoreResize((uint)(_elementCapacity * GrowthFactor));
|
||||
}
|
||||
|
||||
Unsafe.Write(_dataPtr + _count * s_elementByteSize, item);
|
||||
_count += 1;
|
||||
}
|
||||
|
||||
public void Add(void* data, uint numElements)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
uint needed = _count + numElements;
|
||||
if (numElements > _elementCapacity)
|
||||
{
|
||||
CoreResize((uint)(needed * GrowthFactor));
|
||||
}
|
||||
|
||||
Unsafe.CopyBlock(_dataPtr + _count * s_elementByteSize, data, numElements * s_elementByteSize);
|
||||
_count += numElements;
|
||||
}
|
||||
|
||||
public bool Remove(ref T item)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
bool result = IndexOf(ref item, out uint index);
|
||||
if (result)
|
||||
{
|
||||
CoreRemoveAt(index);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool Remove(T item) => Remove(ref item);
|
||||
|
||||
public void RemoveAt(uint index)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
#if VALIDATE
|
||||
if (index >= _count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
#else
|
||||
Debug.Assert(index < _count);
|
||||
#endif
|
||||
CoreRemoveAt(index);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
public bool IndexOf(ref T item, out uint index)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
byte* itemPtr = (byte*)Unsafe.AsPointer(ref item);
|
||||
for (index = 0; index < _count; index++)
|
||||
{
|
||||
byte* ptr = _dataPtr + index * s_elementByteSize;
|
||||
if (Equals(ptr, itemPtr, s_elementByteSize))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IndexOf(T item, out uint index)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
byte* itemPtr = (byte*)Unsafe.AsPointer(ref item);
|
||||
for (index = 0; index < _count; index++)
|
||||
{
|
||||
byte* ptr = _dataPtr + index * s_elementByteSize;
|
||||
if (Equals(ptr, itemPtr, s_elementByteSize))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IntPtr GetAddress(uint index)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
#if VALIDATE
|
||||
if (index >= _count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
#else
|
||||
Debug.Assert(index < _count);
|
||||
#endif
|
||||
return new IntPtr(_dataPtr + (index * s_elementByteSize));
|
||||
}
|
||||
|
||||
public void Resize(uint elementCount)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
CoreResize(elementCount);
|
||||
if (_elementCapacity < _count)
|
||||
{
|
||||
_count = _elementCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
private static uint InitializeTypeSize()
|
||||
{
|
||||
#if VALIDATE
|
||||
// TODO: DHetermine if the structure type contains references and throw if it does.
|
||||
// https://github.com/dotnet/corefx/issues/14047
|
||||
#endif
|
||||
return (uint)Unsafe.SizeOf<T>();
|
||||
}
|
||||
|
||||
private void CoreResize(uint elementCount)
|
||||
{
|
||||
_dataPtr = (byte*)Marshal.ReAllocHGlobal(new IntPtr(_dataPtr), (IntPtr)(elementCount * s_elementByteSize));
|
||||
_elementCapacity = elementCount;
|
||||
}
|
||||
|
||||
private void Allocate(uint elementCount)
|
||||
{
|
||||
_dataPtr = (byte*)Marshal.AllocHGlobal((int)(elementCount * s_elementByteSize));
|
||||
_elementCapacity = elementCount;
|
||||
}
|
||||
|
||||
private bool Equals(byte* ptr, byte* itemPtr, uint s_elementByteSize)
|
||||
{
|
||||
for (int i = 0; i < s_elementByteSize; i++)
|
||||
{
|
||||
if (ptr[i] != itemPtr[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void CoreRemoveAt(uint index)
|
||||
{
|
||||
Unsafe.CopyBlock(_dataPtr + index * s_elementByteSize, _dataPtr + (_count - 1) * s_elementByteSize, s_elementByteSize);
|
||||
_count -= 1;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#if !VALIDATE
|
||||
[Conditional("DEBUG")]
|
||||
#endif
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
#if VALIDATE
|
||||
if (_dataPtr == null)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(Data));
|
||||
}
|
||||
#else
|
||||
Debug.Assert(_dataPtr != null, "NativeList is disposed.");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
Marshal.FreeHGlobal(new IntPtr(_dataPtr));
|
||||
_dataPtr = null;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
~NativeList()
|
||||
{
|
||||
if (_dataPtr != null)
|
||||
{
|
||||
Debug.WriteLine($"A NativeList<{typeof(T).Name}> was not properly disposed.");
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return new Enumerator(_dataPtr, _count);
|
||||
}
|
||||
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
private byte* _basePtr;
|
||||
private uint _count;
|
||||
private uint _currentIndex;
|
||||
private T _current;
|
||||
|
||||
public Enumerator(byte* basePtr, uint count)
|
||||
{
|
||||
_basePtr = basePtr;
|
||||
_count = count;
|
||||
_currentIndex = 0;
|
||||
_current = default(T);
|
||||
}
|
||||
|
||||
public T Current => _current;
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_currentIndex != _count)
|
||||
{
|
||||
_current = Unsafe.Read<T>(_basePtr + _currentIndex * s_elementByteSize);
|
||||
_currentIndex += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_current = default(T);
|
||||
_currentIndex = 0;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
public struct View<ViewType> : IEnumerable<ViewType> where ViewType : struct
|
||||
{
|
||||
private static readonly uint s_elementByteSize = (uint)Unsafe.SizeOf<ViewType>();
|
||||
private readonly VulkanList<T> _parent;
|
||||
|
||||
public View(VulkanList<T> parent)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public uint Count => (_parent.Count * VulkanList<T>.s_elementByteSize) / s_elementByteSize;
|
||||
|
||||
public ViewType this[uint index]
|
||||
{
|
||||
get
|
||||
{
|
||||
#if VALIDATE
|
||||
if (index >= Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
#else
|
||||
Debug.Assert(index < Count);
|
||||
#endif
|
||||
return Unsafe.Read<ViewType>(_parent._dataPtr + index * s_elementByteSize);
|
||||
}
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator() => new Enumerator(this);
|
||||
|
||||
IEnumerator<ViewType> IEnumerable<ViewType>.GetEnumerator() => GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public struct Enumerator : IEnumerator<ViewType>
|
||||
{
|
||||
private View<ViewType> _view;
|
||||
private uint _currentIndex;
|
||||
private ViewType _current;
|
||||
|
||||
public Enumerator(View<ViewType> view)
|
||||
{
|
||||
_view = view;
|
||||
_currentIndex = 0;
|
||||
_current = default(ViewType);
|
||||
}
|
||||
|
||||
public ViewType Current => _view[_currentIndex];
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_currentIndex != _view.Count)
|
||||
{
|
||||
_current = _view[_currentIndex];
|
||||
_currentIndex += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_currentIndex = 0;
|
||||
_current = default(ViewType);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct ReadOnlyNativeListView<T> : IEnumerable<T> where T : struct
|
||||
{
|
||||
private readonly VulkanList<T> _list;
|
||||
private readonly uint _start;
|
||||
public readonly uint Count;
|
||||
|
||||
public ReadOnlyNativeListView(VulkanList<T> list, uint start, uint count)
|
||||
{
|
||||
_list = list;
|
||||
_start = start;
|
||||
Count = count;
|
||||
}
|
||||
|
||||
public T this[uint index]
|
||||
{
|
||||
get
|
||||
{
|
||||
#if VALIDATE
|
||||
if (index >= Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
#else
|
||||
Debug.Assert(index < Count);
|
||||
#endif
|
||||
return _list[index + _start];
|
||||
}
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
#if VALIDATE
|
||||
if (index < 0 || index >= Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
#else
|
||||
Debug.Assert(index >= 0 && index < Count);
|
||||
#endif
|
||||
return _list[(uint)index + _start];
|
||||
}
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator() => new Enumerator(this);
|
||||
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
private ReadOnlyNativeListView<T> _view;
|
||||
private uint _currentIndex;
|
||||
private T _current;
|
||||
|
||||
public Enumerator(ReadOnlyNativeListView<T> view)
|
||||
{
|
||||
_view = view;
|
||||
_currentIndex = view._start;
|
||||
_current = default(T);
|
||||
}
|
||||
|
||||
public T Current => _view[_currentIndex];
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_currentIndex != _view._start + _view.Count)
|
||||
{
|
||||
_current = _view[_currentIndex];
|
||||
_currentIndex += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_currentIndex = _view._start;
|
||||
_current = default(T);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
}
|
54
src/OpenTK/Graphics/Vulkan/VulkanString.cs
Normal file
54
src/OpenTK/Graphics/Vulkan/VulkanString.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public unsafe class VulkanString : IDisposable
|
||||
{
|
||||
private GCHandle _handle;
|
||||
private uint _numBytes;
|
||||
|
||||
public byte* StringPtr => (byte*)_handle.AddrOfPinnedObject().ToPointer();
|
||||
|
||||
public VulkanString(string s)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(s));
|
||||
}
|
||||
|
||||
byte[] text = Encoding.UTF8.GetBytes(s);
|
||||
_handle = GCHandle.Alloc(text, GCHandleType.Pinned);
|
||||
_numBytes = (uint)text.Length;
|
||||
}
|
||||
|
||||
public void SetText(string s)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(s));
|
||||
}
|
||||
|
||||
_handle.Free();
|
||||
byte[] text = Encoding.UTF8.GetBytes(s);
|
||||
_handle = GCHandle.Alloc(text, GCHandleType.Pinned);
|
||||
_numBytes = (uint)text.Length;
|
||||
}
|
||||
|
||||
private string GetString()
|
||||
{
|
||||
return Encoding.UTF8.GetString(StringPtr, (int)_numBytes);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_handle.Free();
|
||||
}
|
||||
|
||||
public static implicit operator byte* (VulkanString utf8String) => utf8String.StringPtr;
|
||||
public static implicit operator IntPtr (VulkanString utf8String) => new IntPtr(utf8String.StringPtr);
|
||||
public static implicit operator VulkanString(string s) => new VulkanString(s);
|
||||
public static implicit operator string(VulkanString utf8String) => utf8String.GetString();
|
||||
}
|
||||
}
|
14
src/OpenTK/Graphics/Vulkan/VulkanStrings.cs
Normal file
14
src/OpenTK/Graphics/Vulkan/VulkanStrings.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public static class VulkanStrings
|
||||
{
|
||||
public static VulkanString VK_KHR_SURFACE_EXTENSION_NAME = "VK_KHR_surface";
|
||||
public static VulkanString VK_KHR_WIN32_SURFACE_EXTENSION_NAME = "VK_KHR_win32_surface";
|
||||
public static VulkanString VK_KHR_XCB_SURFACE_EXTENSION_NAME = "VK_KHR_xcb_surface";
|
||||
public static VulkanString VK_KHR_XLIB_SURFACE_EXTENSION_NAME = "VK_KHR_xlib_surface";
|
||||
public static VulkanString VK_KHR_SWAPCHAIN_EXTENSION_NAME = "VK_KHR_swapchain";
|
||||
public static VulkanString VK_EXT_DEBUG_REPORT_EXTENSION_NAME = "VK_EXT_debug_report";
|
||||
public static VulkanString StandardValidationLayerName = "VK_LAYER_LUNARG_standard_validation";
|
||||
public static VulkanString main = "main";
|
||||
}
|
||||
}
|
23
src/OpenTK/Graphics/Vulkan/VulkanVersion.cs
Normal file
23
src/OpenTK/Graphics/Vulkan/VulkanVersion.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
namespace OpenTK.Graphics.Vulkan
|
||||
{
|
||||
public struct VulkanVersion
|
||||
{
|
||||
private readonly uint value;
|
||||
|
||||
public VulkanVersion(uint major, uint minor, uint patch)
|
||||
{
|
||||
value = major << 22 | minor << 12 | patch;
|
||||
}
|
||||
|
||||
public uint Major => value >> 22;
|
||||
|
||||
public uint Minor => (value >> 12) & 0x3ff;
|
||||
|
||||
public uint Patch => (value >> 22) & 0xfff;
|
||||
|
||||
public static implicit operator uint(VulkanVersion version)
|
||||
{
|
||||
return version.value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ using System.ComponentModel;
|
|||
using System.Drawing;
|
||||
#endif
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Graphics.Vulkan;
|
||||
using OpenTK.Input;
|
||||
using OpenTK.Platform;
|
||||
|
||||
|
@ -49,6 +50,55 @@ namespace OpenTK
|
|||
private bool events;
|
||||
private bool previous_cursor_visible = true;
|
||||
|
||||
public unsafe VkResult CreateVulkanSurface(VkInstance instance, out VkSurfaceKHR surface)
|
||||
{
|
||||
IPlatformFactory factory = Factory.Default;
|
||||
|
||||
if (implementation is Platform.Windows.WinGLNative win)
|
||||
{
|
||||
VkWin32SurfaceCreateInfoKHR createInfo = VkWin32SurfaceCreateInfoKHR.New();
|
||||
createInfo.hwnd = win.Handle;
|
||||
createInfo.hinstance = win.Instance;
|
||||
|
||||
return VK.CreateWin32SurfaceKHR(instance, ref createInfo, IntPtr.Zero, out surface);
|
||||
}
|
||||
else if (implementation is Platform.X11.X11GLNative x11)
|
||||
{
|
||||
Platform.X11.X11WindowInfo info = x11.WindowInfo as Platform.X11.X11WindowInfo;
|
||||
|
||||
Graphics.Vulkan.Xlib.Window window = new Graphics.Vulkan.Xlib.Window();
|
||||
window.Value = info.WindowHandle;
|
||||
|
||||
VkXlibSurfaceCreateInfoKHR createInfo = VkXlibSurfaceCreateInfoKHR.New();
|
||||
createInfo.dpy = (Graphics.Vulkan.Xlib.Display*)info.Display;
|
||||
createInfo.window = window;
|
||||
|
||||
return VK.CreateXlibSurfaceKHR(instance, &createInfo, IntPtr.Zero, out surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If someone knows how to create a MoltenVK surface, please add it here
|
||||
|
||||
throw new NotImplementedException(implementation.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public IntPtr[] RequiredVulkanExtensions()
|
||||
{
|
||||
if (implementation is Platform.Windows.WinGLNative win)
|
||||
{
|
||||
return new IntPtr[] { VulkanStrings.VK_KHR_WIN32_SURFACE_EXTENSION_NAME };
|
||||
}
|
||||
else if (implementation is Platform.X11.X11GLNative x11)
|
||||
{
|
||||
return new IntPtr[] { VulkanStrings.VK_KHR_XLIB_SURFACE_EXTENSION_NAME };
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(implementation.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Threading.Thread.CurrentThread.ManagedThreadId of the thread that created this <see cref="OpenTK.NativeWindow"/>.
|
||||
/// </summary>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<AssemblyName>OpenTK</AssemblyName>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>OpenTK</RootNamespace>
|
||||
<DefineConstants>$(DefineConstants);WIN32;CARBON;X11;SDL2;OPENGL;OPENGLES;MINIMAL</DefineConstants>
|
||||
<DefineConstants>$(DefineConstants);WIN32;CARBON;X11;OPENGL;OPENGLES;MINIMAL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
|
@ -68,22 +68,24 @@
|
|||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>1.0.2</Version>
|
||||
<Description>The Open Toolkit library (OpenTK) is an advanced, low-level C# wrapper for OpenGL, OpenGL ES and OpenAL.
|
||||
<Version>1.0.5</Version>
|
||||
<Description>The Open Toolkit library (OpenTK) is an advanced, low-level C# wrapper for OpenGL, OpenGL ES, OpenAL and Vulkan.
|
||||
It is suitable for games, scientific visualizations and projects that require 3d graphics, audio or compute functionality.
|
||||
|
||||
Features
|
||||
- Create cutting-edge graphics with OpenGL 4.4 and OpenGL ES 3.0
|
||||
- Create cutting-edge graphics with OpenGL 4.6, OpenGL ES 3.0 and Vulkan
|
||||
- Use the .Net/Mono language of your choice: C#, F#, VB.Net, Boo, IronPython, IronRuby
|
||||
- Develop faster with inline documentation and strongly-typed enumerations for all OpenGL and OpenAL functions
|
||||
- Develop faster with inline documentation and strongly-typed enumerations for all OpenGL, OpenAL and Vulkan functions
|
||||
|
||||
This is a .NET Core-compatible version of OpenTK.
|
||||
This version can be found at https://github.com/emmauss/opentk</Description>
|
||||
This version can be found at https://github.com/Ryujinx/Opentk</Description>
|
||||
<PackageId>OpenTK.NetStandard</PackageId>
|
||||
<Authors>emmaus</Authors>
|
||||
<Company>emmaus</Company>
|
||||
<Product>OpenTK</Product>
|
||||
<PackageProjectUrl>https://github.com/emmauss/opentk</PackageProjectUrl>
|
||||
<PackageProjectUrl>https://github.com/Ryujinx/Opentk</PackageProjectUrl>
|
||||
<AssemblyVersion>1.0.5.0</AssemblyVersion>
|
||||
<FileVersion>1.0.5.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="$(OutputPath)..\..\..\..\Generator.Rewrite\bin\Debug\Rewrite.exe --assembly $(OutputPath)OpenTK.dll --signing-key ..\..\OpenTK.snk -debug -netstandard" Condition="$(OS) == 'Windows_NT' and $(Configuration) == 'Debug'" />
|
||||
|
@ -107,8 +109,17 @@ This version can be found at https://github.com/emmauss/opentk</Description>
|
|||
</ProjectExtensions>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<Target Name="AutoGenerateBindings" BeforeTargets="CoreCompile">
|
||||
<Message Text="Generating bindings." />
|
||||
<Exec Command="dotnet run --project ..\vk.generator\vk.generator.csproj --out $(MSBuildThisFileDirectory)Graphics\Vulkan\Generated" />
|
||||
</Target>
|
||||
<Target Name="RewriteCalliStubs" AfterTargets="Build" Condition="'$(DisableCalli)' != 'true'">
|
||||
<Message Text="Rewriting calli stubs." />
|
||||
<Exec Command="dotnet run --project ..\vk.rewrite\vk.rewrite.csproj --vkdll $(TargetPath)" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -46,8 +46,9 @@ namespace OpenTK.Platform
|
|||
Toolkit.Init();
|
||||
|
||||
// Create regular platform backend
|
||||
if (false) { }
|
||||
#if SDL2
|
||||
if (Configuration.RunningOnSdl2)
|
||||
else if (Configuration.RunningOnSdl2)
|
||||
{
|
||||
Default = new SDL2.Sdl2Factory();
|
||||
}
|
||||
|
|
|
@ -45,9 +45,9 @@ namespace OpenTK.Platform.Windows
|
|||
private const ExtendedWindowStyle ParentStyleEx = ExtendedWindowStyle.WindowEdge | ExtendedWindowStyle.ApplicationWindow;
|
||||
private const ExtendedWindowStyle ChildStyleEx = 0;
|
||||
#if NETSTANDARD
|
||||
private readonly IntPtr Instance = Functions.GetModuleHandle(typeof(WinGLNative).Module.Name);
|
||||
public readonly IntPtr Instance = Functions.GetModuleHandle(typeof(WinGLNative).Module.Name);
|
||||
#else
|
||||
private readonly IntPtr Instance = Marshal.GetHINSTANCE(typeof(WinGLNative).Module);
|
||||
public readonly IntPtr Instance = Marshal.GetHINSTANCE(typeof(WinGLNative).Module);
|
||||
#endif
|
||||
private readonly IntPtr ClassName = Marshal.StringToHGlobalAuto(Guid.NewGuid().ToString());
|
||||
private readonly WindowProcedure WindowProcedureDelegate;
|
||||
|
@ -96,6 +96,8 @@ namespace OpenTK.Platform.Windows
|
|||
|
||||
private static readonly object SyncRoot = new object();
|
||||
|
||||
public IntPtr Handle { get => window.WindowHandle; }
|
||||
|
||||
public WinGLNative(int x, int y, int width, int height, string title, GameWindowFlags options, DisplayDevice device)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
|
|
|
@ -692,10 +692,10 @@ namespace OpenTK.Platform.X11
|
|||
public int backing_store;
|
||||
public IntPtr backing_planes;
|
||||
public IntPtr backing_pixel;
|
||||
public bool save_under;
|
||||
public int save_under;
|
||||
public IntPtr event_mask;
|
||||
public IntPtr do_not_propagate_mask;
|
||||
public bool override_redirect;
|
||||
public int override_redirect;
|
||||
public IntPtr colormap;
|
||||
public IntPtr cursor;
|
||||
}
|
||||
|
@ -719,7 +719,7 @@ namespace OpenTK.Platform.X11
|
|||
public IntPtr backing_pixel;
|
||||
public byte save_under;
|
||||
public IntPtr colormap;
|
||||
public bool map_installed;
|
||||
public int map_installed;
|
||||
public MapState map_state;
|
||||
public IntPtr all_event_masks;
|
||||
public IntPtr your_event_mask;
|
||||
|
|
252
src/vk.generator/CodeGenerator.cs
Normal file
252
src/vk.generator/CodeGenerator.cs
Normal file
|
@ -0,0 +1,252 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class CodeGenerator
|
||||
{
|
||||
public static void GenerateCodeFiles(VulkanSpecification spec, TypeNameMappings tnm, string path)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
|
||||
}
|
||||
GenerateAllTypes(spec, tnm, path);
|
||||
}
|
||||
|
||||
private static void GenerateAllTypes(VulkanSpecification spec, TypeNameMappings tnm, string path)
|
||||
{
|
||||
using (StreamWriter sw = File.CreateText(Path.Combine(path, "Structures.gen.cs")))
|
||||
{
|
||||
CsCodeWriter cw = new CsCodeWriter(sw);
|
||||
cw.WriteHeader();
|
||||
cw.WriteLine();
|
||||
|
||||
cw.Using("System");
|
||||
cw.WriteLine();
|
||||
|
||||
using (cw.PushBlock("namespace OpenTK.Graphics.Vulkan"))
|
||||
{
|
||||
Util.SpaceSeparatedList(cw, spec.Structures, structure =>
|
||||
{
|
||||
StructureHelpers.WriteStructure(cw, structure, tnm, spec.Constants);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
using (StreamWriter enumWriter = File.CreateText(Path.Combine(path, "Enums.gen.cs")))
|
||||
{
|
||||
CsCodeWriter cw = new CsCodeWriter(enumWriter);
|
||||
cw.WriteHeader();
|
||||
cw.WriteLine();
|
||||
|
||||
cw.Using("System");
|
||||
cw.WriteLine();
|
||||
|
||||
using (cw.PushBlock("namespace OpenTK.Graphics.Vulkan"))
|
||||
{
|
||||
Util.SpaceSeparatedList(cw, spec.Enums, enumDef =>
|
||||
{
|
||||
EnumHelpers.WriteEnum(cw, enumDef, tnm);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
CommandDefinition[] allVariants = spec.Commands.SelectMany(cd => VariantGenerator.GenerateVariants(cd)).ToArray();
|
||||
CommandDefinition[] allCommandsWithVariants = spec.Commands.Concat(allVariants).OrderBy(cd => cd.Name).ToArray();
|
||||
|
||||
using (StreamWriter commandWriter = File.CreateText(Path.Combine(path, "Commands.gen.cs")))
|
||||
{
|
||||
CsCodeWriter cw = new CsCodeWriter(commandWriter);
|
||||
cw.WriteHeader();
|
||||
cw.WriteLine();
|
||||
|
||||
cw.Using("System");
|
||||
cw.Using("System.Runtime.InteropServices");
|
||||
cw.WriteLine();
|
||||
|
||||
using (cw.PushBlock("namespace OpenTK.Graphics.Vulkan"))
|
||||
using (cw.PushBlock("public static unsafe partial class VK"))
|
||||
{
|
||||
Util.SpaceSeparatedList(cw, allCommandsWithVariants, command =>
|
||||
{
|
||||
CommandHelpers.WriteCommand(cw, tnm, command);
|
||||
});
|
||||
|
||||
cw.WriteLine();
|
||||
|
||||
using (cw.PushBlock("private static void LoadFunctionPointers()"))
|
||||
{
|
||||
foreach (CommandDefinition command in spec.Commands)
|
||||
{
|
||||
cw.WriteLine($"{command.Name}_ptr = s_nativeLib.LoadFunctionPointer(\"{command.RealName}\");");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (StreamWriter handleWriter = File.CreateText(Path.Combine(path, "Handles.gen.cs")))
|
||||
{
|
||||
CsCodeWriter cw = new CsCodeWriter(handleWriter);
|
||||
cw.WriteHeader();
|
||||
cw.WriteLine();
|
||||
|
||||
cw.Using("System");
|
||||
cw.Using("System.Diagnostics");
|
||||
cw.WriteLine();
|
||||
|
||||
using (cw.PushBlock("namespace OpenTK.Graphics.Vulkan"))
|
||||
{
|
||||
Util.SpaceSeparatedList(cw, spec.Handles, handle =>
|
||||
{
|
||||
HandleHelpers.WriteHandle(cw, handle);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
using (StreamWriter unionWriter = File.CreateText(Path.Combine(path, "Unions.gen.cs")))
|
||||
{
|
||||
CsCodeWriter cw = new CsCodeWriter(unionWriter);
|
||||
cw.WriteHeader();
|
||||
cw.WriteLine();
|
||||
|
||||
cw.Using("System.Runtime.InteropServices");
|
||||
cw.WriteLine();
|
||||
|
||||
using (cw.PushBlock("namespace OpenTK.Graphics.Vulkan"))
|
||||
{
|
||||
Util.SpaceSeparatedList(cw, spec.Unions, union =>
|
||||
{
|
||||
UnionHelpers.WriteUnion(cw, tnm, union);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
using (StreamWriter unionWriter = File.CreateText(Path.Combine(path, "Constants.gen.cs")))
|
||||
{
|
||||
CsCodeWriter cw = new CsCodeWriter(unionWriter);
|
||||
cw.WriteHeader();
|
||||
cw.WriteLine();
|
||||
cw.Using("System.Runtime.InteropServices");
|
||||
cw.WriteLine();
|
||||
|
||||
using (cw.PushBlock("namespace OpenTK.Graphics.Vulkan"))
|
||||
{
|
||||
ConstantHelpers.WriteAllConstants(cw, tnm, spec.Constants);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CsCodeWriter
|
||||
{
|
||||
private readonly StreamWriter _sw;
|
||||
|
||||
private int _indentLevel = 0;
|
||||
|
||||
public CsCodeWriter(StreamWriter sw)
|
||||
{
|
||||
_sw = sw;
|
||||
}
|
||||
|
||||
public void Using(string ns)
|
||||
{
|
||||
_sw.WriteLine($"using {ns};");
|
||||
}
|
||||
|
||||
public void WriteHeader()
|
||||
{
|
||||
_sw.WriteLine("// This file is generated.");
|
||||
}
|
||||
|
||||
public void PushBlock()
|
||||
{
|
||||
WriteLine('{');
|
||||
_indentLevel += 4;
|
||||
}
|
||||
|
||||
public CodeBlock PushBlock(string ns)
|
||||
{
|
||||
return new CodeBlock(this, ns);
|
||||
}
|
||||
|
||||
public IfDefSection PushIfDef(string condition)
|
||||
{
|
||||
return new IfDefSection(this, condition);
|
||||
}
|
||||
|
||||
public void PopBlock()
|
||||
{
|
||||
_indentLevel -= 4;
|
||||
WriteLine('}');
|
||||
}
|
||||
|
||||
public void WriteLine()
|
||||
{
|
||||
_sw.WriteLine();
|
||||
}
|
||||
|
||||
public void WriteLine(string text)
|
||||
{
|
||||
WriteIndentation();
|
||||
_sw.WriteLine(text);
|
||||
}
|
||||
|
||||
public void WriteLine(char c)
|
||||
{
|
||||
WriteIndentation();
|
||||
_sw.WriteLine(c);
|
||||
}
|
||||
|
||||
public void Write(string text)
|
||||
{
|
||||
_sw.Write(text);
|
||||
}
|
||||
|
||||
public void WriteIndentation()
|
||||
{
|
||||
for (int i = 0; i < _indentLevel; i++)
|
||||
{
|
||||
_sw.Write(' ');
|
||||
}
|
||||
}
|
||||
|
||||
public class CodeBlock : IDisposable
|
||||
{
|
||||
private readonly CsCodeWriter _cw;
|
||||
|
||||
public CodeBlock(CsCodeWriter cw, string header)
|
||||
{
|
||||
_cw = cw;
|
||||
_cw.WriteLine(header);
|
||||
_cw.PushBlock();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cw.PopBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public class IfDefSection : IDisposable
|
||||
{
|
||||
private readonly CsCodeWriter _cw;
|
||||
private readonly string _condition;
|
||||
|
||||
public IfDefSection(CsCodeWriter cw, string condition)
|
||||
{
|
||||
_cw = cw;
|
||||
_condition = condition;
|
||||
_cw.WriteLine($"#if {condition}");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cw.WriteLine($"#endif // {_condition}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
src/vk.generator/CommandDefinition.cs
Normal file
77
src/vk.generator/CommandDefinition.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class CommandDefinition
|
||||
{
|
||||
public string Name { get; }
|
||||
public TypeSpec ReturnType { get; }
|
||||
public ParameterDefinition[] Parameters { get; }
|
||||
public string[] SuccessCodes { get; }
|
||||
public string[] ErrorCodes { get; }
|
||||
public bool IsVariant { get; }
|
||||
public string RealName { get => "vk" + Name; }
|
||||
|
||||
public CommandDefinition(string name, TypeSpec returnType, ParameterDefinition[] parameters, string[] successCodes, string[] errorCodes, bool isVariant)
|
||||
{
|
||||
Require.NotNull(parameters);
|
||||
Require.NotNull(successCodes);
|
||||
Require.NotNull(errorCodes);
|
||||
|
||||
if (name.StartsWith("vk"))
|
||||
{
|
||||
name = name.Substring(2);
|
||||
}
|
||||
|
||||
Name = name;
|
||||
ReturnType = returnType;
|
||||
Parameters = parameters;
|
||||
SuccessCodes = successCodes;
|
||||
ErrorCodes = errorCodes;
|
||||
IsVariant = isVariant;
|
||||
}
|
||||
|
||||
public static CommandDefinition CreateFromXml(XElement xe)
|
||||
{
|
||||
Require.Equal("command", xe.Name);
|
||||
|
||||
var proto = xe.Element("proto");
|
||||
string name = proto.Element("name").Value;
|
||||
string returnTypeName = proto.Element("type").Value;
|
||||
TypeSpec returnType = new TypeSpec(returnTypeName);
|
||||
|
||||
var successAttr = xe.Attribute("successcodes");
|
||||
string[] successCodes = successAttr != null
|
||||
? successAttr.Value.Split(',').ToArray()
|
||||
: Array.Empty<string>();
|
||||
|
||||
var errorAttr = xe.Attribute("errorcodes");
|
||||
string[] errorCodes = errorAttr != null
|
||||
? errorAttr.Value.Split(',').ToArray()
|
||||
: Array.Empty<string>();
|
||||
|
||||
ParameterDefinition[] parameters = xe.Elements("param")
|
||||
.Select(paramXml => ParameterDefinition.CreateFromXml(paramXml)).ToArray();
|
||||
|
||||
return new CommandDefinition(name, returnType, parameters, successCodes, errorCodes, false);
|
||||
}
|
||||
|
||||
public string GetParametersSignature(TypeNameMappings tnm)
|
||||
{
|
||||
return string.Join(", ", Parameters.Select(pd => pd.GetMappedAndNormalizedString(tnm)));
|
||||
}
|
||||
|
||||
public string GetParametersSignature()
|
||||
{
|
||||
return string.Join(", ", Parameters.Select(pd => pd.ToString()));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string paramSig = GetParametersSignature();
|
||||
return $"{ReturnType} {Name}({paramSig})";
|
||||
}
|
||||
}
|
||||
}
|
27
src/vk.generator/CommandHelpers.cs
Normal file
27
src/vk.generator/CommandHelpers.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class CommandHelpers
|
||||
{
|
||||
public static void WriteCommand(CsCodeWriter cw, TypeNameMappings tnm, CommandDefinition command)
|
||||
{
|
||||
if (!command.IsVariant)
|
||||
{
|
||||
cw.WriteLine($"private static IntPtr {command.Name}_ptr;");
|
||||
}
|
||||
|
||||
if (command.SuccessCodes.Length != 0)
|
||||
{
|
||||
cw.WriteLine($"///<remarks>Success codes:{string.Join(", ", command.SuccessCodes)}. Error codes:{string.Join(", ", command.ErrorCodes)}</remarks>");
|
||||
}
|
||||
|
||||
cw.WriteLine("[Generator.CalliRewrite]");
|
||||
using (cw.PushBlock($"public static unsafe {command.ReturnType.MapTypeSpec(tnm)} {command.Name}({command.GetParametersSignature(tnm)})"))
|
||||
{
|
||||
cw.WriteLine("throw new NotImplementedException();");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/vk.generator/Configuration.cs
Normal file
10
src/vk.generator/Configuration.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class Configuration
|
||||
{
|
||||
public static string CodeOutputPath { get; set; } = AppContext.BaseDirectory;
|
||||
public static bool MapBaseTypes { get; set; } = true;
|
||||
}
|
||||
}
|
55
src/vk.generator/ConstantDefinition.cs
Normal file
55
src/vk.generator/ConstantDefinition.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class ConstantDefinition
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Value { get; }
|
||||
public ConstantType Type { get; }
|
||||
public string Comment { get; }
|
||||
|
||||
public ConstantDefinition(string name, string value, string comment)
|
||||
{
|
||||
Name = name;
|
||||
Value = value;
|
||||
Type = ParseType(value);
|
||||
Comment = comment;
|
||||
}
|
||||
|
||||
private ConstantType ParseType(string value)
|
||||
{
|
||||
if (value.EndsWith("f"))
|
||||
{
|
||||
return ConstantType.Float32;
|
||||
}
|
||||
else if (value.EndsWith("ULL)"))
|
||||
{
|
||||
return ConstantType.UInt64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ConstantType.UInt32;
|
||||
}
|
||||
}
|
||||
|
||||
public static ConstantDefinition CreateFromXml(XElement xe)
|
||||
{
|
||||
Require.NotNull(xe);
|
||||
|
||||
string name = xe.GetNameAttribute();
|
||||
string value = xe.Attribute("value").Value;
|
||||
string comment = xe.Attribute("comment")?.Value;
|
||||
|
||||
return new ConstantDefinition(name, value, comment);
|
||||
}
|
||||
|
||||
public enum ConstantType
|
||||
{
|
||||
UInt32,
|
||||
UInt64,
|
||||
Float32,
|
||||
}
|
||||
}
|
||||
}
|
62
src/vk.generator/ConstantHelpers.cs
Normal file
62
src/vk.generator/ConstantHelpers.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class ConstantHelpers
|
||||
{
|
||||
public static void WriteAllConstants(CsCodeWriter cw, TypeNameMappings tnm, ConstantDefinition[] constants)
|
||||
{
|
||||
using (cw.PushBlock("public static partial class VK"))
|
||||
{
|
||||
foreach (ConstantDefinition constant in constants)
|
||||
{
|
||||
if (constant.Comment != null)
|
||||
{
|
||||
cw.WriteLine($"///<summary>{constant.Comment}</summary>");
|
||||
}
|
||||
|
||||
cw.WriteLine($"public const {GetCSharpNameForConstantType(constant.Type)} {EnumHelpers.GetPrettyEnumName(constant.Name, "VK_")} = {NormalizeValue(constant.Value)};");
|
||||
}
|
||||
}
|
||||
|
||||
cw.WriteLine();
|
||||
|
||||
using (cw.PushBlock("public static partial class RawConstants"))
|
||||
{
|
||||
foreach (ConstantDefinition constant in constants)
|
||||
{
|
||||
if (constant.Comment != null)
|
||||
{
|
||||
cw.WriteLine($"///<summary>{constant.Comment}</summary>");
|
||||
}
|
||||
|
||||
cw.WriteLine($"public const {GetCSharpNameForConstantType(constant.Type)} {constant.Name} = VK.{EnumHelpers.GetPrettyEnumName(constant.Name, "VK_")};");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteConstant(CsCodeWriter cw, TypeNameMappings tnm, ConstantDefinition constant)
|
||||
{
|
||||
}
|
||||
|
||||
public static string GetCSharpNameForConstantType(ConstantDefinition.ConstantType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ConstantDefinition.ConstantType.UInt32:
|
||||
return "uint";
|
||||
case ConstantDefinition.ConstantType.UInt64:
|
||||
return "ulong";
|
||||
case ConstantDefinition.ConstantType.Float32:
|
||||
return "float";
|
||||
default:
|
||||
throw new InvalidOperationException("Illegal ConstantType: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private static string NormalizeValue(string value)
|
||||
{
|
||||
return value.Replace("ULL", "UL");
|
||||
}
|
||||
}
|
||||
}
|
101
src/vk.generator/EnumDefinition.cs
Normal file
101
src/vk.generator/EnumDefinition.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class EnumDefinition
|
||||
{
|
||||
public string Name { get; }
|
||||
public EnumType Type { get; }
|
||||
public EnumValue[] Values { get; set; }
|
||||
|
||||
public EnumDefinition(string name, EnumType type, EnumValue[] values)
|
||||
{
|
||||
Require.NotNullOrEmpty(name);
|
||||
Require.NotNull(values);
|
||||
|
||||
Name = name;
|
||||
Type = type;
|
||||
Values = values;
|
||||
}
|
||||
|
||||
public static EnumDefinition CreateFromXml(XElement xe)
|
||||
{
|
||||
Require.NotNull(xe);
|
||||
|
||||
EnumType type;
|
||||
var typeAttr = xe.Attribute("type");
|
||||
if (typeAttr != null)
|
||||
{
|
||||
string typeString = xe.Attribute("type").Value;
|
||||
type = (EnumType)Enum.Parse(typeof(EnumType), typeString, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = EnumType.Constants;
|
||||
}
|
||||
|
||||
string name = xe.Attribute("name").Value;
|
||||
EnumValue[] values = xe.Elements("enum").Select(valuesx => EnumValue.CreateFromXml(valuesx, type == EnumType.Bitmask)).ToArray();
|
||||
return new EnumDefinition(name, type, values);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Enum: {Name} ({Type})[{Values.Length}]";
|
||||
}
|
||||
}
|
||||
|
||||
public enum EnumType
|
||||
{
|
||||
Bitmask,
|
||||
Enum,
|
||||
Constants,
|
||||
}
|
||||
|
||||
public class EnumValue
|
||||
{
|
||||
public string Name { get; }
|
||||
public int ValueOrBitPosition { get; }
|
||||
public string Comment { get; }
|
||||
|
||||
public EnumValue(string name, int value, string comment)
|
||||
{
|
||||
Name = name;
|
||||
ValueOrBitPosition = value;
|
||||
Comment = comment;
|
||||
}
|
||||
|
||||
public static EnumValue CreateFromXml(XElement xe, bool isBitmask)
|
||||
{
|
||||
Require.NotNull(xe);
|
||||
|
||||
string name = xe.Attribute("name").Value;
|
||||
|
||||
int value;
|
||||
string valueStr = xe.Attribute("value")?.Value;
|
||||
if (valueStr != null)
|
||||
{
|
||||
if (valueStr.StartsWith("0x"))
|
||||
{
|
||||
valueStr = valueStr.Substring(2);
|
||||
value = int.Parse(valueStr, System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = int.Parse(valueStr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string bitposStr = xe.Attribute("bitpos").Value;
|
||||
value = 1 << int.Parse(bitposStr);
|
||||
}
|
||||
|
||||
var commentAttr = xe.Attribute("comment");
|
||||
string comment = commentAttr != null ? commentAttr.Value : string.Empty;
|
||||
return new EnumValue(name, value, comment);
|
||||
}
|
||||
}
|
||||
}
|
204
src/vk.generator/EnumHelpers.cs
Normal file
204
src/vk.generator/EnumHelpers.cs
Normal file
|
@ -0,0 +1,204 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class EnumHelpers
|
||||
{
|
||||
private static readonly char[] s_underscoreSeparator = { '_' };
|
||||
|
||||
private static readonly Dictionary<string, string> s_knownEnumPrefixes = new Dictionary<string, string>
|
||||
{
|
||||
{ "VkResult", "VK" },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, string> s_knownEnumValueNames = new Dictionary<string, string>
|
||||
{
|
||||
{ "VK_STENCIL_FRONT_AND_BACK", "FrontAndBack" },
|
||||
// VkStructureType
|
||||
|
||||
// VkSampleCountFlagBits
|
||||
{ "VK_SAMPLE_COUNT_1_BIT", "Count1" },
|
||||
{ "VK_SAMPLE_COUNT_2_BIT", "Count2" },
|
||||
{ "VK_SAMPLE_COUNT_4_BIT", "Count4" },
|
||||
{ "VK_SAMPLE_COUNT_8_BIT", "Count8" },
|
||||
{ "VK_SAMPLE_COUNT_16_BIT", "Count16" },
|
||||
{ "VK_SAMPLE_COUNT_32_BIT", "Count32" },
|
||||
{ "VK_SAMPLE_COUNT_64_BIT", "Count64" },
|
||||
// VkImageType
|
||||
{ "VK_IMAGE_TYPE_1D", "Image1D" },
|
||||
{ "VK_IMAGE_TYPE_2D", "Image2D" },
|
||||
{ "VK_IMAGE_TYPE_3D", "Image3D" },
|
||||
// VkImageViewType
|
||||
{ "VK_IMAGE_VIEW_TYPE_1D", "Image1D" },
|
||||
{ "VK_IMAGE_VIEW_TYPE_2D", "Image2D" },
|
||||
{ "VK_IMAGE_VIEW_TYPE_3D", "Image3D" },
|
||||
{ "VK_IMAGE_VIEW_TYPE_CUBE", "ImageCube" },
|
||||
{ "VK_IMAGE_VIEW_TYPE_1D_ARRAY", "Image1DArray" },
|
||||
{ "VK_IMAGE_VIEW_TYPE_2D_ARRAY", "Image2DArray" },
|
||||
{ "VK_IMAGE_VIEW_TYPE_CUBE_ARRAY", "ImageCubeArray" },
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> s_ignoredParts = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"flags",
|
||||
"bit"
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> s_preserveCaps = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"khr",
|
||||
"khx",
|
||||
"ext",
|
||||
"nv",
|
||||
"nvx",
|
||||
"amd",
|
||||
};
|
||||
|
||||
public static void WriteEnum(CsCodeWriter cw, EnumDefinition enumDef, TypeNameMappings tnm)
|
||||
{
|
||||
if (enumDef.Type == EnumType.Bitmask)
|
||||
{
|
||||
cw.WriteLine("[Flags]");
|
||||
}
|
||||
string mappedName = tnm.GetMappedName(enumDef.Name);
|
||||
string enumNamePrefix = GetEnumNamePrefix(mappedName);
|
||||
using (cw.PushBlock("public enum " + mappedName))
|
||||
{
|
||||
if (enumDef.Type == EnumType.Bitmask && !enumDef.Values.Any(ev => GetPrettyEnumName(ev.Name, enumNamePrefix) == "None"))
|
||||
{
|
||||
cw.WriteLine($"None = 0,");
|
||||
}
|
||||
foreach (var value in enumDef.Values)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value.Comment))
|
||||
{
|
||||
cw.WriteLine($"///<summary>{value.Comment}</summary>");
|
||||
}
|
||||
|
||||
string prettyName = GetPrettyEnumName(value.Name, enumNamePrefix);
|
||||
cw.WriteLine($"{prettyName} = {value.ValueOrBitPosition},");
|
||||
}
|
||||
}
|
||||
|
||||
using (cw.PushBlock("public static partial class RawConstants"))
|
||||
{
|
||||
foreach (var value in enumDef.Values)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value.Comment))
|
||||
{
|
||||
cw.WriteLine($"///<summary>{value.Comment}</summary>");
|
||||
}
|
||||
|
||||
string prettyName = GetPrettyEnumName(value.Name, enumNamePrefix);
|
||||
cw.WriteLine($"public const {mappedName} {value.Name} = {mappedName}.{prettyName};");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetEnumNamePrefix(string typeName)
|
||||
{
|
||||
if (s_knownEnumPrefixes.TryGetValue(typeName, out string knownValue))
|
||||
{
|
||||
return knownValue;
|
||||
}
|
||||
|
||||
List<string> parts = new List<string>(4);
|
||||
int chunkStart = 0;
|
||||
for (int i = 0; i < typeName.Length; i++)
|
||||
{
|
||||
if (char.IsUpper(typeName[i]))
|
||||
{
|
||||
if (chunkStart != i)
|
||||
{
|
||||
parts.Add(typeName.Substring(chunkStart, i - chunkStart));
|
||||
}
|
||||
|
||||
chunkStart = i;
|
||||
if (i == typeName.Length - 1)
|
||||
{
|
||||
parts.Add(typeName.Substring(i, 1));
|
||||
}
|
||||
}
|
||||
else if (i == typeName.Length - 1)
|
||||
{
|
||||
parts.Add(typeName.Substring(chunkStart, typeName.Length - chunkStart));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
if (
|
||||
parts[i] == "Flag"
|
||||
|| parts[i] == "Flags"
|
||||
|| (parts[i] == "K" && (i + 2) < parts.Count && parts[i + 1] == "H" && parts[i + 2] == "R")
|
||||
|| (parts[i] == "A" && (i + 2) < parts.Count && parts[i + 1] == "M" && parts[i + 2] == "D")
|
||||
|| (parts[i] == "E" && (i + 2) < parts.Count && parts[i + 1] == "X" && parts[i + 2] == "T")
|
||||
|| (parts[i] == "Type" && (i + 3) < parts.Count && parts[i + 1] == "N" && parts[i + 2] == "V" && parts[i + 3] == "X")
|
||||
)
|
||||
{
|
||||
parts = new List<string>(parts.Take(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join("_", parts.Select(s => s.ToUpper()));
|
||||
}
|
||||
|
||||
public static string TrimIgnoredParts(string ret)
|
||||
{
|
||||
foreach (string ignored in s_ignoredParts)
|
||||
{
|
||||
int index;
|
||||
if ((index = ret.IndexOf(ignored, StringComparison.OrdinalIgnoreCase)) != -1)
|
||||
{
|
||||
ret = ret.Remove(index, ignored.Length);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string GetPrettyEnumName(string value, string enumPrefix)
|
||||
{
|
||||
if (s_knownEnumValueNames.TryGetValue(value, out string knownName))
|
||||
{
|
||||
return knownName;
|
||||
}
|
||||
|
||||
if (value.IndexOf(enumPrefix) != 0)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
string[] parts = value.Substring(enumPrefix.Length, value.Length - enumPrefix.Length)
|
||||
.Split(s_underscoreSeparator, StringSplitOptions.RemoveEmptyEntries);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (string part in parts)
|
||||
{
|
||||
if (s_ignoredParts.Contains(part))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s_preserveCaps.Contains(part))
|
||||
{
|
||||
sb.Append(part);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(char.ToUpper(part[0]));
|
||||
for (int i = 1; i < part.Length; i++)
|
||||
{
|
||||
sb.Append(char.ToLower(part[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string prettyName = sb.ToString();
|
||||
return (char.IsNumber(prettyName[0])) ? "_" + prettyName : prettyName;
|
||||
}
|
||||
}
|
||||
}
|
126
src/vk.generator/ExtensionDefinition.cs
Normal file
126
src/vk.generator/ExtensionDefinition.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class ExtensionDefinition
|
||||
{
|
||||
public string Name { get; }
|
||||
public int Number { get; }
|
||||
public string Type { get; }
|
||||
public ExtensionConstant[] Constants { get; }
|
||||
public EnumExtensionValue[] EnumExtensions { get; }
|
||||
public string[] CommandNames { get; }
|
||||
|
||||
public ExtensionDefinition(
|
||||
string name,
|
||||
int number,
|
||||
string type,
|
||||
ExtensionConstant[] constants,
|
||||
EnumExtensionValue[] enumExtensions,
|
||||
string[] commandNames)
|
||||
{
|
||||
Name = name;
|
||||
Number = number;
|
||||
Type = type;
|
||||
Constants = constants;
|
||||
EnumExtensions = enumExtensions;
|
||||
CommandNames = commandNames;
|
||||
}
|
||||
|
||||
public static ExtensionDefinition CreateFromXml(XElement xe)
|
||||
{
|
||||
string name = xe.GetNameAttribute();
|
||||
string numberString = xe.Attribute("number").Value;
|
||||
int number = int.Parse(numberString);
|
||||
string type = xe.GetTypeAttributeOrNull();
|
||||
List<ExtensionConstant> extensionConstants = new List<ExtensionConstant>();
|
||||
List<EnumExtensionValue> enumExtensions = new List<EnumExtensionValue>();
|
||||
List<string> commandNames = new List<string>();
|
||||
|
||||
foreach (var require in xe.Elements("require"))
|
||||
{
|
||||
foreach (var enumXE in require.Elements("enum"))
|
||||
{
|
||||
string enumName = enumXE.GetNameAttribute();
|
||||
string extends = enumXE.Attribute("extends")?.Value;
|
||||
if (extends != null)
|
||||
{
|
||||
string valueString;
|
||||
string offsetString = enumXE.Attribute("offset")?.Value;
|
||||
if (offsetString != null)
|
||||
{
|
||||
int offset = int.Parse(offsetString);
|
||||
int direction = 1;
|
||||
if (enumXE.Attribute("dir")?.Value == "-")
|
||||
{
|
||||
direction = -1;
|
||||
}
|
||||
|
||||
int value = direction * (1000000000 + (number - 1) * 1000 + offset);
|
||||
valueString = value.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
string bitPosString = enumXE.Attribute("bitpos")?.Value;
|
||||
if (bitPosString != null)
|
||||
{
|
||||
int shift = int.Parse(bitPosString);
|
||||
valueString = (1 << shift).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
valueString = enumXE.Attribute("value").Value;
|
||||
}
|
||||
}
|
||||
enumExtensions.Add(new EnumExtensionValue(extends, enumName, valueString));
|
||||
}
|
||||
else
|
||||
{
|
||||
var valueAttribute = enumXE.Attribute("value");
|
||||
if (valueAttribute == null)
|
||||
continue;
|
||||
|
||||
extensionConstants.Add(new ExtensionConstant(name, valueAttribute.Value));
|
||||
}
|
||||
}
|
||||
foreach (var commandXE in require.Elements("command"))
|
||||
{
|
||||
commandNames.Add(commandXE.GetNameAttribute());
|
||||
}
|
||||
}
|
||||
return new ExtensionDefinition(name, number, type, extensionConstants.ToArray(), enumExtensions.ToArray(), commandNames.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public class ExtensionConstant
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Value { get; }
|
||||
public ExtensionConstant(string name, string value)
|
||||
{
|
||||
Name = name;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{DebuggerDisplayString}")]
|
||||
public class EnumExtensionValue
|
||||
{
|
||||
public string ExtendedType { get; }
|
||||
public string Name { get; }
|
||||
public string Value { get; }
|
||||
|
||||
public EnumExtensionValue(string extendedType, string name, string value)
|
||||
{
|
||||
ExtendedType = extendedType;
|
||||
Name = name;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
private string DebuggerDisplayString =>
|
||||
$"Ext: {ExtendedType}, {Name} = {Value}";
|
||||
}
|
||||
}
|
28
src/vk.generator/HandleDefinition.cs
Normal file
28
src/vk.generator/HandleDefinition.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class HandleDefinition
|
||||
{
|
||||
public string Name { get; }
|
||||
public bool Dispatchable { get; }
|
||||
public string Parent { get; }
|
||||
|
||||
public HandleDefinition(string name, bool dispatchable, string parent)
|
||||
{
|
||||
Name = name;
|
||||
Dispatchable = dispatchable;
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
public static HandleDefinition CreateFromXml(XElement xe)
|
||||
{
|
||||
Require.NotNull(xe);
|
||||
string name = xe.GetNameElement();
|
||||
bool dispatchable = xe.GetTypeElement() == "VK_DEFINE_HANDLE";
|
||||
string parent = xe.Attribute("parent")?.Value;
|
||||
|
||||
return new HandleDefinition(name, dispatchable, parent);
|
||||
}
|
||||
}
|
||||
}
|
39
src/vk.generator/HandleHelpers.cs
Normal file
39
src/vk.generator/HandleHelpers.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class HandleHelpers
|
||||
{
|
||||
public static void WriteHandle(CsCodeWriter cw, HandleDefinition handle)
|
||||
{
|
||||
if (handle.Parent != null)
|
||||
{
|
||||
cw.WriteIndentation();
|
||||
cw.Write($"///<summary>");
|
||||
cw.Write($"A {(handle.Dispatchable ? "dispatchable" : "non-dispatchable")} handle owned by a {handle.Parent}.");
|
||||
cw.Write("</summary>");
|
||||
cw.Write(Environment.NewLine);
|
||||
}
|
||||
cw.WriteLine($"[DebuggerDisplay(\"{{DebuggerDisplay,nq}}\")]");
|
||||
using (cw.PushBlock($"public partial struct {handle.Name} : IEquatable<{handle.Name}>"))
|
||||
{
|
||||
string handleType = handle.Dispatchable ? "IntPtr" : "ulong";
|
||||
string nullValue = handle.Dispatchable ? "IntPtr.Zero" : "0";
|
||||
|
||||
cw.WriteLine($"public readonly {handleType} Handle;");
|
||||
|
||||
cw.WriteLine($"public {handle.Name}({handleType} existingHandle) {{ Handle = existingHandle; }}");
|
||||
cw.WriteLine($"public static {handle.Name} Null => new {handle.Name}({nullValue});");
|
||||
cw.WriteLine($"public static implicit operator {handle.Name}({handleType} handle) => new {handle.Name}(handle);");
|
||||
cw.WriteLine($"public static bool operator ==({handle.Name} left, {handle.Name} right) => left.Handle == right.Handle;");
|
||||
cw.WriteLine($"public static bool operator !=({handle.Name} left, {handle.Name} right) => left.Handle != right.Handle;");
|
||||
cw.WriteLine($"public static bool operator ==({handle.Name} left, {handleType} right) => left.Handle == right;");
|
||||
cw.WriteLine($"public static bool operator !=({handle.Name} left, {handleType} right) => left.Handle != right;");
|
||||
cw.WriteLine($"public bool Equals({handle.Name} h) => Handle.Equals(h.Handle);");
|
||||
cw.WriteLine($"public override bool Equals(object o) => o is {handle.Name} h && Equals(h);");
|
||||
cw.WriteLine($"public override int GetHashCode() => Handle.GetHashCode();");
|
||||
cw.WriteLine($"private string DebuggerDisplay => string.Format(\"{handle.Name} [0x{{0}}]\", Handle.ToString(\"X\"));");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
76
src/vk.generator/MemberSpec.cs
Normal file
76
src/vk.generator/MemberSpec.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class MemberSpec
|
||||
{
|
||||
public string Name { get; }
|
||||
public TypeSpec Type { get; }
|
||||
public bool IsOptional { get; }
|
||||
public int ElementCount { get; }
|
||||
public string ElementCountSymbolic { get; }
|
||||
public string Comment { get; }
|
||||
public string LegalValues { get; }
|
||||
|
||||
public MemberSpec(string name, TypeSpec type, bool isOptional, int elementCount, string elementCountSymbolic, string comment, string legalValues)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
IsOptional = isOptional;
|
||||
ElementCount = elementCount;
|
||||
ElementCountSymbolic = elementCountSymbolic;
|
||||
Comment = comment;
|
||||
LegalValues = legalValues;
|
||||
}
|
||||
|
||||
public static MemberSpec CreateFromXml(XElement xe)
|
||||
{
|
||||
Require.NotNull(xe);
|
||||
|
||||
string name = xe.GetNameElement();
|
||||
bool isOptional = xe.GetOptionalAttributeOrFalse();
|
||||
string typeName = xe.Element("type").Value;
|
||||
int pointerLevel = xe.Value.Contains($"{typeName}*") ? 1 : 0; // TODO: Make this better.
|
||||
if (xe.Value.Contains($"{typeName}* const*"))
|
||||
{
|
||||
pointerLevel += 1;
|
||||
}
|
||||
|
||||
TypeSpec type = new TypeSpec(typeName, pointerLevel);
|
||||
|
||||
bool foundConstantElementCount = false;
|
||||
int elementCount = 1;
|
||||
string elementCountSymbolic = null;
|
||||
for (int i = 2; i < 10; i++)
|
||||
{
|
||||
if (xe.Value.Contains($"{name}[{i}]"))
|
||||
{
|
||||
elementCount = i;
|
||||
foundConstantElementCount = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundConstantElementCount)
|
||||
{
|
||||
Match m = Regex.Match(xe.Value, @"\[(.*)\]");
|
||||
if (m.Captures.Count > 0)
|
||||
{
|
||||
elementCountSymbolic = m.Groups[1].Value;
|
||||
}
|
||||
}
|
||||
|
||||
string value = xe.Attribute("values")?.Value;
|
||||
|
||||
return new MemberSpec(name, type, isOptional, elementCount, elementCountSymbolic, string.Empty, value);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string optionalPart = IsOptional ? "[opt] " : "";
|
||||
string countPart = ElementCount != 1 ? $" [{ElementCount}]" : ElementCountSymbolic != null ? $" [{ElementCountSymbolic}]" : "";
|
||||
return $"{optionalPart}{Type} {Name}";
|
||||
}
|
||||
}
|
||||
}
|
76
src/vk.generator/ParameterDefinition.cs
Normal file
76
src/vk.generator/ParameterDefinition.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class ParameterDefinition
|
||||
{
|
||||
public string Name { get; }
|
||||
public TypeSpec Type { get; }
|
||||
public ParameterModifier Modifier { get; }
|
||||
public bool IsOptional { get; }
|
||||
|
||||
public ParameterDefinition(string name, TypeSpec type, ParameterModifier modifier, bool isOptional)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
Modifier = modifier;
|
||||
IsOptional = isOptional;
|
||||
}
|
||||
|
||||
public static ParameterDefinition CreateFromXml(XElement xe)
|
||||
{
|
||||
string name = xe.Element("name").Value;
|
||||
var optionalAttr = xe.Attribute("optional");
|
||||
bool isOptional = optionalAttr != null && optionalAttr.Value == "true";
|
||||
string typeName = xe.Element("type").Value;
|
||||
int pointerLevel = 0;
|
||||
if (xe.Value.Contains($"{typeName}**") || xe.Value.Contains($"{typeName}* const*"))
|
||||
{
|
||||
pointerLevel = 2;
|
||||
}
|
||||
else if(xe.Value.Contains($"{typeName}*"))
|
||||
{
|
||||
pointerLevel = 1;
|
||||
}
|
||||
|
||||
|
||||
TypeSpec type = new TypeSpec(typeName, pointerLevel);
|
||||
|
||||
return new ParameterDefinition(name, type, ParameterModifier.None, isOptional);
|
||||
}
|
||||
|
||||
public string GetMappedAndNormalizedString(TypeNameMappings tnm)
|
||||
{
|
||||
return $"{GetModifierString()}{Type.MapTypeSpec(tnm)} {Util.NormalizeFieldName(Name)}";
|
||||
}
|
||||
|
||||
public string GetModifierString()
|
||||
{
|
||||
if (Modifier == ParameterModifier.Ref)
|
||||
{
|
||||
return "ref ";
|
||||
}
|
||||
else if (Modifier == ParameterModifier.Out)
|
||||
{
|
||||
return "out ";
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{GetModifierString()}{Type} {Name}";
|
||||
}
|
||||
}
|
||||
|
||||
public enum ParameterModifier
|
||||
{
|
||||
None,
|
||||
Ref,
|
||||
Out
|
||||
}
|
||||
}
|
69
src/vk.generator/Program.cs
Normal file
69
src/vk.generator/Program.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.CommandLine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
string outputPath = AppContext.BaseDirectory;
|
||||
|
||||
ArgumentSyntax.Parse(args, s =>
|
||||
{
|
||||
s.DefineOption("o|out", ref outputPath, "The folder into which code is generated. Defaults to the application directory.");
|
||||
});
|
||||
|
||||
Configuration.CodeOutputPath = outputPath;
|
||||
|
||||
if (File.Exists(outputPath))
|
||||
{
|
||||
Console.Error.WriteLine("The given path is a file, not a folder.");
|
||||
return 1;
|
||||
}
|
||||
else if (!Directory.Exists(outputPath))
|
||||
{
|
||||
Directory.CreateDirectory(outputPath);
|
||||
}
|
||||
|
||||
using (var fs = File.OpenRead(Path.Combine(AppContext.BaseDirectory, "vk.xml")))
|
||||
{
|
||||
VulkanSpecification vs = VulkanSpecification.LoadFromXmlStream(fs);
|
||||
TypeNameMappings tnm = new TypeNameMappings();
|
||||
foreach (var typedef in vs.Typedefs)
|
||||
{
|
||||
if (typedef.Requires != null)
|
||||
{
|
||||
tnm.AddMapping(typedef.Requires, typedef.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
tnm.AddMapping(typedef.Name, "uint");
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<string> definedBaseTypes = new HashSet<string>
|
||||
{
|
||||
"VkBool32"
|
||||
};
|
||||
|
||||
if (Configuration.MapBaseTypes)
|
||||
{
|
||||
foreach (var baseType in vs.BaseTypes)
|
||||
{
|
||||
if (!definedBaseTypes.Contains(baseType.Key))
|
||||
{
|
||||
tnm.AddMapping(baseType.Key, baseType.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CodeGenerator.GenerateCodeFiles(vs, tnm, Configuration.CodeOutputPath);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
32
src/vk.generator/Require.cs
Normal file
32
src/vk.generator/Require.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class Require
|
||||
{
|
||||
public static void NotNull<T>(T obj) where T : class
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
throw new InvalidOperationException("Object should not have been null.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void NotNullOrEmpty(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new InvalidOperationException("Value should not have been null or empty.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Equal<T>(T expected, T actual) where T : IEquatable<T>
|
||||
{
|
||||
if (!expected.Equals(actual))
|
||||
{
|
||||
throw new InvalidOperationException($"Requirement not met. Expected: {expected}, Actual: {actual}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
src/vk.generator/StructureDefinition.cs
Normal file
31
src/vk.generator/StructureDefinition.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class StructureDefinition
|
||||
{
|
||||
public string Name { get; }
|
||||
public MemberSpec[] Members { get; }
|
||||
|
||||
public StructureDefinition(string name, MemberSpec[] members)
|
||||
{
|
||||
Name = name;
|
||||
Members = members;
|
||||
}
|
||||
|
||||
public static StructureDefinition CreateFromXml(XElement xe)
|
||||
{
|
||||
Require.NotNull(xe);
|
||||
|
||||
string name = xe.GetNameAttribute();
|
||||
MemberSpec[] members = xe.Elements("member").Select(memberx => MemberSpec.CreateFromXml(memberx)).ToArray();
|
||||
return new StructureDefinition(name, members);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"struct {Name}[{Members.Length}]";
|
||||
}
|
||||
}
|
||||
}
|
111
src/vk.generator/StructureHelpers.cs
Normal file
111
src/vk.generator/StructureHelpers.cs
Normal file
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class StructureHelpers
|
||||
{
|
||||
private static readonly HashSet<string> s_fixedCapableTypes = new HashSet<string>()
|
||||
{
|
||||
"byte", "short", "int", "long", "char", "sbyte", "ushort", "uint", "ulong", "float", "double"
|
||||
};
|
||||
|
||||
public static void WriteStructure(CsCodeWriter cw, StructureDefinition structure, TypeNameMappings tnm, ConstantDefinition[] constants)
|
||||
{
|
||||
using (cw.PushBlock("public unsafe partial struct " + structure.Name))
|
||||
{
|
||||
foreach (var member in structure.Members)
|
||||
{
|
||||
if (member.ElementCount > 1)
|
||||
{
|
||||
for (int i = 0; i < member.ElementCount; i++)
|
||||
{
|
||||
WriteMember(cw, tnm, member, "_" + i);
|
||||
}
|
||||
}
|
||||
else if (member.ElementCountSymbolic != null)
|
||||
{
|
||||
var validConstant = constants.FirstOrDefault(cd => cd.Name == member.ElementCountSymbolic);
|
||||
if (validConstant != null)
|
||||
WriteMemberSymbolicCount(cw, tnm, member, constants);
|
||||
else
|
||||
WriteMember(cw, tnm, member, string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteMember(cw, tnm, member, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasAnyFieldWithSpecifiedValues(structure))
|
||||
{
|
||||
// Add a helper property which fills in the structure type.
|
||||
using (cw.PushBlock($"public static {structure.Name} New()"))
|
||||
{
|
||||
cw.WriteLine($"{structure.Name} ret = new {structure.Name}();");
|
||||
foreach (var member in structure.Members.Where(ms => ms.LegalValues != null))
|
||||
{
|
||||
cw.WriteLine($"ret.{member.Name} = {member.Type}.{GetDefaultValueString(member.Type, member.LegalValues)};");
|
||||
}
|
||||
cw.WriteLine("return ret;");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDefaultValueString(TypeSpec type, string legalValues)
|
||||
{
|
||||
string prefix = EnumHelpers.GetEnumNamePrefix(type.Name);
|
||||
string prettyName = EnumHelpers.GetPrettyEnumName(legalValues, prefix);
|
||||
return prettyName;
|
||||
}
|
||||
|
||||
private static bool HasAnyFieldWithSpecifiedValues(StructureDefinition sd)
|
||||
{
|
||||
return sd.Members.Any(ms => ms.LegalValues != null);
|
||||
}
|
||||
|
||||
private static void WriteMember(CsCodeWriter cw, TypeNameMappings tnm, MemberSpec member, string nameSuffix)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(member.Comment))
|
||||
{
|
||||
cw.WriteLine($"///<summary>{member.Comment}</summary>");
|
||||
}
|
||||
|
||||
cw.WriteLine($"public {member.Type.MapTypeSpec(tnm)} {Util.NormalizeFieldName(member.Name)}{nameSuffix};");
|
||||
}
|
||||
|
||||
private static void WriteMemberSymbolicCount(CsCodeWriter cw, TypeNameMappings tnm, MemberSpec member, ConstantDefinition[] constants)
|
||||
{
|
||||
if (!CanUseFixed(member.Type.MapTypeSpec(tnm)))
|
||||
{
|
||||
int count = GetSymbolValue(member.ElementCountSymbolic, constants);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
WriteMember(cw, tnm, member, "_" + i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(member.Comment))
|
||||
{
|
||||
cw.WriteLine($"///<summary>{member.Comment}</summary>");
|
||||
}
|
||||
|
||||
string mappedSymbolicName = EnumHelpers.GetPrettyEnumName(member.ElementCountSymbolic, "VK_");
|
||||
cw.WriteLine($"public fixed {member.Type.MapTypeSpec(tnm)} {Util.NormalizeFieldName(member.Name)}[(int)VK.{mappedSymbolicName}];");
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetSymbolValue(string symbolName, ConstantDefinition[] constants)
|
||||
{
|
||||
return int.Parse(constants.Single(cd => cd.Name == symbolName).Value);
|
||||
}
|
||||
|
||||
private static bool CanUseFixed(TypeSpec type)
|
||||
{
|
||||
return s_fixedCapableTypes.Contains(type.Name);
|
||||
}
|
||||
}
|
||||
}
|
70
src/vk.generator/TypeNameMappings.cs
Normal file
70
src/vk.generator/TypeNameMappings.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class TypeNameMappings
|
||||
{
|
||||
private readonly Dictionary<string, string> _nameMappings = new Dictionary<string, string>()
|
||||
{
|
||||
{ "uint8_t", "byte" },
|
||||
{ "uint32_t", "uint" },
|
||||
{ "uint64_t", "ulong" },
|
||||
{ "int32_t", "int" },
|
||||
{ "int64_t", "long" },
|
||||
{ "int64_t*", "long*" },
|
||||
{ "char", "byte" },
|
||||
{ "size_t", "UIntPtr" },
|
||||
{ "DWORD", "uint" },
|
||||
|
||||
{ "ANativeWindow", "Android.ANativeWindow" },
|
||||
|
||||
{ "MirConnection", "Mir.MirConnection" },
|
||||
{ "MirSurface", "Mir.MirSurface" },
|
||||
|
||||
{ "wl_display", "Wayland.wl_display" },
|
||||
{ "wl_surface", "Wayland.wl_surface" },
|
||||
|
||||
{ "Display", "Xlib.Display" },
|
||||
{ "Window", "Xlib.Window" },
|
||||
{ "VisualID", "Xlib.VisualID" },
|
||||
{ "RROutput", "IntPtr" },
|
||||
|
||||
{ "HINSTANCE", "Win32.HINSTANCE" },
|
||||
{ "HWND", "Win32.HWND" },
|
||||
{ "HANDLE", "Win32.HANDLE" },
|
||||
{ "SECURITY_ATTRIBUTES", "Win32.SECURITY_ATTRIBUTES" },
|
||||
{ "LPCWSTR", "IntPtr" },
|
||||
|
||||
{ "xcb_connection_t", "Xcb.xcb_connection_t" },
|
||||
{ "xcb_window_t", "Xcb.xcb_window_t" },
|
||||
{ "xcb_visualid_t", "Xcb.xcb_visualid_t" },
|
||||
};
|
||||
|
||||
internal IEnumerable<KeyValuePair<string, string>> GetAllMappings()
|
||||
{
|
||||
return _nameMappings;
|
||||
}
|
||||
|
||||
public void AddMapping(string originalName, string newName)
|
||||
{
|
||||
_nameMappings.Add(originalName, newName);
|
||||
}
|
||||
|
||||
public string GetMappedName(string name)
|
||||
{
|
||||
if (_nameMappings.TryGetValue(name, out string mappedName))
|
||||
{
|
||||
return GetMappedName(mappedName);
|
||||
}
|
||||
else if (name.StartsWith("PFN"))
|
||||
{
|
||||
return "IntPtr";
|
||||
}
|
||||
else
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
src/vk.generator/TypeSpec.cs
Normal file
51
src/vk.generator/TypeSpec.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class TypeSpec
|
||||
{
|
||||
public string Name { get; }
|
||||
public int PointerIndirection { get; }
|
||||
public int ArrayDimensions { get; }
|
||||
|
||||
public TypeSpec(string name) : this(name, 0, 0) { }
|
||||
public TypeSpec(string name, int pointerIndirection) : this(name, pointerIndirection, 0) { }
|
||||
public TypeSpec(string name, int pointerIndirection, int arrayDimensions)
|
||||
{
|
||||
Name = name;
|
||||
PointerIndirection = pointerIndirection;
|
||||
ArrayDimensions = arrayDimensions;
|
||||
}
|
||||
|
||||
public TypeSpec MapTypeSpec(TypeNameMappings tnm)
|
||||
{
|
||||
return new TypeSpec(tnm.GetMappedName(Name), PointerIndirection, ArrayDimensions);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return GetFullTypeName();
|
||||
}
|
||||
|
||||
private string GetFullTypeName()
|
||||
{
|
||||
return $"{Name}{new string('*', PointerIndirection)}{GetArrayPortion()}";
|
||||
}
|
||||
|
||||
private string GetArrayPortion()
|
||||
{
|
||||
if (ArrayDimensions == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
else if (ArrayDimensions == 1)
|
||||
{
|
||||
return "[]";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"[{new string(',', ArrayDimensions - 1)}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
src/vk.generator/TypedefDefinition.cs
Normal file
31
src/vk.generator/TypedefDefinition.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class TypedefDefinition
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Requires { get; }
|
||||
public string Type { get; }
|
||||
|
||||
public TypedefDefinition(string name, string requires, string type)
|
||||
{
|
||||
Name = name;
|
||||
Requires = requires;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public static TypedefDefinition CreateFromXml(XElement xe)
|
||||
{
|
||||
string name = xe.GetNameElement();
|
||||
string requires = xe.Attribute("requires")?.Value;
|
||||
string type = xe.GetTypeElement();
|
||||
return new TypedefDefinition(name, requires, type);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Name}, {Requires} -> {Type}";
|
||||
}
|
||||
}
|
||||
}
|
42
src/vk.generator/UnionHelpers.cs
Normal file
42
src/vk.generator/UnionHelpers.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class UnionHelpers
|
||||
{
|
||||
public static void WriteUnion(CsCodeWriter cw, TypeNameMappings tnm, StructureDefinition union)
|
||||
{
|
||||
cw.WriteLine("[StructLayout(LayoutKind.Explicit)]");
|
||||
using (cw.PushBlock("public partial struct " + union.Name))
|
||||
{
|
||||
foreach (var member in union.Members)
|
||||
{
|
||||
if (member.ElementCount > 1)
|
||||
{
|
||||
for (int i = 0; i < member.ElementCount; i++)
|
||||
{
|
||||
int fieldSize = Util.GetTypeSize(member.Type.MapTypeSpec(tnm));
|
||||
cw.WriteLine($"[FieldOffset({i * fieldSize})]");
|
||||
WriteMember(cw, tnm, member, "_" + i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cw.WriteLine("[FieldOffset(0)]");
|
||||
WriteMember(cw, tnm, member, string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteMember(CsCodeWriter cw, TypeNameMappings tnm, MemberSpec member, string nameSuffix)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(member.Comment))
|
||||
{
|
||||
cw.WriteLine($"///<summary>{member.Comment}</summary>");
|
||||
}
|
||||
|
||||
cw.WriteLine($"public {member.Type.MapTypeSpec(tnm)} {Util.NormalizeFieldName(member.Name)}{nameSuffix};");
|
||||
}
|
||||
}
|
||||
}
|
55
src/vk.generator/Util.cs
Normal file
55
src/vk.generator/Util.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class Util
|
||||
{
|
||||
private static readonly Dictionary<string, int> s_typeSizes = new Dictionary<string, int>
|
||||
{
|
||||
{ "byte", 1 },
|
||||
{ "uint", 4 },
|
||||
{ "ulong", 4 },
|
||||
{ "int", 4 },
|
||||
{ "float", 4 },
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> s_keywords = new HashSet<string>
|
||||
{
|
||||
"object",
|
||||
"event",
|
||||
};
|
||||
|
||||
public static int GetTypeSize(TypeSpec type)
|
||||
{
|
||||
if (type.PointerIndirection != 0 || !s_typeSizes.TryGetValue(type.Name, out int size))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public static string NormalizeFieldName(string name)
|
||||
{
|
||||
if (s_keywords.Contains(name))
|
||||
{
|
||||
return "@" + name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
public static void SpaceSeparatedList<T>(CsCodeWriter cw, IList<T> list, Action<T> action)
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
var item = list[i];
|
||||
action(item);
|
||||
if (i != list.Count - 1)
|
||||
{
|
||||
cw.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
122
src/vk.generator/VariantGenerator.cs
Normal file
122
src/vk.generator/VariantGenerator.cs
Normal file
|
@ -0,0 +1,122 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class VariantGenerator
|
||||
{
|
||||
public static CommandDefinition[] GenerateVariants(CommandDefinition cd)
|
||||
{
|
||||
ParameterDefinition[] parameters = cd.Parameters;
|
||||
List<ParameterDefinition>[] parameterPossibilities = new List<ParameterDefinition>[parameters.Length];
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameterPossibilities[i] = new List<ParameterDefinition>() { parameters[i] };
|
||||
parameterPossibilities[i].AddRange(GenerateVariantParameters(cd, parameters[i]));
|
||||
}
|
||||
|
||||
ParameterDefinition[][] definitions = parameterPossibilities.Select(l => l.ToArray()).ToArray();
|
||||
var combos = GetCombinations(definitions).ToArray();
|
||||
CommandDefinition[] commands = combos.Skip(1).Select(pd =>
|
||||
{
|
||||
return new CommandDefinition(cd.Name, cd.ReturnType, pd, cd.SuccessCodes, cd.ErrorCodes, true);
|
||||
}).ToArray();
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
private static IEnumerable<ParameterDefinition[]> GetCombinations(ParameterDefinition[][] pds)
|
||||
{
|
||||
ParameterDefinition[] first = pds.First();
|
||||
ParameterDefinition[][] rest = GetSubArray(pds, 1);
|
||||
foreach (var option in first)
|
||||
{
|
||||
if (!rest.Any())
|
||||
{
|
||||
yield return new[] { option };
|
||||
}
|
||||
else
|
||||
{
|
||||
var restVariants = GetCombinations(rest);
|
||||
foreach (var restVariant in restVariants)
|
||||
{
|
||||
yield return Prepend(option, restVariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ParameterDefinition> GenerateVariantParameters(CommandDefinition cd, ParameterDefinition pd)
|
||||
{
|
||||
if (CanHaveVariant(pd))
|
||||
{
|
||||
if ((cd.Name.StartsWith("Create") || cd.Name.StartsWith("Allocate") || cd.Name.StartsWith("Get")) && pd == cd.Parameters.Last())
|
||||
{
|
||||
yield return OutVariant(pd);
|
||||
}
|
||||
else if (pd.Type.Name == "char" && pd.Type.PointerIndirection == 1)
|
||||
{
|
||||
yield return StringVariant(pd);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return RefVariant(pd);
|
||||
yield return IntPtrVariant(pd);
|
||||
if (pd.Name.EndsWith("Infos"))
|
||||
{
|
||||
yield return ArrayVariant(pd, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ParameterDefinition StringVariant(ParameterDefinition pd)
|
||||
{
|
||||
TypeSpec typeSpec = new TypeSpec("string");
|
||||
return new ParameterDefinition(pd.Name, typeSpec, ParameterModifier.None, pd.IsOptional);
|
||||
}
|
||||
|
||||
private static ParameterDefinition ArrayVariant(ParameterDefinition pd, int dimensions)
|
||||
{
|
||||
TypeSpec typeSpec = new TypeSpec(pd.Type.Name, pd.Type.PointerIndirection - 1, dimensions);
|
||||
return new ParameterDefinition(pd.Name, typeSpec, ParameterModifier.None, pd.IsOptional);
|
||||
}
|
||||
|
||||
private static ParameterDefinition OutVariant(ParameterDefinition pd)
|
||||
{
|
||||
TypeSpec typeSpec = new TypeSpec(pd.Type.Name, pd.Type.PointerIndirection - 1);
|
||||
return new ParameterDefinition(pd.Name, typeSpec, ParameterModifier.Out, pd.IsOptional);
|
||||
}
|
||||
|
||||
private static ParameterDefinition RefVariant(ParameterDefinition pd)
|
||||
{
|
||||
TypeSpec typeSpec = new TypeSpec(pd.Type.Name, pd.Type.PointerIndirection - 1);
|
||||
return new ParameterDefinition(pd.Name, typeSpec, ParameterModifier.Ref, pd.IsOptional);
|
||||
}
|
||||
|
||||
private static ParameterDefinition IntPtrVariant(ParameterDefinition pd)
|
||||
{
|
||||
TypeSpec typeSpec = new TypeSpec(nameof(IntPtr));
|
||||
return new ParameterDefinition(pd.Name, typeSpec, ParameterModifier.None, pd.IsOptional);
|
||||
}
|
||||
|
||||
private static bool CanHaveVariant(ParameterDefinition pd)
|
||||
{
|
||||
return pd.Type.PointerIndirection > 0 && pd.Type.Name != "void";
|
||||
}
|
||||
|
||||
private static T[] GetSubArray<T>(T[] array, int skip)
|
||||
{
|
||||
return array.Skip(skip).ToArray();
|
||||
}
|
||||
|
||||
private static T[] Prepend<T>(T first, T[] rest)
|
||||
{
|
||||
T[] arr = new T[rest.Length + 1];
|
||||
rest.CopyTo(arr, 1);
|
||||
arr[0] = first;
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
}
|
126
src/vk.generator/VulkanSpecification.cs
Normal file
126
src/vk.generator/VulkanSpecification.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public class VulkanSpecification
|
||||
{
|
||||
public CommandDefinition[] Commands { get; }
|
||||
public ConstantDefinition[] Constants { get; }
|
||||
public TypedefDefinition[] Typedefs { get; }
|
||||
public EnumDefinition[] Enums { get; }
|
||||
public StructureDefinition[] Structures { get; }
|
||||
public StructureDefinition[] Unions{ get; }
|
||||
public HandleDefinition[] Handles { get; }
|
||||
public string[] BitmaskTypes { get; }
|
||||
public Dictionary<string, string> BaseTypes { get; }
|
||||
public ExtensionDefinition[] Extensions { get; }
|
||||
|
||||
public VulkanSpecification(
|
||||
CommandDefinition[] commands,
|
||||
ConstantDefinition[] constants,
|
||||
TypedefDefinition[] typedefs,
|
||||
EnumDefinition[] enums,
|
||||
StructureDefinition[] structures,
|
||||
StructureDefinition[] unions,
|
||||
HandleDefinition[] handles,
|
||||
string[] bitmaskTypes,
|
||||
Dictionary<string, string> baseTypes,
|
||||
ExtensionDefinition[] extensions)
|
||||
{
|
||||
Commands = commands;
|
||||
Constants = constants;
|
||||
Typedefs = typedefs;
|
||||
Enums = enums;
|
||||
Structures = structures;
|
||||
Unions = unions;
|
||||
Handles = handles;
|
||||
BitmaskTypes = bitmaskTypes;
|
||||
BaseTypes = baseTypes;
|
||||
Extensions = extensions;
|
||||
AddExtensionEnums(Enums, Extensions);
|
||||
}
|
||||
|
||||
public static VulkanSpecification LoadFromXmlStream(Stream specFileStream)
|
||||
{
|
||||
var spec = XDocument.Load(specFileStream);
|
||||
var registry = spec.Element("registry");
|
||||
var commands = registry.Element("commands");
|
||||
CommandDefinition[] commandDefinitions = commands.Elements("command")
|
||||
.Select(commandx => CommandDefinition.CreateFromXml(commandx)).ToArray();
|
||||
|
||||
ConstantDefinition[] constantDefinitions = registry.Elements("enums")
|
||||
.Where(enumx => enumx.Attribute("name").Value == "API Constants")
|
||||
.SelectMany(enumx => enumx.Elements("enum"))
|
||||
.Select(enumxx => ConstantDefinition.CreateFromXml(enumxx)).ToArray();
|
||||
|
||||
var types = registry.Elements("types");
|
||||
TypedefDefinition[] typedefDefinitions = types.Elements("type").Where(xe => xe.Value.Contains("typedef") && xe.HasCategoryAttribute("bitmask"))
|
||||
.Select(xe2 => TypedefDefinition.CreateFromXml(xe2)).ToArray();
|
||||
|
||||
EnumDefinition[] enumDefinitions = registry.Elements("enums")
|
||||
.Where(enumx => enumx.GetTypeAttributeOrNull() == "enum" || enumx.GetTypeAttributeOrNull() == "bitmask")
|
||||
.Select(enumx => EnumDefinition.CreateFromXml(enumx)).ToArray();
|
||||
|
||||
StructureDefinition[] structures = types.Elements("type").Where(typex => typex.HasCategoryAttribute("struct"))
|
||||
.Select(typex => StructureDefinition.CreateFromXml(typex)).ToArray();
|
||||
|
||||
StructureDefinition[] unions =
|
||||
types.Elements("type")
|
||||
.Where(typex => typex.HasCategoryAttribute("union"))
|
||||
.Select(typex => StructureDefinition.CreateFromXml(typex)).ToArray();
|
||||
|
||||
HandleDefinition[] handles = types.Elements("type").Where(typex => typex.HasCategoryAttribute("handle"))
|
||||
.Select(typex => HandleDefinition.CreateFromXml(typex)).ToArray();
|
||||
|
||||
string[] bitmaskTypes = types.Elements("type").Where(typex => typex.HasCategoryAttribute("bitmask"))
|
||||
.Select(typex => typex.GetNameElement()).ToArray();
|
||||
|
||||
Dictionary<string, string> baseTypes = types.Elements("type").Where(typex => typex.HasCategoryAttribute("basetype"))
|
||||
.ToDictionary(
|
||||
typex => typex.GetNameElement(),
|
||||
typex => typex.Element("type").Value);
|
||||
|
||||
ExtensionDefinition[] extensions = registry.Element("extensions").Elements("extension")
|
||||
.Select(xe => ExtensionDefinition.CreateFromXml(xe)).ToArray();
|
||||
|
||||
return new VulkanSpecification(
|
||||
commandDefinitions,
|
||||
constantDefinitions,
|
||||
typedefDefinitions,
|
||||
enumDefinitions,
|
||||
structures,
|
||||
unions,
|
||||
handles,
|
||||
bitmaskTypes,
|
||||
baseTypes,
|
||||
extensions);
|
||||
}
|
||||
|
||||
private void AddExtensionEnums(EnumDefinition[] enums, ExtensionDefinition[] extensions)
|
||||
{
|
||||
foreach (ExtensionDefinition exDef in extensions)
|
||||
{
|
||||
if (exDef.Name == "VK_KHX_device_group")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
foreach (var enumEx in exDef.EnumExtensions)
|
||||
{
|
||||
EnumDefinition enumDef = GetEnumDef(enums, enumEx.ExtendedType);
|
||||
int value = int.Parse(enumEx.Value);
|
||||
enumDef.Values = enumDef.Values.Append(new EnumValue(enumEx.Name, value, null)).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EnumDefinition GetEnumDef(EnumDefinition[] enums, string name)
|
||||
{
|
||||
return enums.Single(ed => ed.Name == name);
|
||||
}
|
||||
}
|
||||
}
|
45
src/vk.generator/XElementExtensions.cs
Normal file
45
src/vk.generator/XElementExtensions.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Vk.Generator
|
||||
{
|
||||
public static class XElementExtensions
|
||||
{
|
||||
public static string GetNameAttribute(this XElement xe)
|
||||
{
|
||||
return xe.Attribute("name").Value;
|
||||
}
|
||||
|
||||
public static string GetNameElement(this XElement xe)
|
||||
{
|
||||
return xe.Element("name").Value;
|
||||
}
|
||||
|
||||
public static string GetTypeElement(this XElement xe)
|
||||
{
|
||||
return xe.Element("type").Value;
|
||||
}
|
||||
|
||||
public static string GetTypeAttributeOrNull(this XElement xe)
|
||||
{
|
||||
return xe.Attribute("type")?.Value;
|
||||
}
|
||||
|
||||
public static bool GetOptionalAttributeOrFalse(this XElement xe)
|
||||
{
|
||||
var attr = xe.Attribute("optional");
|
||||
return attr != null
|
||||
? attr.Value == "true"
|
||||
: false;
|
||||
}
|
||||
|
||||
public static bool HasCategoryAttribute(this XElement xe, string value)
|
||||
{
|
||||
var attr = xe.Attribute("category");
|
||||
return attr != null && attr.Value == value;
|
||||
}
|
||||
}
|
||||
}
|
17
src/vk.generator/vk.generator.csproj
Normal file
17
src/vk.generator/vk.generator.csproj
Normal file
|
@ -0,0 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyName>vk.generator</AssemblyName>
|
||||
<RootNamespace>Vk.Generator</RootNamespace>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="vk.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<PackageReference Include="System.CommandLine" Version="0.1.0-e160908-1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
7634
src/vk.generator/vk.xml
Normal file
7634
src/vk.generator/vk.xml
Normal file
File diff suppressed because it is too large
Load diff
201
src/vk.rewrite/Program.cs
Normal file
201
src/vk.rewrite/Program.cs
Normal file
|
@ -0,0 +1,201 @@
|
|||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Mono.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Vk.Rewrite
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
private static TypeReference s_calliRewriteRef;
|
||||
private static MethodReference s_stringToHGlobalUtf8Ref;
|
||||
private static MethodDefinition s_freeHGlobalRef;
|
||||
private static TypeReference s_stringHandleRef;
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
string vkDllPath = null;
|
||||
string outputPath = null;
|
||||
bool copiedToTemp = false;
|
||||
var s = System.CommandLine.ArgumentSyntax.Parse(args, syntax =>
|
||||
{
|
||||
syntax.DefineOption("vkdll", ref vkDllPath, "The location of vk.dll to rewrite.");
|
||||
syntax.DefineOption("out", ref outputPath, "The output location of the rewritten DLL. If not specified, the DLL is rewritten in-place.");
|
||||
});
|
||||
|
||||
if (vkDllPath == null)
|
||||
{
|
||||
Console.WriteLine("Error: a path for --vkdll is required.");
|
||||
Console.WriteLine(s.GetHelpText());
|
||||
return -1;
|
||||
}
|
||||
if (outputPath == null)
|
||||
{
|
||||
outputPath = vkDllPath;
|
||||
string copyPath = Path.GetTempFileName();
|
||||
File.Copy(vkDllPath, copyPath, overwrite: true);
|
||||
vkDllPath = copyPath;
|
||||
copiedToTemp = true;
|
||||
}
|
||||
try
|
||||
{
|
||||
Rewrite(vkDllPath, outputPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (copiedToTemp)
|
||||
{
|
||||
File.Delete(vkDllPath);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void Rewrite(string vkDllPath, string outputPath)
|
||||
{
|
||||
using (AssemblyDefinition vkDll = AssemblyDefinition.ReadAssembly(vkDllPath))
|
||||
{
|
||||
LoadRefs(vkDll);
|
||||
ModuleDefinition mainModule = vkDll.Modules[0];
|
||||
|
||||
s_stringHandleRef = mainModule.GetType("OpenTK.Graphics.Vulkan.StringHandle");
|
||||
TypeDefinition bindingHelpers = mainModule.GetType("OpenTK.Graphics.Vulkan.BindingsHelpers");
|
||||
s_stringToHGlobalUtf8Ref = bindingHelpers.Methods.Single(md => md.Name == "StringToHGlobalUtf8");
|
||||
s_freeHGlobalRef = bindingHelpers.Methods.Single(md => md.Name == "FreeHGlobal");
|
||||
|
||||
foreach (var type in mainModule.Types)
|
||||
{
|
||||
ProcessType(type);
|
||||
}
|
||||
vkDll.Write(outputPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadRefs(AssemblyDefinition vkDll)
|
||||
{
|
||||
s_calliRewriteRef = vkDll.MainModule.GetType("OpenTK.Graphics.Vulkan.Generator.CalliRewriteAttribute");
|
||||
}
|
||||
|
||||
private static void ProcessType(TypeDefinition type)
|
||||
{
|
||||
foreach (var method in type.Methods)
|
||||
{
|
||||
ProcessMethod(method);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessMethod(MethodDefinition method)
|
||||
{
|
||||
if (method.CustomAttributes.Any(ca => ca.AttributeType == s_calliRewriteRef))
|
||||
{
|
||||
var processor = method.Body.GetILProcessor();
|
||||
RewriteMethod(method);
|
||||
method.CustomAttributes.Remove(method.CustomAttributes.Single(ca => ca.AttributeType == s_calliRewriteRef));
|
||||
}
|
||||
}
|
||||
|
||||
private static void RewriteMethod(MethodDefinition method)
|
||||
{
|
||||
var il = method.Body.GetILProcessor();
|
||||
il.Body.Instructions.Clear();
|
||||
|
||||
List<VariableDefinition> stringParams = new List<VariableDefinition>();
|
||||
for (int i = 0; i < method.Parameters.Count; i++)
|
||||
{
|
||||
EmitLoadArgument(il, i, method.Parameters);
|
||||
TypeReference parameterType = method.Parameters[i].ParameterType;
|
||||
if (parameterType.FullName == "System.String")
|
||||
{
|
||||
VariableDefinition variableDef = new VariableDefinition(s_stringHandleRef);
|
||||
method.Body.Variables.Add(variableDef);
|
||||
il.Emit(OpCodes.Call, s_stringToHGlobalUtf8Ref);
|
||||
il.Emit(OpCodes.Stloc, variableDef);
|
||||
il.Emit(OpCodes.Ldloc, variableDef);
|
||||
stringParams.Add(variableDef);
|
||||
}
|
||||
else if (parameterType.IsByReference)
|
||||
{
|
||||
VariableDefinition byRefVariable = new VariableDefinition(new PinnedType(parameterType));
|
||||
method.Body.Variables.Add(byRefVariable);
|
||||
il.Emit(OpCodes.Stloc, byRefVariable);
|
||||
il.Emit(OpCodes.Ldloc, byRefVariable);
|
||||
il.Emit(OpCodes.Conv_I);
|
||||
}
|
||||
}
|
||||
|
||||
string functionPtrName = method.Name + "_ptr";
|
||||
var field = method.DeclaringType.Fields.SingleOrDefault(fd => fd.Name == functionPtrName);
|
||||
if (field == null)
|
||||
{
|
||||
throw new InvalidOperationException("Can't find function pointer field for " + method.Name);
|
||||
}
|
||||
il.Emit(OpCodes.Ldsfld, field);
|
||||
|
||||
CallSite callSite = new CallSite(method.ReturnType)
|
||||
{
|
||||
CallingConvention = MethodCallingConvention.StdCall
|
||||
};
|
||||
foreach (ParameterDefinition pd in method.Parameters)
|
||||
{
|
||||
TypeReference parameterType;
|
||||
if (pd.ParameterType.IsByReference)
|
||||
{
|
||||
parameterType = new PointerType(pd.ParameterType.GetElementType());
|
||||
}
|
||||
else if (pd.ParameterType.FullName == "System.String")
|
||||
{
|
||||
parameterType = s_stringHandleRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameterType = pd.ParameterType;
|
||||
}
|
||||
ParameterDefinition calliPD = new ParameterDefinition(pd.Name, pd.Attributes, parameterType);
|
||||
|
||||
callSite.Parameters.Add(calliPD);
|
||||
}
|
||||
il.Emit(OpCodes.Calli, callSite);
|
||||
|
||||
foreach (var stringVar in stringParams)
|
||||
{
|
||||
il.Emit(OpCodes.Ldloc, stringVar);
|
||||
il.Emit(OpCodes.Call, s_freeHGlobalRef);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
if (method.Body.Variables.Count > 0)
|
||||
{
|
||||
method.Body.InitLocals = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitLoadArgument(ILProcessor il, int i, Collection<ParameterDefinition> parameters)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
}
|
||||
else if (i == 1)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
}
|
||||
else if (i == 2)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_2);
|
||||
}
|
||||
else if (i == 3)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_3);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
0
src/vk.rewrite/rewritten.dll
Normal file
0
src/vk.rewrite/rewritten.dll
Normal file
14
src/vk.rewrite/vk.rewrite.csproj
Normal file
14
src/vk.rewrite/vk.rewrite.csproj
Normal file
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk" DefaultTargets="Build;Publish">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyName>vk.rewrite</AssemblyName>
|
||||
<RootNamespace>Vk.Generator.Rewrite</RootNamespace>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.CommandLine" Version="0.1.0-e160908-1" />
|
||||
<PackageReference Include="Mono.Cecil" Version="0.10.0-beta7" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in a new issue