diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2021-12-02 08:35:09 +0100 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2021-12-02 08:35:09 +0100 |
| commit | 7c27042d45798225306dfbc677640ea2701f8e1a (patch) | |
| tree | e802c4333b8aada3db4d2f88dc23e5aec2910553 | |
| parent | 4a39db4c1d61907188a411d4db73033f77fc4813 (diff) | |
some docs, build dependecies, netcoreapp3.1 for tools and test
| -rw-r--r-- | VK/vulkan.csproj | 66 | ||||
| -rw-r--r-- | tests/Program.cs | 34 | ||||
| -rw-r--r-- | tests/tests.csproj | 11 | ||||
| -rw-r--r-- | vk.generator/Program.cs | 261 | ||||
| -rw-r--r-- | vk.net.sln | 13 | ||||
| -rw-r--r-- | vulkan/ExtensionMethods.cs | 98 | ||||
| -rw-r--r-- | vulkan/PinnedObjects.cs | 21 | ||||
| -rw-r--r-- | vulkan/Utils.cs | 6 | ||||
| -rw-r--r-- | vulkan/vulkan.csproj | 10 |
9 files changed, 429 insertions, 91 deletions
diff --git a/VK/vulkan.csproj b/VK/vulkan.csproj deleted file mode 100644 index 2d52f03..0000000 --- a/VK/vulkan.csproj +++ /dev/null @@ -1,66 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project Sdk="Microsoft.NET.Sdk"> - <PropertyGroup> - <TargetFrameworks>netstandard2.0</TargetFrameworks> - - <AssemblyVersion>0.2.4</AssemblyVersion> - <AssemblyName>VK</AssemblyName> - <Description>Low level vulkan bindings for .net</Description> - <Product>VK</Product> - <PackageLicence>MIT</PackageLicence> - <PackageId>Vulkan</PackageId> - <PackageTags>C# vulkan net binding</PackageTags> - <PackageLicenseExpression>MIT</PackageLicenseExpression> - <PackageVersion>$(AssemblyVersion)</PackageVersion> - <GeneratePackageOnBuild>True</GeneratePackageOnBuild> - <PackageProjectUrl>https://github.com/jpbruyere/vk.net/blob/master/README.md</PackageProjectUrl> - <Icon>vk.net-64.png</Icon> - <PackageIcon>vk.net-64.png</PackageIcon> - <SynchReleaseVersion>false</SynchReleaseVersion> - <PackageReleaseNotes> - - </PackageReleaseNotes> - </PropertyGroup> - - <ItemGroup> - <Content Include="vk.net-64.png" Pack="true" PackagePath="" /> - <ProjectReference Include="../vk.generator/vk.generator.csproj"> - <ReferenceOutputAssembly>false</ReferenceOutputAssembly> - </ProjectReference> - <ProjectReference Include="../vk.rewrite/vk.rewrite.csproj"> - <ReferenceOutputAssembly>false</ReferenceOutputAssembly> - </ProjectReference> - </ItemGroup> - - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <DefineConstants>TRACE;NETSTANDARD;NETSTANDARD2_0;DEBUG</DefineConstants> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <DefineConstants>NETSTANDARD;NETSTANDARD2_0</DefineConstants> - </PropertyGroup> - - <Target Name="generate" BeforeTargets="BeforeCompile"> - <MakeDir Directories="$(SolutionDir)build/generated" /> - <Exec Condition="$(OS) == 'Windows_NT'" Command="$(SolutionDir)build/$(Configuration)/$(ToolsFramework)/vk.generator.exe" WorkingDirectory="$(SolutionDir)build/generated"> - <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" /> - </Exec> - <Exec Condition="$(OS) != 'Windows_NT'" Command="mono $(SolutionDir)build/$(Configuration)/$(ToolsFramework)/vk.generator.exe" WorkingDirectory="$(SolutionDir)build/generated"> - <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" /> - </Exec> - <CreateItem Include="$(SolutionDir)build/generated/*.cs"> - <Output TaskParameter="Include" ItemName="Compile" /> - </CreateItem> - </Target> - - <Target Name="rewrite" AfterTargets="CoreBuild"> - <Exec Condition="$(OS) == 'Windows_NT'" Command="$(SolutionDir)build/$(Configuration)/$(ToolsFramework)/vk.rewrite.exe $(TargetPath)" ConsoleToMSBuild="true" EchoOff="true"> - <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" /> - </Exec> - <Exec Condition="$(OS) != 'Windows_NT'" Command="mono $(SolutionDir)build/$(Configuration)/$(ToolsFramework)/vk.rewrite.exe $(TargetPath)" ConsoleToMSBuild="true" EchoOff="true"> - <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" /> - </Exec> - </Target> - -</Project> diff --git a/tests/Program.cs b/tests/Program.cs new file mode 100644 index 0000000..dcbdd2a --- /dev/null +++ b/tests/Program.cs @@ -0,0 +1,34 @@ +using System; +using Vulkan; +using static Vulkan.Vk; +using Version = Vulkan.Version; + +namespace tests +{ + class Program + { + static void Main(string[] args) + { + VkInstance instance; + + VkInstanceCreateInfo ci = VkInstanceCreateInfo.New(); + VkApplicationInfo ai = VkApplicationInfo.New(); + //ai.apiVersion = new Version (1,0,0); + //ai.applicationVersion = new Version (1,0,0); + + using (PinnedObjects pi = new PinnedObjects()) { + ci.pApplicationInfo = ai.Pin(pi); + + VkResult res = vkCreateInstance (ref ci, IntPtr.Zero, out instance); + if (res != VkResult.Success) { + Console.WriteLine ($"Error: {res}"); + return; + }else + Console.WriteLine ($"Success: {res}"); + + } + + vkDestroyInstance (instance, IntPtr.Zero); + } + } +} diff --git a/tests/tests.csproj b/tests/tests.csproj new file mode 100644 index 0000000..ed261c9 --- /dev/null +++ b/tests/tests.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>netcoreapp3.1</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\vulkan\vulkan.csproj" /> + </ItemGroup> +</Project> diff --git a/vk.generator/Program.cs b/vk.generator/Program.cs index 2cc3094..a7c5419 100644 --- a/vk.generator/Program.cs +++ b/vk.generator/Program.cs @@ -9,6 +9,7 @@ using System.IO; using System.Xml; using System.Linq; using System.Net; +using System.Text.RegularExpressions; namespace vk.generator { @@ -145,7 +146,7 @@ namespace vk.generator { { "xcb_visualid_t", "Xcb.xcb_visualid_t" }, //those are not checked, just putted there for compiling - { "GgpFrameToken", "uint" }, //cant find header to check length + { "GgpFrameToken", "uint" }, //cant find header to check length { "zx_handle_t", "ulong" }, { "GgpStreamDescriptor", "ulong" }, { "PFN_vkVoidFunction","IntPtr" }, @@ -195,7 +196,7 @@ namespace vk.generator { "vkEnumerateInstanceLayerProperties", "vkEnumerateInstanceVersion"}; - static string[] reservedNames = { "event", "object" }; + static string[] reservedNames = { "event", "object" }; static Dictionary<string, ParamDef> paramsDefs = new Dictionary<string, ParamDef> (); @@ -320,11 +321,11 @@ namespace vk.generator { return name == other.name; } public override bool Equals(object obj){ - if(obj == null) return false; + if(obj == null) return false; return name == (obj as EnumerantValue).name; } public override int GetHashCode(){ - return value.GetHashCode(); + return value.GetHashCode(); } } @@ -400,6 +401,10 @@ namespace vk.generator { } static string[] valueTypes = { "byte", "int", "uint", "float", "ushort", "ulong" }; static void gen_struct (IndentedTextWriter tw, StructDef sd) { + bool hasDoc = tryFindRefPage (sd.Name, out refPage rp); + if (hasDoc) + rp.writeSummaryAndRemarks (tw); + if (sd.category == TypeCategories.union) tw.WriteLine($"[StructLayout(LayoutKind.Explicit)]"); else @@ -407,7 +412,9 @@ namespace vk.generator { tw.WriteLine ($"public unsafe partial struct {sd.Name} {{"); tw.Indent++; foreach (MemberDef mb in sd.members) { - if (!string.IsNullOrEmpty (mb.comment)) + if (hasDoc) + rp.writeMemberDocIfFound (tw, mb.Name); + else if (!string.IsNullOrEmpty (mb.comment)) tw.WriteLine ($"/// <summary> {mb.comment} </summary>"); string typeStr; @@ -532,8 +539,10 @@ namespace vk.generator { tw.WriteLine (@"}"); } - static void gen_enum_value (IndentedTextWriter tw, string enumName, EnumerantValue ev) { - if (!string.IsNullOrEmpty (ev.comment)) + static void gen_enum_value (IndentedTextWriter tw, string enumName, EnumerantValue ev, refPage? refpage = null) { + if (refpage.HasValue) + refpage.Value.writeMemberDocIfFound (tw, ev.Name); + else if (!string.IsNullOrEmpty (ev.comment)) tw.WriteLine ($"/// <summary> {ev.comment} </summary>"); if (!string.IsNullOrEmpty (ev.unusedComment)) tw.WriteLine ($"[Obsolete(\"{ev.unusedComment}\"]"); @@ -569,9 +578,11 @@ namespace vk.generator { AddAlias (ed.Name, "uint"); continue; } - - if (!string.IsNullOrEmpty (ed?.comment)) - tw.WriteLine ($"/// <summary> {ed.comment} </summary>"); + bool hasDoc = tryFindRefPage (ed.Name, out refPage rp); + if (hasDoc) { + rp.writeSummaryAndRemarks (tw); + } else if (!string.IsNullOrEmpty (ed?.comment)) + tw.WriteLine ($"///<summary>{ed.comment}</summary>"); if (ed?.type == EnumTypes.bitmask) { tw.WriteLine (@"[Flags]"); tw.WriteLine ($"public enum {td.CSName} : uint {{"); @@ -580,12 +591,20 @@ namespace vk.generator { tw.Indent++; - foreach (EnumerantValue ev in ed.values.OrderBy(aa => aa.isAlias)) - gen_enum_value (tw, td.CSName, ev); + foreach (EnumerantValue ev in ed.values.OrderBy(aa => aa.isAlias)) { + if (hasDoc) + gen_enum_value (tw, td.CSName, ev, rp); + else + gen_enum_value (tw, td.CSName, ev); + } IEnumerable<EnumerantValue> ext = extends.Where (e => e.extends == ed.Name); - foreach (EnumerantValue ev in ext.OrderBy(aa => aa.isAlias)) - gen_enum_value (tw, td.CSName, ev); + foreach (EnumerantValue ev in ext.OrderBy(aa => aa.isAlias)) { + if (hasDoc) + gen_enum_value (tw, td.CSName, ev, rp); + else + gen_enum_value (tw, td.CSName, ev); + } tw.Indent--; @@ -645,6 +664,8 @@ namespace vk.generator { } } static void gen_handle (IndentedTextWriter tw, HandleDef hd) { + if (tryFindRefPage (hd.Name, out refPage rp)) + rp.writeSummaryAndRemarks(tw, true); tw.WriteLine (@"[DebuggerDisplay(""{DebuggerDisplay,nq}"")]"); tw.WriteLine ($"public struct {hd.CSName} : IEquatable<{hd.CSName}>"); tw.WriteLine (@"{"); @@ -791,9 +812,15 @@ namespace vk.generator { } } } - - foreach (string sig in signatures) - writeCmd (tw, string.Format ($"{cd.returnType.CSName} {cd.Name} ({sig}")); + if (tryFindRefPage (cd.Name, out refPage rp)) { + foreach (string sig in signatures) { + rp.writeSummaryAndRemarks(tw); + writeCmd (tw, string.Format ($"{cd.returnType.CSName} {cd.Name} ({sig}")); + } + } else { + foreach (string sig in signatures) + writeCmd (tw, string.Format ($"{cd.returnType.CSName} {cd.Name} ({sig}")); + } tw.WriteLine (); } @@ -1255,7 +1282,200 @@ namespace vk.generator { } #endregion - const string vkxmlLocal = "Vulkan-Docs/xml/vk.xml"; + /// <summary> + /// this is a summary #ref:string + /// </summary> + struct refPage { + public string bief; + public string description; + public string cspecInfos; + public Dictionary<string, string> members; + + public void writeSummaryAndRemarks (IndentedTextWriter tw, bool writecspecAsRemark = false) { + tw.WriteLine ($"///<summary>{bief}</summary>"); + if (description != null || (writecspecAsRemark && cspecInfos != null)) { + tw.WriteLine ($"///<remarks>"); + if (writecspecAsRemark) { + foreach (string s in splitLines (cspecInfos)) + tw.WriteLine ($"///{s}"); + } + foreach (string s in splitLines (description)) + tw.WriteLine ($"///{s}"); + tw.WriteLine ($"///</remarks>"); + } + } + public void writeMemberDocIfFound (IndentedTextWriter tw, string memberName) { + if (members == null || !members.ContainsKey (memberName)) + return; + string[] docs = splitLines (members[memberName]).ToArray(); + if (docs.Length == 1) + tw.WriteLine ($"///<summary>{docs[0]}</summary>"); + else { + tw.WriteLine ($"///<summary>"); + foreach (string d in docs) + tw.WriteLine ($"///{d}"); + tw.WriteLine ($"///</summary>"); + } + } + } + static IEnumerable<string> splitLines (string s) { + if (string.IsNullOrEmpty (s)) + return new List<string>(); + List<string> tmp = s.Split (@"\n").ToList(); + int start = tmp.FindIndex (0, tmp.Count, l=>!string.IsNullOrEmpty(l)); + if (start<0) + return new List<string>(); + int end = tmp.Count < 2 ? tmp.Count - 1 : + tmp.FindLastIndex (tmp.Count - 1, start, l=>!string.IsNullOrEmpty(l)); + if (end < 0) + return tmp.GetRange (start, tmp.Count - start); + else + return tmp.GetRange (start, end + 1 - start); + } + static Regex linkRx = new Regex (@"[p|f|s|e]link:([a-zA-Z0-9_:]*)", RegexOptions.Multiline); + static Regex nameRx = new Regex (@"([p|f|s|e]name|code):([a-zA-Z0-9_]*)", RegexOptions.Multiline); + //static Regex elinkRx = new Regex (@"[p|f|s|e]link:([a-zA-Z0-9]*)", RegexOptions.Multiline); + static string seecrefG1replace = @"<see cref=""$1""/>"; + static string codeG2replace = @"<c>$2</c>"; + static string docReplacements (string s) { + if (string.IsNullOrEmpty (s)) + return ""; + string tmp = linkRx.Replace(s, seecrefG1replace); + tmp = tmp.Replace ("::pname:", "."); + tmp = nameRx.Replace(tmp, codeG2replace); + + return tmp; + } + static string readRefPageMembers (StreamReader sr, ref refPage refpage, bool isEnum) { + refpage.members = new Dictionary<string, string>(); + string memberName = null; + string memberDoc = null; + Stack<string> conditionsStack = new Stack<string>(); + while (!sr.EndOfStream) { + string l = sr.ReadLine().Trim(); + if (l.StartsWith ("include::{generated}/api")) + continue; + + if (l.StartsWith ("ifdef::")) { + conditionsStack.Push (l); + continue; + } + if (l.StartsWith ("endif::")) { + if (!conditionsStack.TryPop (out string condition)) { + printError ($"empty condition stack: {l}"); + } + } + if (l.StartsWith ("== ") || l.StartsWith (".")) { + if (memberName != null) { + if (refpage.members.ContainsKey (memberName)) + refpage.members[memberName] += @"\n--duplicated--\n" + docReplacements (memberDoc); + else + refpage.members.Add (memberName, docReplacements (memberDoc)); + } + return l; + } + if (isEnum && string.IsNullOrEmpty(l)) { + if (memberName != null) { + refpage.members.Add (memberName, docReplacements (memberDoc)); + return l; + } + continue; + } + if (l.StartsWith ("* ename:") || l.StartsWith ("* pname:")) { + l = l.Substring (8); + int nameEndIdx = l.IndexOf (' '); + string newMemberName = nameEndIdx < 0 ? l : l.Substring (0,nameEndIdx); + string newMemberDoc = nameEndIdx < 0 ? "" : l.Substring (nameEndIdx + 1); + + if (memberName != null) { + if (newMemberName == memberName) { + memberDoc += @"\n" + newMemberDoc; + continue; + } + if (refpage.members.ContainsKey (memberName)) + refpage.members[memberName] += @"\n--duplicated--\n" + docReplacements (memberDoc); + else + refpage.members.Add (memberName, docReplacements (memberDoc)); + } + memberName = newMemberName; + memberDoc = newMemberDoc; + continue; + } + memberDoc += @"\n" + l; + } + return null; + } + static bool tryFindRefPage (string name, out refPage refpage) { + refpage = default; + string path = Path.Combine (vkrefsdir, $"{name}.txt"); + if (!File.Exists(path)) + return false; + bool isEnum = true; + + using (StreamReader sr = new StreamReader (path)) { + string l = null, savedLine = null; + while(!sr.EndOfStream) { + if (savedLine != null) { + l = savedLine; + savedLine = null; + } else + l = sr.ReadLine(); + if (l.StartsWith ("= ")) { + int idx = l.IndexOf ('('); + if (idx < 1 || l.Substring (2, idx - 2) != name) + Debugger.Break(); + continue; + } + if (l.StartsWith ("== Name")) { + l = sr.ReadLine(); + refpage.bief = l.Substring (name.Length + 3); + continue; + } + if (l.StartsWith ("== C Specification")) { + while (!sr.EndOfStream) { + l = sr.ReadLine(); + if (l.StartsWith ("include::{generated}/api")) + continue; + if (l.StartsWith ("== ") || l.StartsWith (".")) { + savedLine = l; + break; + } + if (!string.IsNullOrEmpty(refpage.cspecInfos)) + refpage.cspecInfos += @"\n"; + refpage.cspecInfos += docReplacements (l); + } + continue; + } + if (l.StartsWith ("== Members") || l.StartsWith ("== Parameters")) { + isEnum = false; + savedLine = readRefPageMembers (sr, ref refpage, isEnum); + continue; + } + if (l.StartsWith ("== Description")) { + if (isEnum) { + savedLine = readRefPageMembers (sr, ref refpage, isEnum); + if (savedLine != null) + continue; + } + while (!sr.EndOfStream) { + l = sr.ReadLine(); + if (l.StartsWith ("include::{generated}/api")) + continue; + if (l.StartsWith ("== ") || l.StartsWith (".")) { + savedLine = l; + break; + } + if (!string.IsNullOrEmpty(refpage.description)) + refpage.description += @"\n"; + refpage.description += docReplacements (l); + } + continue; + } + } + } + return true; + } + const string vkrefsdir = "Vulkan-Docs/gen/refpage"; const string targetDir = "build/generated"; static string targetPath (string fileName) => Path.Combine (targetDir, $"{fileName}_gen.cs"); @@ -1267,6 +1487,11 @@ namespace vk.generator { } public static void Main (string[] args) { + if(args.Length < 1) { + Console.WriteLine ("Usage: vk.generator path/to/vk.xml"); + return; + } + string vkxmlLocal = args[0]; if (!File.Exists(vkxmlLocal)) { printError ($"[GEN] {Path.Combine (Directory.GetCurrentDirectory(),vkxmlLocal)} not found."); @@ -1,15 +1,20 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vk.generator", "vk.generator\vk.generator.csproj", "{B105512C-9461-4802-B299-A6E7A29CDAEE}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vulkan", "vulkan\vulkan.csproj", "{37D01BE5-5FE2-4742-BD5B-5D2C25FCF146}" ProjectSection(ProjectDependencies) = postProject - {B105512C-9461-4802-B299-A6E7A29CDAEE} = {AB8DF076-E252-4FDF-BCD4-9503851BB9A0} + {B105512C-9461-4802-B299-A6E7A29CDAEE} = {B105512C-9461-4802-B299-A6E7A29CDAEE} {5EC0F6C6-74C9-4509-8AC8-FAE3574AF5C7} = {5EC0F6C6-74C9-4509-8AC8-FAE3574AF5C7} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vk.rewrite", "vk.rewrite\vk.rewrite.csproj", "{5EC0F6C6-74C9-4509-8AC8-FAE3574AF5C7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{6EA93907-C477-45D7-BB68-50940821B1F1}" + ProjectSection(ProjectDependencies) = postProject + {37D01BE5-5FE2-4742-BD5B-5D2C25FCF146} = {37D01BE5-5FE2-4742-BD5B-5D2C25FCF146} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -28,6 +33,10 @@ Global {5EC0F6C6-74C9-4509-8AC8-FAE3574AF5C7}.Debug|Any CPU.Build.0 = Debug|Any CPU {5EC0F6C6-74C9-4509-8AC8-FAE3574AF5C7}.Release|Any CPU.ActiveCfg = Release|Any CPU {5EC0F6C6-74C9-4509-8AC8-FAE3574AF5C7}.Release|Any CPU.Build.0 = Release|Any CPU + {6EA93907-C477-45D7-BB68-50940821B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EA93907-C477-45D7-BB68-50940821B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EA93907-C477-45D7-BB68-50940821B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EA93907-C477-45D7-BB68-50940821B1F1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution EndGlobalSection diff --git a/vulkan/ExtensionMethods.cs b/vulkan/ExtensionMethods.cs new file mode 100644 index 0000000..0b9797f --- /dev/null +++ b/vulkan/ExtensionMethods.cs @@ -0,0 +1,98 @@ +// Copyright (c) 2019 Jean-Philippe Bruyère <jp_bruyere@hotmail.com> +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; + +using static Vulkan.Vk; + +namespace Vulkan { + public static class ExtensionMethods { + #region pinning + /// <summary> + /// list of pinned GCHandles used to pass value from managed to unmanaged code. + /// </summary> + public static Dictionary<object, GCHandle> handles = new Dictionary<object, GCHandle>(); + + /// <summary> + /// Unpin the specified object and free the GCHandle associated. + /// </summary> + public static void Unpin (this object obj) { + if (!handles.ContainsKey (obj)) { + Debug.WriteLine ("Trying to unpin unpinned object: {0}.", obj); + return; + } + handles[obj].Free (); + handles.Remove (obj); + } + + /// <summary> + /// Pin the specified object and return a pointer. MUST be Unpined as soon as possible. + /// </summary> + public static IntPtr Pin (this object obj) { + if (handles.ContainsKey (obj)) { + Debug.WriteLine ("Trying to pin already pinned object: {0}", obj); + return handles[obj].AddrOfPinnedObject (); + } + + GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); + handles.Add (obj, hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin<T> (this List<T> obj) { + if (handles.ContainsKey (obj)) + Debug.WriteLine ("Pinning already pinned object: {0}", obj); + + GCHandle hnd = GCHandle.Alloc (obj.ToArray(), GCHandleType.Pinned); + handles.Add (obj, hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin<T> (this T[] obj) { + if (handles.ContainsKey (obj)) + Debug.WriteLine ("Pinning already pinned object: {0}", obj); + + GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); + handles.Add (obj, hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin (this string obj) { + if (handles.ContainsKey (obj)) { + Debug.WriteLine ("Trying to pin already pinned object: {0}", obj); + return handles[obj].AddrOfPinnedObject (); + } + byte[] n = System.Text.Encoding.UTF8.GetBytes(obj +'\0'); + GCHandle hnd = GCHandle.Alloc (n, GCHandleType.Pinned); + handles.Add (obj, hnd); + return hnd.AddrOfPinnedObject (); + } + + //pin with pinning context + public static IntPtr Pin (this object obj, PinnedObjects ctx) { + GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); + ctx.Handles.Add (hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin<T> (this IList<T> obj, PinnedObjects ctx) { + GCHandle hnd = GCHandle.Alloc (obj.ToArray (), GCHandleType.Pinned); + ctx.Handles.Add (hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin<T> (this T[] obj, PinnedObjects ctx) { + GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); + ctx.Handles.Add (hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin (this string obj, PinnedObjects ctx) { + byte[] n = System.Text.Encoding.UTF8.GetBytes (obj + '\0'); + GCHandle hnd = GCHandle.Alloc (n, GCHandleType.Pinned); + ctx.Handles.Add (hnd); + return hnd.AddrOfPinnedObject (); + } + + #endregion + + } +} diff --git a/vulkan/PinnedObjects.cs b/vulkan/PinnedObjects.cs new file mode 100644 index 0000000..da14f26 --- /dev/null +++ b/vulkan/PinnedObjects.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2019 Jean-Philippe Bruyère <jp_bruyere@hotmail.com> +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Vulkan { + /// <summary> + /// Keep pinned object gc handles and free them on dispose. + /// </summary> + public class PinnedObjects : IDisposable { + public readonly List<GCHandle> Handles = new List<GCHandle> (); + + public void Dispose () { + for (int i = Handles.Count - 1; i >= 0; i--) + Handles[i].Free (); + GC.SuppressFinalize (this); + } + } +} diff --git a/vulkan/Utils.cs b/vulkan/Utils.cs index cd2b3ee..b91a47b 100644 --- a/vulkan/Utils.cs +++ b/vulkan/Utils.cs @@ -26,7 +26,7 @@ namespace Vulkan { System.Diagnostics.Debug.WriteLine ("device function pointer not found for " + name); else ptr = del; - hnd.Free (); - } - } + hnd.Free (); + } + } } diff --git a/vulkan/vulkan.csproj b/vulkan/vulkan.csproj index 337aca0..a93dee5 100644 --- a/vulkan/vulkan.csproj +++ b/vulkan/vulkan.csproj @@ -22,21 +22,27 @@ </PackageReleaseNotes> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <GenerateDocumentationFile>true</GenerateDocumentationFile> + + </PropertyGroup> <ItemGroup> <Content Include="vk.net-64.png" Pack="true" PackagePath="" /> </ItemGroup> + <ItemGroup> + <SpecFile Include="$(SolutionDir)Vulkan-Docs/xml/vk.xml" /> + </ItemGroup> <Target Name="generate" BeforeTargets="BeforeCompile"> <MakeDir Directories="$(SolutionDir)build/generated" /> <Exec Condition="$(OS) == 'Windows_NT'" - Command="$(SolutionDir)vk.generator/bin/$(Configuration)/$(ToolsFramework)/vk.generator.exe" + Command="$(SolutionDir)vk.generator/bin/$(Configuration)/$(ToolsFramework)/vk.generator.exe %(SpecFile.Identity)" WorkingDirectory="$(SolutionDir)"> <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" /> </Exec> <Exec Condition="$(OS) != 'Windows_NT'" - Command="$(SolutionDir)vk.generator/bin/$(Configuration)/$(ToolsFramework)/vk.generator" + Command="$(SolutionDir)vk.generator/bin/$(Configuration)/$(ToolsFramework)/vk.generator %(SpecFile.Identity)" WorkingDirectory="$(SolutionDir)"> <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" /> </Exec> |