From 42438ea39a1026f0a63e622ace76bb9e42ed541c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Wollenschl=C3=A4ger?= Date: Sat, 2 Apr 2016 16:22:24 +0900 Subject: [PATCH] Add triangle sample --- Samples/MiniTri/CompileShaders.cmd | 2 + Samples/MiniTri/MiniTri.csproj | 84 ++ Samples/MiniTri/MiniTri.frag | 31 + Samples/MiniTri/MiniTri.vert | 34 + Samples/MiniTri/Program.cs | 36 + Samples/MiniTri/Properties/AssemblyInfo.cs | 36 + Samples/MiniTri/Sample.cs | 900 +++++++++++++++++++++ Samples/MiniTri/app.config | 3 + Samples/MiniTri/frag.spv | Bin 0 -> 568 bytes Samples/MiniTri/packages.config | 5 + Samples/MiniTri/vert.spv | Bin 0 -> 1008 bytes Samples/SharpVulkanSamples.sln | 22 + Source/SharpVulkan/SharpVulkan.csproj | 8 +- 13 files changed, 1157 insertions(+), 4 deletions(-) create mode 100644 Samples/MiniTri/CompileShaders.cmd create mode 100644 Samples/MiniTri/MiniTri.csproj create mode 100644 Samples/MiniTri/MiniTri.frag create mode 100644 Samples/MiniTri/MiniTri.vert create mode 100644 Samples/MiniTri/Program.cs create mode 100644 Samples/MiniTri/Properties/AssemblyInfo.cs create mode 100644 Samples/MiniTri/Sample.cs create mode 100644 Samples/MiniTri/app.config create mode 100644 Samples/MiniTri/frag.spv create mode 100644 Samples/MiniTri/packages.config create mode 100644 Samples/MiniTri/vert.spv create mode 100644 Samples/SharpVulkanSamples.sln diff --git a/Samples/MiniTri/CompileShaders.cmd b/Samples/MiniTri/CompileShaders.cmd new file mode 100644 index 0000000..37ad40c --- /dev/null +++ b/Samples/MiniTri/CompileShaders.cmd @@ -0,0 +1,2 @@ +glslangValidator.exe -V MiniTri.frag +glslangValidator.exe -V MiniTri.vert \ No newline at end of file diff --git a/Samples/MiniTri/MiniTri.csproj b/Samples/MiniTri/MiniTri.csproj new file mode 100644 index 0000000..0e8b9b4 --- /dev/null +++ b/Samples/MiniTri/MiniTri.csproj @@ -0,0 +1,84 @@ + + + + + Debug + AnyCPU + {96426D44-3995-44F5-85C0-901027203313} + WinExe + Properties + MiniTri + MiniTri + v4.5.1 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + MiniTri.Program + + + + ..\packages\SharpDX.3.0.2\lib\net45\SharpDX.dll + True + + + ..\packages\SharpDX.Desktop.3.0.2\lib\net45\SharpDX.Desktop.dll + True + + + ..\..\Bin\SharpVulkan.dll + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + PreserveNewest + + + + + \ No newline at end of file diff --git a/Samples/MiniTri/MiniTri.frag b/Samples/MiniTri/MiniTri.frag new file mode 100644 index 0000000..5f81235 --- /dev/null +++ b/Samples/MiniTri/MiniTri.frag @@ -0,0 +1,31 @@ +// Copyright (c) 2016 Jörg Wollenschläger +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#version 400 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 Color; + +layout (location = 0) out vec4 FragColor; + +void main() { + FragColor = vec4(Color, 1); +} diff --git a/Samples/MiniTri/MiniTri.vert b/Samples/MiniTri/MiniTri.vert new file mode 100644 index 0000000..410bf12 --- /dev/null +++ b/Samples/MiniTri/MiniTri.vert @@ -0,0 +1,34 @@ +// Copyright (c) 2016 Jörg Wollenschläger +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#version 400 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 Position; +layout (location = 1) in vec3 ColorIn; + +layout (location = 0) out vec3 ColorOut; + +void main() +{ + ColorOut = ColorIn; + gl_Position = vec4(Position, 1); +} diff --git a/Samples/MiniTri/Program.cs b/Samples/MiniTri/Program.cs new file mode 100644 index 0000000..91aaeff --- /dev/null +++ b/Samples/MiniTri/Program.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2016 Jörg Wollenschläger +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; + +namespace MiniTri +{ + static class Program + { + [STAThread] + private static void Main() + { + using (var sample = new Sample()) + { + sample.Run(); + } + } + } +} diff --git a/Samples/MiniTri/Properties/AssemblyInfo.cs b/Samples/MiniTri/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..bb1aade --- /dev/null +++ b/Samples/MiniTri/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MiniTri")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MiniTri")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("96426d44-3995-44f5-85c0-901027203313")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/MiniTri/Sample.cs b/Samples/MiniTri/Sample.cs new file mode 100644 index 0000000..b3de99d --- /dev/null +++ b/Samples/MiniTri/Sample.cs @@ -0,0 +1,900 @@ +// Copyright (c) 2016 Jörg Wollenschläger +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using SharpDX; +using SharpDX.Text; +using SharpDX.Windows; + +namespace MiniTri +{ + using SharpVulkan; + + public unsafe class Sample : IDisposable + { + private readonly bool validate = false; + + private readonly Form form; + + private Instance instance; + private PhysicalDevice physicalDevice; + private Queue queue; + private Device device; + private DebugReportCallback debugReportCallback; + private DebugReportCallbackDelegate debugReport; + + private Surface surface; + private Swapchain swapchain; + private Format backBufferFormat; + private Image[] backBuffers; + private ImageView[] backBufferViews; + private uint currentBackBufferIndex; + private Image depthStencilBuffer; + private ImageView depthStencilView; + + private CommandPool commandPool; + private CommandBuffer commandBuffer; + private CommandBuffer setupCommanBuffer; + + private PipelineLayout pipelineLayout; + private Pipeline pipeline; + private RenderPass renderPass; + private Framebuffer[] framebuffers; + + private Buffer vertexBuffer; + private DeviceMemory vertexBufferMemory; + private VertexInputAttributeDescription[] vertexAttributes; + private VertexInputBindingDescription[] vertexBindings; + + public Sample() + { + form = new RenderForm("SharpVulkan - Vulkan Sample"); + } + + public void Run() + { + Debugger.Launch(); + Initialize(); + RenderLoop.Run(form, Draw); + } + + protected virtual void Initialize() + { + CreateInstance(); + CreateSurface(); + CreateDevice(); + CreateCommandBuffer(); + + CreateSwapchain(); + CreateBackBufferViews(); + + CreateVertexBuffer(); + CreateRenderPass(); + CreatePipelineLayout(); + CreatePipeline(); + CreateFramebuffers(); + } + + protected virtual void CreateInstance() + { + var applicationInfo = new ApplicationInfo + { + StructureType = StructureType.ApplicationInfo, + EngineVersion = 0, + ApiVersion = Vulkan.ApiVersion + }; + + var enabledLayerNames = new [] + { + Marshal.StringToHGlobalAnsi("VK_LAYER_LUNARG_standard_validation"), + }; + + var enabledExtensionNames = new [] + { + Marshal.StringToHGlobalAnsi("VK_KHR_surface"), + Marshal.StringToHGlobalAnsi("VK_KHR_win32_surface"), + Marshal.StringToHGlobalAnsi("VK_EXT_debug_report"), + }; + + try + { + fixed (void* enabledLayerNamesPointer = &enabledLayerNames[0]) + fixed (void* enabledExtensionNamesPointer = &enabledExtensionNames[0]) + { + var instanceCreateInfo = new InstanceCreateInfo + { + StructureType = StructureType.InstanceCreateInfo, + ApplicationInfo = new IntPtr(&applicationInfo), + EnabledExtensionCount = (uint)enabledExtensionNames.Length, + EnabledExtensionNames = new IntPtr(enabledExtensionNamesPointer), + }; + + if (validate) + { + instanceCreateInfo.EnabledLayerCount = (uint)enabledLayerNames.Length; + instanceCreateInfo.EnabledLayerNames = new IntPtr(enabledLayerNamesPointer); + } + + instance = Vulkan.CreateInstance(ref instanceCreateInfo); + } + + if (validate) + { + var createDebugReportCallbackName = Encoding.ASCII.GetBytes("vkCreateDebugReportCallbackEXT"); + fixed (byte* createDebugReportCallbackNamePointer = &createDebugReportCallbackName[0]) + { + var createDebugReportCallback = Marshal.GetDelegateForFunctionPointer(instance.GetProcAddress(createDebugReportCallbackNamePointer)); + + debugReport = DebugReport; + var createInfo = new DebugReportCallbackCreateInfo + { + StructureType = StructureType.DebugReportCallbackCreateInfo, + Flags = (uint)(DebugReportFlags.Error | DebugReportFlags.Warning | DebugReportFlags.PerformanceWarning), + Callback = Marshal.GetFunctionPointerForDelegate(debugReport) + }; + createDebugReportCallback(instance, ref createInfo, null, out debugReportCallback); + } + } + } + finally + { + foreach (var enabledExtensionName in enabledExtensionNames) + Marshal.FreeHGlobal(enabledExtensionName); + + foreach (var enabledLayerName in enabledLayerNames) + Marshal.FreeHGlobal(enabledLayerName); + } + + physicalDevice = instance.PhysicalDevices[0]; + + var props = physicalDevice.QueueFamilyProperties; + } + + private static RawBool DebugReport(DebugReportFlags flags, DebugReportObjectType objectType, ulong @object, PointerSize location, int messageCode, string layerPrefix, string message, IntPtr userData) + { + Debug.WriteLine($"{flags}: {message} ([{messageCode}] {layerPrefix})"); + return true; + } + + protected virtual void CreateDevice() + { + uint queuePriorities = 0; + var queueCreateInfo = new DeviceQueueCreateInfo + { + StructureType = StructureType.DeviceQueueCreateInfo, + QueueFamilyIndex = 0, + QueueCount = 1, + QueuePriorities = new IntPtr(&queuePriorities) + }; + + var enabledLayerNames = new[] + { + Marshal.StringToHGlobalAnsi("VK_LAYER_LUNARG_standard_validation"), + }; + + var enabledExtensionNames = new[] + { + Marshal.StringToHGlobalAnsi("VK_KHR_swapchain"), + }; + + try + { + fixed (void* enabledLayerNamesPointer = &enabledLayerNames[0]) + fixed (void* enabledExtensionNamesPointer = &enabledExtensionNames[0]) + { + var deviceCreateInfo = new DeviceCreateInfo + { + StructureType = StructureType.DeviceCreateInfo, + QueueCreateInfoCount = 1, + QueueCreateInfos = new IntPtr(&queueCreateInfo), + EnabledExtensionCount = (uint)enabledExtensionNames.Length, + EnabledExtensionNames = new IntPtr(enabledExtensionNamesPointer) + }; + + if (validate) + { + deviceCreateInfo.EnabledLayerCount = (uint)enabledLayerNames.Length; + deviceCreateInfo.EnabledLayerNames = new IntPtr(enabledLayerNamesPointer); + } + + device = physicalDevice.CreateDevice(ref deviceCreateInfo); + } + } + finally + { + foreach (var enabledExtensionName in enabledExtensionNames) + Marshal.FreeHGlobal(enabledExtensionName); + + foreach (var enabledLayerName in enabledLayerNames) + Marshal.FreeHGlobal(enabledLayerName); + } + + var queueNodeIndex = physicalDevice.QueueFamilyProperties. + Where((properties, index) => (properties.QueueFlags & QueueFlags.Graphics) != 0 && physicalDevice.GetSurfaceSupport((uint)index, surface)). + Select((properties, index) => index).First(); + + queue = device.GetQueue(0, (uint)queueNodeIndex); + } + + protected virtual void CreateSurface() + { + var surfaceCreateInfo = new Win32SurfaceCreateInfo + { + StructureType = StructureType.Win32SurfaceCreateInfo, + InstanceHandle = Process.GetCurrentProcess().Handle, + WindowHandle = form.Handle, + }; + surface = instance.CreateWin32Surface(surfaceCreateInfo); + } + + protected virtual void CreateSwapchain() + { + // surface format + var surfaceFormats = physicalDevice.GetSurfaceFormats(surface); + if (surfaceFormats.Length == 1 && surfaceFormats[0].Format == Format.Undefined) + { + backBufferFormat = Format.B8G8R8A8UNorm; + } + else + { + backBufferFormat = surfaceFormats[0].Format; + } + + SurfaceCapabilities surfaceCapabilities; + physicalDevice.GetSurfaceCapabilities(surface, out surfaceCapabilities); + + // Buffer count + uint desiredImageCount = surfaceCapabilities.MinImageCount + 1; + if (surfaceCapabilities.MaxImageCount > 0 && desiredImageCount > surfaceCapabilities.MaxImageCount) + { + desiredImageCount = surfaceCapabilities.MaxImageCount; + } + + // Transform + SurfaceTransformFlags preTransform; + if ((surfaceCapabilities.SupportedTransforms & SurfaceTransformFlags.Identity) != 0) + { + preTransform = SurfaceTransformFlags.Identity; + } + else + { + preTransform = surfaceCapabilities.CurrentTransform; + } + + // Present mode + var presentModes = physicalDevice.GetSurfacePresentModes(surface); + + var swapChainPresentMode = PresentMode.Fifo; + if (presentModes.Contains(PresentMode.Mailbox)) + swapChainPresentMode = PresentMode.Mailbox; + else if (presentModes.Contains(PresentMode.Immediate)) + swapChainPresentMode = PresentMode.Immediate; + + // Create swapchain + var swapchainCreateInfo = new SwapchainCreateInfo + { + StructureType = StructureType.SwapchainCreateInfo, + Surface = surface, + ImageSharingMode = SharingMode.Exclusive, + ImageExtent = new Extent2D((uint)form.ClientSize.Width, (uint)form.ClientSize.Height), + ImageArrayLayers = 1, + ImageFormat = backBufferFormat, + ImageColorSpace = ColorSpace.SRgbNonlinear, + ImageUsage = ImageUsageFlags.ColorAttachment, + PresentMode = swapChainPresentMode, + CompositeAlpha = CompositeAlphaFlags.Opaque, + MinImageCount = desiredImageCount, + PreTransform = preTransform, + Clipped = true + // OldSwapchain = + }; + swapchain = device.CreateSwapchain(ref swapchainCreateInfo); + + // Initialize swapchain image layout + backBuffers = device.GetSwapchainImages(swapchain); + foreach (var image in backBuffers) + { + SetImageLayout(image, ImageAspectFlags.Color, ImageLayout.Undefined, ImageLayout.PresentSource); + } + Flush(); + } + + protected virtual void CreateBackBufferViews() + { + + backBufferViews = new ImageView[backBuffers.Length]; + + for (var i = 0; i < backBuffers.Length; i++) + { + var createInfo = new ImageViewCreateInfo + { + StructureType = StructureType.ImageViewCreateInfo, + ViewType = ImageViewType.Image2D, + Format = backBufferFormat, + Image = backBuffers[i], + Components = ComponentMapping.Identity, + SubresourceRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 1, 0, 1) + }; + + backBufferViews[i] = device.CreateImageView(ref createInfo); + } + } + + protected virtual void CreateCommandBuffer() + { + // Command pool + var commandPoolCreateInfo = new CommandPoolCreateInfo + { + StructureType = StructureType.CommandPoolCreateInfo, + QueueFamilyIndex = 0, + Flags = CommandPoolCreateFlags.ResetCommandBuffer + }; + commandPool = device.CreateCommandPool(ref commandPoolCreateInfo); + + // Command buffer + var commandBufferAllocationInfo = new CommandBufferAllocateInfo + { + StructureType = StructureType.CommandBufferAllocateInfo, + Level = CommandBufferLevel.Primary, + CommandPool = commandPool, + CommandBufferCount = 1 + }; + CommandBuffer commandBuffer; + device.AllocateCommandBuffers(ref commandBufferAllocationInfo, &commandBuffer); + this.commandBuffer = commandBuffer; + } + + private void CreateVertexBuffer() + { + var vertices = new[,] + { + { 0.0f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f }, + { 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f }, + { -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f }, + }; + + var createInfo = new BufferCreateInfo + { + StructureType = StructureType.BufferCreateInfo, + Usage = BufferUsageFlags.VertexBuffer, + Size = (ulong)(sizeof(float) * vertices.Length) + }; + vertexBuffer = device.CreateBuffer(ref createInfo); + + MemoryRequirements memoryRequirements; + device.GetBufferMemoryRequirements(vertexBuffer, out memoryRequirements); + + if (memoryRequirements.Size == 0) + return; + + var allocateInfo = new MemoryAllocateInfo + { + StructureType = StructureType.MemoryAllocateInfo, + AllocationSize = memoryRequirements.Size, + MemoryTypeIndex = MemoryTypeFromProperties(memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.HostVisible) + }; + vertexBufferMemory = device.AllocateMemory(ref allocateInfo); + + var mapped = device.MapMemory(vertexBufferMemory, 0, (ulong)createInfo.Size, MemoryMapFlags.None); + fixed (float* source = &vertices[0, 0]) Utilities.CopyMemory(mapped, new IntPtr(source), (int)createInfo.Size); + device.UnmapMemory(vertexBufferMemory); + + device.BindBufferMemory(vertexBuffer, vertexBufferMemory, 0); + + vertexAttributes = new [] + { + new VertexInputAttributeDescription { Binding = 0, Location = 0, Format = Format.R32G32B32SFloat, Offset = 0 }, + new VertexInputAttributeDescription { Binding = 0, Location = 1, Format = Format.R32G32B32SFloat, Offset = sizeof(float) * 3 }, + }; + + vertexBindings = new [] + { + new VertexInputBindingDescription { Binding = 0, InputRate = VertexInputRate.Vertex, Stride = (uint)(sizeof(float) * vertices.GetLength(1)) } + }; + } + + private void CreateRenderPass() + { + var colorAttachmentReference = new AttachmentReference { Attachment = 0, Layout = ImageLayout.ColorAttachmentOptimal }; + var depthStencilAttachmentReference = new AttachmentReference { Attachment = 1, Layout = ImageLayout.DepthStencilAttachmentOptimal }; + + var subpass = new SubpassDescription + { + PipelineBindPoint = PipelineBindPoint.Graphics, + ColorAttachmentCount = 1, + ColorAttachments = new IntPtr(&colorAttachmentReference), + }; + + var attachments = new[] + { + new AttachmentDescription + { + Format = backBufferFormat, + Samples = SampleCountFlags.Sample1, + LoadOperation = AttachmentLoadOperation.Load, + StoreOperation = AttachmentStoreOperation.Store, + StencilLoadOperation = AttachmentLoadOperation.DontCare, + StencilStoreOperation = AttachmentStoreOperation.DontCare, + InitialLayout = ImageLayout.ColorAttachmentOptimal, + FinalLayout = ImageLayout.ColorAttachmentOptimal + }, + }; + + fixed (AttachmentDescription* attachmentsPointer = &attachments[0]) + { + var createInfo = new RenderPassCreateInfo + { + StructureType = StructureType.RenderPassCreateInfo, + AttachmentCount = (uint)attachments.Length, + Attachments = new IntPtr(attachmentsPointer), + SubpassCount = 1, + Subpasses = new IntPtr(&subpass) + }; + + renderPass = device.CreateRenderPass(ref createInfo); + } + } + + private void CreateFramebuffers() + { + framebuffers = new Framebuffer[backBuffers.Length]; + for (int i = 0; i < backBuffers.Length; i++) + { + var attachment = backBufferViews[i]; + var createInfo = new FramebufferCreateInfo + { + StructureType = StructureType.FramebufferCreateInfo, + RenderPass = renderPass, + AttachmentCount = 1, + Attachments = new IntPtr(&attachment), + Width = (uint)form.ClientSize.Width, + Height = (uint)form.ClientSize.Height, + Layers = 1 + }; + framebuffers[i] = device.CreateFramebuffer(ref createInfo); + } + } + + private void CreatePipelineLayout() + { + // We don't need any descriptors, since we don't use any resources/uniforms + var descriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo { StructureType = StructureType.DescriptorSetLayoutCreateInfo }; + var descriptorSetLayout = device.CreateDescriptorSetLayout(ref descriptorSetLayoutCreateInfo); + + var createInfo = new PipelineLayoutCreateInfo { StructureType = StructureType.PipelineLayoutCreateInfo }; + pipelineLayout = device.CreatePipelineLayout(ref createInfo); + + // Destroy temporary layout + device.DestroyDescriptorSetLayout(descriptorSetLayout); + } + + private void CreatePipeline() + { + var dynamicStates = new [] { DynamicState.Viewport, DynamicState.Scissor }; + + var entryPointName = System.Text.Encoding.UTF8.GetBytes("main\0"); + + fixed (byte* entryPointNamePointer = &entryPointName[0]) + fixed (DynamicState* dynamicStatesPointer = &dynamicStates[0]) + fixed (VertexInputAttributeDescription* vertexAttibutesPointer = &vertexAttributes[0]) + fixed (VertexInputBindingDescription* vertexBindingsPointer = &vertexBindings[0]) + { + var dynamicState = new PipelineDynamicStateCreateInfo + { + StructureType = StructureType.PipelineDynamicStateCreateInfo, + DynamicStateCount = (uint)dynamicStates.Length, + DynamicStates = new IntPtr(dynamicStatesPointer) + }; + + var viewportState = new PipelineViewportStateCreateInfo + { + StructureType = StructureType.PipelineViewportStateCreateInfo, + ScissorCount = 1, + ViewportCount = 1, + }; + + var vertexInputState = new PipelineVertexInputStateCreateInfo + { + StructureType = StructureType.PipelineVertexInputStateCreateInfo, + VertexAttributeDescriptionCount = (uint)vertexAttributes.Length, + VertexAttributeDescriptions = new IntPtr(vertexAttibutesPointer), + VertexBindingDescriptionCount = (uint)vertexBindings.Length, + VertexBindingDescriptions = new IntPtr(vertexBindingsPointer), + }; + + var inputAssemblyState = new PipelineInputAssemblyStateCreateInfo + { + StructureType = StructureType.PipelineInputAssemblyStateCreateInfo, + Topology = PrimitiveTopology.TriangleList + }; + + var rasterizerState = new PipelineRasterizationStateCreateInfo + { + StructureType = StructureType.PipelineRasterizationStateCreateInfo, + PolygonMode = PolygonMode.Fill, + CullMode = CullModeFlags.None, + FrontFace = FrontFace.Clockwise, + }; + + var colorBlendAttachment = new PipelineColorBlendAttachmentState { ColorWriteMask = ColorComponentFlags.R | ColorComponentFlags.G | ColorComponentFlags.B | ColorComponentFlags.A }; + var blendState = new PipelineColorBlendStateCreateInfo + { + StructureType = StructureType.PipelineColorBlendStateCreateInfo, + AttachmentCount = 1, + Attachments = new IntPtr(&colorBlendAttachment) + }; + + var depthStencilState = new PipelineDepthStencilStateCreateInfo + { + StructureType = StructureType.PipelineDepthStencilStateCreateInfo, + DepthTestEnable = false, + DepthWriteEnable = true, + DepthCompareOperation = CompareOperation.LessOrEqual, + Back = new StencilOperationState { CompareOperation = CompareOperation.Always }, + Front = new StencilOperationState { CompareOperation = CompareOperation.Always } + }; + + var shaderStages = new[] + { + new PipelineShaderStageCreateInfo + { + StructureType = StructureType.PipelineShaderStageCreateInfo, + Name = new IntPtr(entryPointNamePointer), + Stage = ShaderStageFlags.Vertex, + Module = CreateVertexShader() + }, + new PipelineShaderStageCreateInfo + { + StructureType = StructureType.PipelineShaderStageCreateInfo, + Name = new IntPtr(entryPointNamePointer), + Stage = ShaderStageFlags.Fragment, + Module = CreateFragmentShader() + } + }; + + fixed (PipelineShaderStageCreateInfo* shaderStagesPointer = &shaderStages[0]) + { + var createInfo = new GraphicsPipelineCreateInfo + { + StructureType = StructureType.GraphicsPipelineCreateInfo, + Layout = pipelineLayout, + DynamicState = new IntPtr(&dynamicState), + ViewportState = new IntPtr(&viewportState), + VertexInputState = new IntPtr(&vertexInputState), + InputAssemblyState = new IntPtr(&inputAssemblyState), + RasterizationState = new IntPtr(&rasterizerState), + ColorBlendState = new IntPtr(&blendState), + DepthStencilState = new IntPtr(&depthStencilState), + StageCount = (uint)shaderStages.Length, + Stages = new IntPtr(shaderStagesPointer), + RenderPass = renderPass + }; + pipeline = device.CreateGraphicsPipelines(PipelineCache.Null, 1, &createInfo); + } + + foreach (var shaderStage in shaderStages) + { + device.DestroyShaderModule(shaderStage.Module); + } + } + } + + private ShaderModule CreateVertexShader() + { + var bytes = File.ReadAllBytes("vert.spv"); + return CreateShaderModule(bytes); + } + + private ShaderModule CreateFragmentShader() + { + var bytes = File.ReadAllBytes("frag.spv"); + return CreateShaderModule(bytes); + } + + private ShaderModule CreateShaderModule(byte[] shaderCode) + { + fixed (byte* codePointer = &shaderCode[0]) + { + var createInfo = new ShaderModuleCreateInfo + { + StructureType = StructureType.ShaderModuleCreateInfo, + CodeSize = shaderCode.Length, + Code = new IntPtr(codePointer) + }; + return device.CreateShaderModule(ref createInfo); + } + } + + private uint MemoryTypeFromProperties(uint typeBits, MemoryPropertyFlags memoryProperties) + { + PhysicalDeviceMemoryProperties physicalDeviceMemoryProperties; + physicalDevice.GetMemoryProperties(out physicalDeviceMemoryProperties); + for (uint i = 0; i < physicalDeviceMemoryProperties.MemoryTypeCount; i++) + { + if ((typeBits & 1) == 1) + { + // Type is available, does it match user properties? + var memoryType = *((MemoryType*)&physicalDeviceMemoryProperties.MemoryTypes + i); + if ((memoryType.PropertyFlags & memoryProperties) == memoryProperties) + { + return i; + } + } + typeBits >>= 1; + } + + throw new InvalidOperationException(); + } + + protected virtual void Draw() + { + var semaphoreCreateInfo = new SemaphoreCreateInfo { StructureType = StructureType.SemaphoreCreateInfo }; + var presentCompleteSemaphore = device.CreateSemaphore(ref semaphoreCreateInfo); + + try + { + // Get the index of the next available swapchain image + currentBackBufferIndex = device.AcquireNextImage(this.swapchain, ulong.MaxValue, presentCompleteSemaphore, Fence.Null); + } + catch (SharpVulkanException e) when (e.Result == Result.ErrorOutOfDate) + { + // TODO: Handle resize and retry draw + throw new NotImplementedException(); + } + + // Record drawing command buffer + var beginInfo = new CommandBufferBeginInfo { StructureType = StructureType.CommandBufferBeginInfo }; + commandBuffer.Begin(ref beginInfo); + DrawInternal(); + commandBuffer.End(); + + // Submit + var drawCommandBuffer = commandBuffer; + var pipelineStageFlags = PipelineStageFlags.BottomOfPipe; + var submitInfo = new SubmitInfo + { + StructureType = StructureType.SubmitInfo, + WaitSemaphoreCount = 1, + WaitSemaphores = new IntPtr(&presentCompleteSemaphore), + WaitDstStageMask = new IntPtr(&pipelineStageFlags), + CommandBufferCount = 1, + CommandBuffers = new IntPtr(&drawCommandBuffer), + }; + queue.Submit(1, &submitInfo, Fence.Null); + + // Present + var swapchain = this.swapchain; + var currentBackBufferIndexCopy = currentBackBufferIndex; + var presentInfo = new PresentInfo + { + StructureType = StructureType.PresentInfo, + SwapchainCount = 1, + Swapchains = new IntPtr(&swapchain), + ImageIndices = new IntPtr(¤tBackBufferIndexCopy) + }; + queue.Present(ref presentInfo); + + // Wait + queue.WaitIdle(); + + // Cleanup + device.DestroySemaphore(presentCompleteSemaphore); + } + + private void DrawInternal() + { + // Post-present transition + var memoryBarrier = new ImageMemoryBarrier + { + StructureType = StructureType.ImageMemoryBarrier, + Image = backBuffers[currentBackBufferIndex], + SubresourceRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 1, 0, 1), + OldLayout = ImageLayout.PresentSource, + NewLayout = ImageLayout.ColorAttachmentOptimal, + SourceAccessMask = AccessFlags.MemoryRead, + DestinationAccessMask = AccessFlags.ColorAttachmentWrite + }; + commandBuffer.PipelineBarrier(PipelineStageFlags.TopOfPipe, PipelineStageFlags.TopOfPipe, DependencyFlags.None, 0, null, 0, null, 1, &memoryBarrier); + + // Clear render target + var clearRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 0, 0, 1); + commandBuffer.ClearColorImage(backBuffers[currentBackBufferIndex], ImageLayout.TransferDestinationOptimal, new RawColor4(1, 0, 1, 1), 1, &clearRange); + + // Begin render pass + var renderPassBeginInfo = new RenderPassBeginInfo + { + StructureType = StructureType.RenderPassBeginInfo, + RenderPass = renderPass, + Framebuffer = framebuffers[currentBackBufferIndex], + RenderArea = new Rect2D(0, 0, (uint)form.ClientSize.Width, (uint)form.ClientSize.Height), + }; + commandBuffer.BeginRenderPass(ref renderPassBeginInfo, SubpassContents.Inline); + + // Bind pipeline + commandBuffer.BindPipeline(PipelineBindPoint.Graphics, pipeline); + + // Set viewport and scissor + var viewport = new Viewport(0, 0, form.ClientSize.Width, form.ClientSize.Height); + commandBuffer.SetViewport(0, 1, &viewport); + + var scissor = new Rect2D(0, 0, (uint)form.ClientSize.Width, (uint)form.ClientSize.Height); + commandBuffer.SetScissor(0, 1, &scissor); + + // Bind vertex buffer + var vertexBufferCopy = vertexBuffer; + ulong offset = 0; + commandBuffer.BindVertexBuffers(0, 1, &vertexBufferCopy, &offset); + + // Draw vertices + commandBuffer.Draw(3, 1, 0, 0); + + // End render pass + commandBuffer.EndRenderPass(); + + // Pre-present transition + memoryBarrier = new ImageMemoryBarrier + { + StructureType = StructureType.ImageMemoryBarrier, + Image = backBuffers[currentBackBufferIndex], + SubresourceRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 1, 0, 1), + OldLayout = ImageLayout.ColorAttachmentOptimal, + NewLayout = ImageLayout.PresentSource, + SourceAccessMask = AccessFlags.ColorAttachmentWrite, + DestinationAccessMask = AccessFlags.MemoryRead + }; + commandBuffer.PipelineBarrier(PipelineStageFlags.AllCommands, PipelineStageFlags.BottomOfPipe, DependencyFlags.None, 0, null, 0, null, 1, &memoryBarrier); + } + + private void SetImageLayout(Image image, ImageAspectFlags imageAspect, ImageLayout oldLayout, ImageLayout newLayout) + { + if (setupCommanBuffer == CommandBuffer.Null) + { + // Create command buffer + CommandBuffer setupCommandBuffer; + var allocateInfo = new CommandBufferAllocateInfo + { + StructureType = StructureType.CommandBufferAllocateInfo, + CommandPool = commandPool, + Level = CommandBufferLevel.Primary, + CommandBufferCount = 1, + }; + device.AllocateCommandBuffers(ref allocateInfo, &setupCommandBuffer); + setupCommanBuffer = setupCommandBuffer; + + // Begin command buffer + var inheritanceInfo = new CommandBufferInheritanceInfo { StructureType = StructureType.CommandBufferInheritanceInfo }; + var beginInfo = new CommandBufferBeginInfo + { + StructureType = StructureType.CommandBufferBeginInfo, + InheritanceInfo = new IntPtr(&inheritanceInfo) + }; + setupCommanBuffer.Begin(ref beginInfo); + } + + var imageMemoryBarrier = new ImageMemoryBarrier + { + StructureType = StructureType.ImageMemoryBarrier, + OldLayout = oldLayout, + NewLayout = newLayout, + Image = image, + SubresourceRange = new ImageSubresourceRange(imageAspect, 0, 1, 0, 1) + }; + + switch (newLayout) + { + case ImageLayout.TransferDestinationOptimal: + imageMemoryBarrier.DestinationAccessMask = AccessFlags.TransferRead; + break; + case ImageLayout.ColorAttachmentOptimal: + imageMemoryBarrier.DestinationAccessMask = AccessFlags.ColorAttachmentWrite; + break; + case ImageLayout.DepthStencilAttachmentOptimal: + imageMemoryBarrier.DestinationAccessMask = AccessFlags.DepthStencilAttachmentWrite; + break; + case ImageLayout.ShaderReadOnlyOptimal: + imageMemoryBarrier.DestinationAccessMask = AccessFlags.ShaderRead | AccessFlags.InputAttachmentRead; + break; + } + + var sourceStages = PipelineStageFlags.TopOfPipe; + var destinationStages = PipelineStageFlags.TopOfPipe; + + setupCommanBuffer.PipelineBarrier(sourceStages, destinationStages, DependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); + } + + public void Flush() + { + if (this.setupCommanBuffer == CommandBuffer.Null) + return; + + var setupCommanBuffer = this.setupCommanBuffer; + + this.setupCommanBuffer.End(); + + var submitInfo = new SubmitInfo + { + StructureType = StructureType.SubmitInfo, + CommandBufferCount = 1, + CommandBuffers = new IntPtr(&setupCommanBuffer) + }; + + queue.Submit(1, &submitInfo, Fence.Null); + + queue.WaitIdle(); + + device.FreeCommandBuffers(commandPool, 1, &setupCommanBuffer); + + this.setupCommanBuffer = CommandBuffer.Null; + } + + public void Dispose() + { + device.WaitIdle(); + + device.FreeMemory(vertexBufferMemory); + device.DestroyBuffer(vertexBuffer); + + foreach (var framebuffer in framebuffers) + device.DestroyFramebuffer(framebuffer); + + device.DestroyRenderPass(renderPass); + device.DestroyPipeline(pipeline); + device.DestroyPipelineLayout(pipelineLayout); + + var commandBufferCopy = commandBuffer; + device.FreeCommandBuffers(commandPool, 1, &commandBufferCopy); + device.DestroyCommandPool(commandPool); + + foreach (var backBufferView in backBufferViews) + device.DestroyImageView(backBufferView); + + device.DestroySwapchain(swapchain); + instance.DestroySurface(surface); + + device.Destroy(); + + if (debugReportCallback != DebugReportCallback.Null) + { + var destroyDebugReportCallbackName = Encoding.ASCII.GetBytes("vkDestroyDebugReportCallbackEXT"); + fixed (byte* destroyDebugReportCallbackNamePointer = &destroyDebugReportCallbackName[0]) + { + var destroyDebugReportCallback = Marshal.GetDelegateForFunctionPointer(instance.GetProcAddress(destroyDebugReportCallbackNamePointer)); + destroyDebugReportCallback(instance, debugReportCallback, null); + } + } + instance.Destroy(); + } + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] + private unsafe delegate RawBool DebugReportCallbackDelegate(DebugReportFlags flags, DebugReportObjectType objectType, ulong @object, PointerSize location, int messageCode, string layerPrefix, string message, IntPtr userData); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private unsafe delegate Result CreateDebugReportCallbackDelegate(Instance instance, ref DebugReportCallbackCreateInfo createInfo, AllocationCallbacks* allocator, out DebugReportCallback callback); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private unsafe delegate Result DestroyDebugReportCallbackDelegate(Instance instance, DebugReportCallback debugReportCallback, AllocationCallbacks* allocator); + + } +} \ No newline at end of file diff --git a/Samples/MiniTri/app.config b/Samples/MiniTri/app.config new file mode 100644 index 0000000..884f984 --- /dev/null +++ b/Samples/MiniTri/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Samples/MiniTri/frag.spv b/Samples/MiniTri/frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..f83e1db4bf9cff5d22200c69e380271ea4554831 GIT binary patch literal 568 zcmY+A-Acni5QWFKX{*)#SkODEcqx=3tq7u`g1PC1KMxSrHpFUeOA_yW1RvKM!SlsL zbi-u!oH;vlcFU!Mn%SDZx^?Ymb*v<8*05@p{qe)NpQO|Na5O;Cv~ngy)3TaXl!;e2 zTTob6Y%1E)!E1naWpy?C(4mSH{y4b2zY3CY7TSUR! zEuuFUg~9M>uyT_Z^VI3@Tu%(MZ( + + + + \ No newline at end of file diff --git a/Samples/MiniTri/vert.spv b/Samples/MiniTri/vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..95ce61fb3eec4c0fc249f6fe01d5eea669995afc GIT binary patch literal 1008 zcmY+C-Amk15XGmv?rPQgQNL=nn&P7%QdESZVl8Y73u=YFhPYnV)HPX>2>{3I4f# z5j?+ZZn1Zn%$zfmnR6%GY;260z0z;Y*6sPsT0__jAIVQx+v866qPtaAS6e%~+f+_j z6X$c&_S(lIdfp~!27sB6&B+#JP5m134{AQ5Y^NI^|M(J@ZkQBF<>K->xpGCEU;c8v zs{Fr3sWj`ygCy(UC4Cp~eA*r+y&G$()61DHG0Z*52YGRNS1I&0=F-V* zy4bMWsD$8!bA-ANMS?79#ImWf~!F+1R%=m1mysIL36Cv^EvH2?qr literal 0 HcmV?d00001 diff --git a/Samples/SharpVulkanSamples.sln b/Samples/SharpVulkanSamples.sln new file mode 100644 index 0000000..20ff805 --- /dev/null +++ b/Samples/SharpVulkanSamples.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniTri", "MiniTri\MiniTri.csproj", "{96426D44-3995-44F5-85C0-901027203313}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {96426D44-3995-44F5-85C0-901027203313}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96426D44-3995-44F5-85C0-901027203313}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96426D44-3995-44F5-85C0-901027203313}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96426D44-3995-44F5-85C0-901027203313}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Source/SharpVulkan/SharpVulkan.csproj b/Source/SharpVulkan/SharpVulkan.csproj index 24f4204..f383d5d 100644 --- a/Source/SharpVulkan/SharpVulkan.csproj +++ b/Source/SharpVulkan/SharpVulkan.csproj @@ -9,24 +9,24 @@ Properties SharpVulkan SharpVulkan - v4.5.2 + v4.5 512 + $(SolutionDir)\Bin\ + true full false - bin\Debug\ DEBUG;TRACE prompt 4 - x64 + AnyCPU true pdbonly true - bin\Release\ TRACE prompt 4