From 83fa18407ace7b7deea471c8113855fd2af1fe0f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Sun, 31 May 2020 17:02:11 +0200 Subject: [PATCH] Memory and Span introduction --- Directory.Build.props | 4 +- addons/CrowWindow/CrowWindow.csproj | 2 +- addons/gltfLoader/glTFLoader.cs | 110 +++++++++++------------ samples/DistanceFieldFontTest/Program.cs | 1 + samples/Textured/main.cs | 1 + samples/crowWin/crowWin.csproj | 2 +- samples/deferred/main.cs | 4 + vke/src/ExtensionMethods.cs | 9 ++ vke/src/StbImage.cs | 19 +++- vke/src/base/Image.cs | 79 +++++++++++++++- vke/vke.csproj | 11 ++- 11 files changed, 176 insertions(+), 66 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b77bc6b..a755d5d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,13 +7,13 @@ 0.1.20 $(VkeReleaseVersion)-beta true - true + false 7.2 - $(DefineConstants);MEMORY_POOLS + $(DefineConstants);_MEMORY_POOLS $(DefineConstants);STB_SHARP diff --git a/addons/CrowWindow/CrowWindow.csproj b/addons/CrowWindow/CrowWindow.csproj index 58bbead..a02a429 100644 --- a/addons/CrowWindow/CrowWindow.csproj +++ b/addons/CrowWindow/CrowWindow.csproj @@ -17,7 +17,7 @@ - + diff --git a/addons/gltfLoader/glTFLoader.cs b/addons/gltfLoader/glTFLoader.cs index ee4f940..cce4019 100644 --- a/addons/gltfLoader/glTFLoader.cs +++ b/addons/gltfLoader/glTFLoader.cs @@ -16,6 +16,7 @@ using System.Linq; namespace vke.glTF { using static Vulkan.Utils; using static vke.Model; + using System.Runtime.CompilerServices; /// /// Loading context with I as the vertex index type (uint16,uint32) @@ -76,8 +77,7 @@ namespace vke.glTF { public GL.Gltf gltf; public string baseDirectory; - public byte[][] loadedBuffers; - public GCHandle[] bufferHandles; + public Memory[] loadedBuffers; List meshes; string path; @@ -88,8 +88,7 @@ namespace vke.glTF { cmdPool = _cmdPool; baseDirectory = Path.GetDirectoryName (path); gltf = Interface.LoadModel (path); - loadedBuffers = new byte [gltf.Buffers.Length] []; - bufferHandles = new GCHandle [gltf.Buffers.Length]; + loadedBuffers = new Memory [gltf.Buffers.Length]; } static byte[] loadDataUri (GL.Image img) { @@ -102,7 +101,7 @@ namespace vke.glTF { } void ensureBufferIsLoaded (int bufferIdx) { - if (loadedBuffers[bufferIdx] == null) { + if (loadedBuffers[bufferIdx].IsEmpty) { //load full buffer string uri = gltf.Buffers[bufferIdx].Uri; if (string.IsNullOrEmpty(uri))//glb @@ -111,7 +110,6 @@ namespace vke.glTF { loadedBuffers[bufferIdx] = loadDataUri (gltf.Buffers[bufferIdx]);//TODO:check this func=>System.Buffers.Text.Base64.EncodeToUtf8InPlace else loadedBuffers[bufferIdx] = File.ReadAllBytes (Path.Combine (baseDirectory, gltf.Buffers[bufferIdx].Uri)); - bufferHandles[bufferIdx] = GCHandle.Alloc (loadedBuffers[bufferIdx], GCHandleType.Pinned); } } @@ -159,10 +157,10 @@ namespace vke.glTF { stagging.Map (); unsafe { - byte* stagVertPtrInit = (byte*)stagging.MappedData.ToPointer (); - byte* stagIdxPtrInit = (byte*)(stagging.MappedData.ToPointer ()) + vertSize; - byte* stagVertPtr = stagVertPtrInit; - byte* stagIdxPtr = stagIdxPtrInit; + + Span stagVertPtrInit = new Span(stagging.MappedData.ToPointer (), (int)vertSize); + Span stagIdxPtrInit = new Span((byte*)stagging.MappedData.ToPointer() + vertSize, (int)idxSize); + Span stagVertPtr = stagVertPtrInit, stagIdxPtr = stagIdxPtrInit; foreach (GL.Mesh mesh in gltf.Meshes) { @@ -206,90 +204,92 @@ namespace vke.glTF { prim.bb.isValid = true; //Interleaving vertices - byte * inPosPtr = null, inNormPtr = null, inUvPtr = null, inUv1Ptr = null; + Span inPosPtr = Span.Empty, inNormPtr = Span.Empty, inUvPtr = Span.Empty, inUv1Ptr = Span.Empty; GL.BufferView bv = gltf.BufferViews[(int)AccPos.BufferView]; - inPosPtr = (byte*)bufferHandles[bv.Buffer].AddrOfPinnedObject ().ToPointer (); - inPosPtr += AccPos.ByteOffset + bv.ByteOffset; + inPosPtr = loadedBuffers[bv.Buffer].Span.Slice (AccPos.ByteOffset + bv.ByteOffset); if (AccNorm != null) { bv = gltf.BufferViews[(int)AccNorm.BufferView]; - inNormPtr = (byte*)bufferHandles[bv.Buffer].AddrOfPinnedObject ().ToPointer (); - inNormPtr += AccNorm.ByteOffset + bv.ByteOffset; + inNormPtr = loadedBuffers[bv.Buffer].Span.Slice (AccNorm.ByteOffset + bv.ByteOffset); } if (AccUv != null) { bv = gltf.BufferViews[(int)AccUv.BufferView]; - inUvPtr = (byte*)bufferHandles[bv.Buffer].AddrOfPinnedObject ().ToPointer (); - inUvPtr += AccUv.ByteOffset + bv.ByteOffset; + inUvPtr = loadedBuffers[bv.Buffer].Span.Slice (AccUv.ByteOffset + bv.ByteOffset); } if (AccUv1 != null) { bv = gltf.BufferViews[(int)AccUv1.BufferView]; - inUv1Ptr = (byte*)bufferHandles[bv.Buffer].AddrOfPinnedObject ().ToPointer (); - inUv1Ptr += AccUv1.ByteOffset + bv.ByteOffset; + inUv1Ptr = loadedBuffers[bv.Buffer].Span.Slice (AccUv1.ByteOffset + bv.ByteOffset); } //TODO: use vertex attributes scan for copying data if they exists for (int j = 0; j < prim.vertexCount; j++) { - System.Buffer.MemoryCopy (inPosPtr, stagVertPtr, 12, 12); - inPosPtr += 12; - if (inNormPtr != null) { - System.Buffer.MemoryCopy (inNormPtr, stagVertPtr + 12, 12, 12); - inNormPtr += 12; + inPosPtr.Slice (0, 12).CopyTo (stagVertPtr); + inPosPtr = inPosPtr.Slice(12); + if (!inNormPtr.IsEmpty) { + inNormPtr.Slice (0, 12).CopyTo (stagVertPtr.Slice (12)); + inNormPtr = inNormPtr.Slice (12); } if (inUvPtr != null) { - System.Buffer.MemoryCopy (inUvPtr, stagVertPtr + 24, 8, 8); - inUvPtr += 8; + inUvPtr.Slice (0, 8).CopyTo (stagVertPtr.Slice (24)); + inUvPtr = inUvPtr.Slice (8); } if (inUv1Ptr != null) { - System.Buffer.MemoryCopy (inUv1Ptr, stagVertPtr + 32, 8, 8); - inUv1Ptr += 8; + inUv1Ptr.Slice (0, 8).CopyTo (stagVertPtr.Slice (32)); + inUv1Ptr = inUvPtr.Slice (8); } - stagVertPtr += vertexByteSize; + stagVertPtr = stagVertPtr.Slice (vertexByteSize); } + /*Span s = stagVertPtrInit; + for (int i = 0; i < s.Length; i++) + Console.Write (s[i].ToString ("X2") + (i % 32 == 0 ? "\n" : " "));*/ + + //indices loading if (p.Indices != null) { GL.Accessor acc = gltf.Accessors[(int)p.Indices]; bv = gltf.BufferViews[(int)acc.BufferView]; - byte* inIdxPtr = (byte*)bufferHandles[bv.Buffer].AddrOfPinnedObject ().ToPointer (); - inIdxPtr += acc.ByteOffset + bv.ByteOffset; + Span inIdxPtr = loadedBuffers[bv.Buffer].Span.Slice (acc.ByteOffset + bv.ByteOffset); //TODO:double check this, I dont seems to increment stag pointer if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_SHORT) { if (indexType == VkIndexType.Uint16) { - System.Buffer.MemoryCopy (inIdxPtr, stagIdxPtr, (long)acc.Count * 2, (long)acc.Count * 2); - stagIdxPtr += (long)acc.Count * 2; + inIdxPtr.Slice (0, acc.Count * 2).CopyTo (stagIdxPtr); + stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2); } else { - uint* usPtr = (uint*)stagIdxPtr; - ushort* inPtr = (ushort*)inIdxPtr; - for (int i = 0; i < acc.Count; i++) - usPtr[i] = inPtr[i]; - stagIdxPtr += (long)acc.Count * 4; + + Span usPtr = MemoryMarshal.Cast (stagIdxPtr); + Span inPtr = MemoryMarshal.Cast < byte, ushort> (inIdxPtr); + for (int i = 0; i < acc.Count; i++) + usPtr[i] = inPtr[i]; + stagIdxPtr = stagIdxPtr.Slice (acc.Count * 4); } } else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_INT) { if (indexType == VkIndexType.Uint32) { - System.Buffer.MemoryCopy (inIdxPtr, stagIdxPtr, (long)acc.Count * 4, (long)acc.Count * 4); - stagIdxPtr += (long)acc.Count * 4; + inIdxPtr.Slice (0, acc.Count * 4).CopyTo (stagIdxPtr); + stagIdxPtr = stagIdxPtr.Slice (acc.Count * 4); } else { - ushort* usPtr = (ushort*)stagIdxPtr; - uint* inPtr = (uint*)inIdxPtr; + Span usPtr = MemoryMarshal.Cast (stagIdxPtr); + Span inPtr = MemoryMarshal.Cast (inIdxPtr); + for (int i = 0; i < acc.Count; i++) usPtr[i] = (ushort)inPtr[i]; - stagIdxPtr += (long)acc.Count * 2; + stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2); } } else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_BYTE) { //convert if (indexType == VkIndexType.Uint16) { - ushort* usPtr = (ushort*)stagIdxPtr; + Span usPtr = MemoryMarshal.Cast (stagIdxPtr); for (int i = 0; i < acc.Count; i++) usPtr[i] = (ushort)inIdxPtr[i]; - stagIdxPtr += (long)acc.Count * 2; + stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2); } else { - uint* usPtr = (uint*)stagIdxPtr; + Span usPtr = MemoryMarshal.Cast (stagIdxPtr); for (int i = 0; i < acc.Count; i++) usPtr[i] = (uint)inIdxPtr[i]; - stagIdxPtr += (long)acc.Count * 4; + stagIdxPtr = stagIdxPtr.Slice (acc.Count * 4); } } else throw new NotImplementedException (); @@ -304,6 +304,10 @@ namespace vke.glTF { } meshes.Add (m); } + + /*ReadOnlySpan tmp = new ReadOnlySpan (stagging.MappedData.ToPointer (), (int)size); + Memory mtmp = new Memory (tmp.ToArray()); + mtmp.Dump();*/ } stagging.Unmap (); @@ -433,7 +437,7 @@ namespace vke.glTF { if (img.BufferView != null) {//load image from gltf buffer view GL.BufferView bv = gltf.BufferViews[(int)img.BufferView]; ensureBufferIsLoaded (bv.Buffer); - vkimg = Image.Load (dev, bufferHandles[bv.Buffer].AddrOfPinnedObject () + bv.ByteOffset, (ulong)bv.ByteLength, VkImageUsageFlags.TransferSrc); + vkimg = Image.Load (dev, loadedBuffers[bv.Buffer].Slice (bv.ByteOffset), (ulong)bv.ByteLength, VkImageUsageFlags.TransferSrc); } else if (img.Uri.StartsWith ("data:", StringComparison.Ordinal)) {//load base64 encoded image Debug.WriteLine ("loading embedded image {0} : {1}", img.Name, img.MimeType); vkimg = Image.Load (dev, glTFLoader.loadDataUri (img), VkImageUsageFlags.TransferSrc); @@ -515,11 +519,7 @@ namespace vke.glTF { if (img.BufferView != null) {//load image from gltf buffer view GL.BufferView bv = gltf.BufferViews[(int)img.BufferView]; ensureBufferIsLoaded (bv.Buffer); - if (Image.USE_STB_SHARP) - vkimg = Image.Load (dev, transferQ, cmdPool, loadedBuffers[bv.Buffer].Skip(bv.ByteOffset).Take(bv.ByteLength).ToArray()); - else - vkimg = Image.Load (dev, transferQ, cmdPool, bufferHandles[bv.Buffer].AddrOfPinnedObject () + bv.ByteOffset, (ulong)bv.ByteLength); - + vkimg = Image.Load (dev, transferQ, cmdPool, loadedBuffers[bv.Buffer].Slice (bv.ByteOffset, bv.ByteLength)); } else if (img.Uri.StartsWith ("data:", StringComparison.Ordinal)) {//load base64 encoded image Debug.WriteLine ("loading embedded image {0} : {1}", img.Name, img.MimeType); vkimg = Image.Load (dev, transferQ, cmdPool, glTFLoader.loadDataUri (img)); @@ -619,8 +619,8 @@ namespace vke.glTF { } for (int i = 0; i < gltf.Buffers.Length; i++) { - if (bufferHandles[i].IsAllocated) - bufferHandles[i].Free (); + //if (bufferHandles[i].IsAllocated) + //bufferHandles[i].Free (); } isDisposed = true; diff --git a/samples/DistanceFieldFontTest/Program.cs b/samples/DistanceFieldFontTest/Program.cs index 906931d..52b55e0 100644 --- a/samples/DistanceFieldFontTest/Program.cs +++ b/samples/DistanceFieldFontTest/Program.cs @@ -6,6 +6,7 @@ using Glfw; using Vulkan; using vke; using vke.DistanceFieldFont; +using Image = vke.Image; namespace DistanceFieldFontTest { diff --git a/samples/Textured/main.cs b/samples/Textured/main.cs index 3206cca..f2702d6 100644 --- a/samples/Textured/main.cs +++ b/samples/Textured/main.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using Glfw; using vke; using Vulkan; +using Image = vke.Image; namespace Textured { /// diff --git a/samples/crowWin/crowWin.csproj b/samples/crowWin/crowWin.csproj index 04611c0..5091127 100644 --- a/samples/crowWin/crowWin.csproj +++ b/samples/crowWin/crowWin.csproj @@ -3,7 +3,7 @@ false - + diff --git a/samples/deferred/main.cs b/samples/deferred/main.cs index 7cdcc8c..1e32c50 100644 --- a/samples/deferred/main.cs +++ b/samples/deferred/main.cs @@ -66,6 +66,10 @@ namespace deferred { string[] modelPathes = { //"/mnt/devel/vkPinball/data/models/pinball.gltf", //"/mnt/devel/pinball.net/data/test.glb", + //Utils.DataDirectory + "models/Box.gltf", + //Utils.DataDirectory + "models/cubeOnPlane.glb", + //Utils.DataDirectory + "models/shadow.glb", + Utils.DataDirectory + "models/cube.gltf", Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf", //Utils.DataDirectory + "models/shadow.glb", Utils.DataDirectory + "models/Hubble.glb", diff --git a/vke/src/ExtensionMethods.cs b/vke/src/ExtensionMethods.cs index 6b1b0f7..589ae2a 100644 --- a/vke/src/ExtensionMethods.cs +++ b/vke/src/ExtensionMethods.cs @@ -181,5 +181,14 @@ namespace vke { } } #endregion + + #region temp + public static void Dump (this Memory mem) { + Span s = mem.Span; + for (int i = 0; i < s.Length; i++) + Console.Write (s[i].ToString("X2") + (i % 32 == 0 ? "\n" : " ")); + } + #endregion + } } diff --git a/vke/src/StbImage.cs b/vke/src/StbImage.cs index 1ae1e42..5da7534 100644 --- a/vke/src/StbImage.cs +++ b/vke/src/StbImage.cs @@ -12,9 +12,12 @@ namespace vke { static extern IntPtr Load ([MarshalAs (UnmanagedType.LPStr)] string filename, out int x, out int y, out int channels_in_file, int desired_channels); [DllImport (stblib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_memory")] - static extern IntPtr Load (IntPtr bitmap, int byteCount, out int x, out int y, out int channels_in_file, int desired_channels); + static extern IntPtr Load (IntPtr bitmap, int byteCount, out int x, out int y, out int channels_in_file, int desired_channels); - [DllImport (stblib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_image_free")] + [DllImport (stblib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_memory")] + static extern IntPtr Load2 (ref byte bitmap, int byteCount, out int x, out int y, out int channels_in_file, int desired_channels); + + [DllImport (stblib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_image_free")] static extern void FreeImage (IntPtr img); public readonly IntPtr Handle; @@ -49,6 +52,18 @@ namespace vke { Channels = requestedChannels; } /// + /// Open image with STBI library + /// + /// raw bitmap datas + /// Force returned channels count, set 0 for original count + public StbImage (Memory bitmap, int requestedChannels = 4) { + Handle = StbImage.Load2 (ref MemoryMarshal.GetReference(bitmap.Span), bitmap.Length, out Width, out Height, out Channels, requestedChannels); + if (Handle == IntPtr.Zero) + throw new Exception ($"STBI image loading error."); + if (requestedChannels > 0) + Channels = requestedChannels; + } + /// /// copy pixels to destination. /// /// Destination pointer. diff --git a/vke/src/base/Image.cs b/vke/src/base/Image.cs index 9b3905f..0b01b46 100644 --- a/vke/src/base/Image.cs +++ b/vke/src/base/Image.cs @@ -2,6 +2,7 @@ // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; +using System.Buffers; using System.Diagnostics; using Vulkan; @@ -159,6 +160,77 @@ namespace vke { return false;*/ return true; } + /// + /// Load image from byte array containing full image file (jpg, png,...) + /// + public static Image Load (Device dev, Queue staggingQ, CommandPool staggingCmdPool, + Memory bitmap, VkFormat format = VkFormat.Undefined, + VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.DeviceLocal, + VkImageTiling tiling = VkImageTiling.Optimal, bool generateMipmaps = true, + VkImageType imageType = VkImageType.Image2D, + VkImageUsageFlags usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst) { + + if (format == VkFormat.Undefined) + format = DefaultTextureFormat; + if (tiling == VkImageTiling.Optimal) + usage |= VkImageUsageFlags.TransferDst; + if (generateMipmaps) + usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst); + /*#if STB_SHARP + StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromMemory (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha); + uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1; + image = new byte [stbi.Data.Length]; + //rgba to argb for cairo. + for (int i = 0; i < stbi.Data.Length; i += 4) { + image [i] = stbi.Data[i + 2]; + image [i + 1] = stbi.Data [i + 1]; + image [i + 2] = stbi.Data [i]; + image [i + 3] = stbi.Data [i + 3]; + } + Dimensions = new Size (stbi.Width, stbi.Height); + #else*/ + + using (StbImage stbi = new StbImage (bitmap)) { + uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1; + + Image img = new Image (dev, format, usage, memoryProps, (uint)stbi.Width, (uint)stbi.Height, imageType, + VkSampleCountFlags.SampleCount1, tiling, mipLevels); + + img.load (staggingQ, staggingCmdPool, stbi.Handle, generateMipmaps); + + return img; + } +//#endif + } + /// + /// create host visible linear image without command from data pointed by IntPtr pointer containing full image file (jpg, png,...) + /// + public static Image Load (Device dev, + Memory bitmap, ulong bitmapByteCount, VkImageUsageFlags usage = VkImageUsageFlags.TransferSrc, + VkFormat format = VkFormat.Undefined, + VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, + VkImageTiling tiling = VkImageTiling.Linear, bool generateMipmaps = false, + VkImageType imageType = VkImageType.Image2D) { + + if (format == VkFormat.Undefined) + format = DefaultTextureFormat; + if (generateMipmaps) + usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst); + + using (StbImage stbi = new StbImage (bitmap)) { + uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1; + + Image img = new Image (dev, format, usage, memoryProps, (uint)stbi.Width, (uint)stbi.Height, imageType, + VkSampleCountFlags.SampleCount1, tiling, mipLevels); + + img.Map (); + stbi.CoptyTo (img.MappedData); + img.Unmap (); + + return img; + } + } + /// /// Load image from byte array containing full image file (jpg, png,...) /// @@ -192,8 +264,7 @@ namespace vke { usage |= VkImageUsageFlags.TransferDst; if (generateMipmaps) usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst); -#if STB_SHARP - +/*#if STB_SHARP StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromMemory (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha); uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1; image = new byte [stbi.Data.Length]; @@ -205,7 +276,7 @@ namespace vke { image [i + 3] = stbi.Data [i + 3]; } Dimensions = new Size (stbi.Width, stbi.Height); -#else +#else*/ using (StbImage stbi = new StbImage (bitmap, bitmapByteCount)) { uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1; @@ -216,7 +287,7 @@ namespace vke { return img; } -#endif +//#endif } /// diff --git a/vke/vke.csproj b/vke/vke.csproj index 23fbace..e920e5f 100644 --- a/vke/vke.csproj +++ b/vke/vke.csproj @@ -47,10 +47,19 @@ - + + + + + + + + + + -- 2.47.3