From: Jean-Philippe Bruyère Date: Thu, 19 Nov 2020 08:18:55 +0000 (+0100) Subject: save commit X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=refs%2Fpull%2F4%2Fhead;p=jp%2Fvke.net.git save commit --- diff --git a/.gitignore b/.gitignore index 8c08057..727a600 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vs +.vscode build/ packages/ datas diff --git a/clean.sh b/clean.sh index d39df8f..762ec80 100755 --- a/clean.sh +++ b/clean.sh @@ -1,2 +1,2 @@ #!/bin/bash -rm -fr build && find . -iname bin -o -iname obj | xargs rm -rf +rm -fr build && find . -iname bin -o -iname obj -o -iname build | xargs rm -rf diff --git a/samples/Circle/Circle.csproj b/samples/Circle/Circle.csproj new file mode 100644 index 0000000..1b81ff7 --- /dev/null +++ b/samples/Circle/Circle.csproj @@ -0,0 +1,5 @@ + + + false + + diff --git a/samples/Circle/README.md b/samples/Circle/README.md new file mode 100644 index 0000000..3f7f02d --- /dev/null +++ b/samples/Circle/README.md @@ -0,0 +1,60 @@ +### Creating buffers + +Vke has two classes to handle buffers. Mappable [`HostBuffer`](../../wiki/api/HostBuffer) and device only [`GPUBuffer`](../../wiki/api/GPUBuffer). +For this first simple example, we will only use host mappable buffers. Those classes can handle a Generic argument of a blittable type to handle arrays. Resources like buffers or images are activated in constructor, and they need to be explicitly disposed on cleanup. Create them in the `initVulkan` override. + +```csharp +//the vertex buffer +vbo = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vertices); +//the index buffer +ibo = new HostBuffer (dev, VkBufferUsageFlags.IndexBuffer, indices); +//a permanantly mapped buffer for the mvp matrice +uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, mvp, true); +``` + +To be able to access the mvp matrix in a shader, we need a descriptor. This implies to create a descriptor pool to allocate it from and configure the triangle pipeline layout with a corresponding descriptor layout for our matrix. +```csharp +descriptorPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer)); +``` +Graphic pipeline configuration are predefined by the [`GraphicPipelineConfig`](../../wiki/api/GraphicPipelineConfig) class, which ease sharing configs for several pipelines having lots in common. The pipeline layout will be automatically activated on pipeline creation, so that sharing layout among different pipelines will benefit from the reference counting to automatically dispose unused layout on pipeline clean up. It's the same for [`DescriptorSetLayout`](../../wiki/api/DescriptorSetLayout). +```csharp +GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault ( + VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); + +cfg.Layout = new PipelineLayout (dev, + new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding ( + 0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer))); +``` +Next we configure a default [`RenderPass`](../../wiki/api/RenderPass) with just a color attachment for the swap chain image, a default sub-pass is automatically created and the render pass activation will follow the pipeline life cycle and will be automatically disposed when no longer in use. +```csharp + cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, cfg.Samples); +``` +Configuration of vertex bindings and attributes +```csharp +cfg.AddVertexBinding (0); +cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, //position + VkFormat.R32g32b32Sfloat);//color +``` +shader are automatically compiled by [`SpirVTasks`](../../SpirVTasks/README.md) if added to the project. The resulting shaders are automatically embedded in the assembly. To specifiy that the shader path is a resource name, put the **'#'** prefix. Else the path will be search on disk. +```csharp +cfg.AddShader (VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"); +cfg.AddShader (VkShaderStageFlags.Fragment, "#shaders.main.frag.spv"); +``` +Once the pipeline configuration is complete, we use it to effectively create and activate a graphic pipeline. Activables used by the pipeline (like the RenderPass, or the PipelineLayout) are referenced in the newly created managed pipeline. So the Configuration object doesn't need cleanup. +```csharp + pipeline = new GraphicPipeline (cfg); +``` +Because descriptor layouts used for a pipeline are only activated on pipeline activation, descriptor sets must not be allocated before, except if the layout has been manually activated, but in this case, layouts will also need to be explicitly disposed. +```csharp + descriptorSet = descriptorPool.Allocate (pipeline.Layout.DescriptorSetLayouts[0]); +``` +The descriptor update is a two step operation. First we create a [`DescriptorSetWrites`](../../wiki/api/DescriptorSetWrites) object defining the layout(s), than we write the descriptor(s). +The `Descriptor` property of the mvp HostBuffer will return a default descriptor with no offset of the full size of the buffer. + +```csharp +DescriptorSetWrites uboUpdate = + new DescriptorSetWrites (descriptorSet, pipeline.Layout.DescriptorSetLayouts[0]); + +uboUpdate.Write (dev, uboMats.Descriptor); +``` diff --git a/samples/Circle/main.cs b/samples/Circle/main.cs new file mode 100644 index 0000000..d5cf15b --- /dev/null +++ b/samples/Circle/main.cs @@ -0,0 +1,234 @@ +using System.ComponentModel; +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Collections.Generic; +//using System.Text; +using vke; +using Vulkan; + +//the traditional triangle sample +namespace Triangle { + class Program : VkWindow { + static void Main (string[] args) { +#if NETCOREAPP + DllMapCore.Resolve.Enable (true); +#endif + using (Program vke = new Program ()) { + vke.Run (); + } + } + Program () : base ("triangle", 800, 600, false) { } + + const float rotSpeed = 0.01f, zoomSpeed = 0.01f; + float rotX, rotY, zoom = 1f; + + Matrix4x4 mvp; //the model view projection matrix + + GPUBuffer ibo; //a host mappable buffer to hold the indices. + GPUBuffer vbo; //a host mappable buffer to hold vertices. + HostBuffer uboMats; //a host mappable buffer for mvp matrice. + + DescriptorPool descriptorPool; + DescriptorSet descriptorSet;//descriptor set for the mvp matrice. + + FrameBuffers frameBuffers; //the frame buffer collection coupled to the swapchain images + GraphicPipeline pipeline; //the triangle rendering pipeline + + Vector3 center = new Vector3(0.0f,0.0f,0); + float radius = 2; + float step = 0.01f; + + List verts = new List(); + List indices = null; + + protected override void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures enabled_features) { + base.configureEnabledFeatures (available_features, ref enabled_features); + enabled_features.pipelineStatisticsQuery = true; + } + PipelineStatisticsQueryPool statPool; + TimestampQueryPool timestampQPool; + ulong[] results; + + protected override void initVulkan () { + base.initVulkan (); + + UpdateFrequency = 200; + + statPool = new PipelineStatisticsQueryPool (dev, + VkQueryPipelineStatisticFlags.InputAssemblyVertices | + VkQueryPipelineStatisticFlags.InputAssemblyPrimitives | + VkQueryPipelineStatisticFlags.ClippingInvocations | + VkQueryPipelineStatisticFlags.ClippingPrimitives | + VkQueryPipelineStatisticFlags.FragmentShaderInvocations); + + timestampQPool = new TimestampQueryPool (dev); + verts.Add (center); + for (float alpha = 0; alpha < System.MathF.PI *2f; alpha+=step) { + verts.Add (new Vector3(center.X + MathF.Cos(alpha) * radius, center.Y + MathF.Sin(alpha) * radius, 0)); + } + verts.Add (new Vector3(center.X + MathF.Cos(0) * radius, center.Y + MathF.Sin(0) * radius, 0)); + + /*indices = new List (); + for (UInt16 i = 1; i < (UInt16)verts.Count - 1; i++) + { + indices.Add (0); + indices.Add (i); + indices.Add ((UInt16)(i+1)); + }*/ + + + //first create the needed buffers + vbo = new GPUBuffer (presentQueue, cmdPool , VkBufferUsageFlags.VertexBuffer, verts.ToArray()); + if (indices != null) + ibo = new GPUBuffer (presentQueue, cmdPool, VkBufferUsageFlags.IndexBuffer, indices.ToArray()); + //because mvp matrice may be updated by mouse move, we keep it mapped after creation. + uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, mvp, true); + + //a descriptor pool to allocate the mvp matrice descriptor from. + descriptorPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer)); + + //Graphic pipeline configuration are predefined by the GraphicPipelineConfig class, which ease sharing config for several pipelines having lots in common. + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleFan, VkSampleCountFlags.SampleCount1, false); + + //Create the pipeline layout, it will be automatically activated on pipeline creation, so that sharing layout among different pipelines will benefit + //from the reference counting to automatically dispose unused layout on pipeline clean up. It's the same for DescriptorSetLayout. + cfg.Layout = new PipelineLayout (dev, + new DescriptorSetLayout (dev, new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer))); + //create a default renderpass with just a color attachment for the swapchain image, a default subpass is automatically created and the renderpass activation + //will follow the pipeline life cicle and will be automatically disposed when no longuer used. + cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, cfg.Samples); + //configuration of vertex bindings and attributes + cfg.AddVertexBinding (0); + cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat);//position + + //shader are automatically compiled by SpirVTasks if added to the project. The resulting shaders are automatically embedded in the assembly. + //To specifiy that the shader path is a resource name, put the '#' prefix. Else the path will be search on disk. + cfg.AddShaders ( + new ShaderInfo (dev, VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"), + new ShaderInfo (dev, VkShaderStageFlags.Fragment, "#shaders.main.frag.spv") + ); + + //create and activate the pipeline with the configuration we've just done. + pipeline = new GraphicPipeline (cfg); + + //ShaderInfo used in this configuration with create the VkShaderModule's used + //for creating the pipeline. They have to be disposed to destroy those modules + //used only during pipeline creation. + cfg.DisposeShaders (); + + //because descriptor layout used for a pipeline are only activated on pipeline activation, descriptor set must not be allocated before, except if the layout has been manually activated, + //but in this case, layout will need also to be explicitly disposed. + descriptorSet = descriptorPool.Allocate (pipeline.Layout.DescriptorSetLayouts[0]); + + //Write the content of the descriptor, the mvp matrice. + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descriptorSet, pipeline.Layout.DescriptorSetLayouts[0]); + //Descriptor property of the mvp buffer will return a default descriptor with no offset of the full size of the buffer. + uboUpdate.Write (dev, uboMats.Descriptor); + + //allocate the default VkWindow buffers, one per swapchain image. Their will be only reset when rebuilding and not reallocated. + cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount); + } + + //view update override, see base method for more informations. + public override void UpdateView () { + mvp = + Matrix4x4.CreateFromAxisAngle (Vector3.UnitY, rotY) * + Matrix4x4.CreateFromAxisAngle (Vector3.UnitX, rotX) * + Matrix4x4.CreateTranslation (0, 0, -5f * zoom) * + Utils.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (45f), (float)swapChain.Width / (float)swapChain.Height, 0.1f, 256.0f); + + uboMats.Update (mvp, (uint)Marshal.SizeOf ()); + base.UpdateView (); + } + protected override void onMouseMove (double xPos, double yPos) { + double diffX = lastMouseX - xPos; + double diffY = lastMouseY - yPos; + if (GetButton(Glfw.MouseButton.Left) == Glfw.InputAction.Press) { + rotY -= rotSpeed * (float)diffX; + rotX += rotSpeed * (float)diffY; + } else if (GetButton (Glfw.MouseButton.Right) == Glfw.InputAction.Press) { + zoom += zoomSpeed * (float)diffY; + } else + return; + //VkWindow has a boolean for requesting a call to 'UpdateView', it will be + //reset by the 'UpdateView' base method or the custom override. + updateViewRequested = true; + } + + void buildCommandBuffers() { + cmdPool.Reset (VkCommandPoolResetFlags.ReleaseResources); + + for (int i = 0; i < swapChain.ImageCount; ++i) { + FrameBuffer fb = frameBuffers[i]; + cmds[i].Start (); + + pipeline.RenderPass.Begin (cmds[i], fb); + + cmds[i].SetViewport (swapChain.Width, swapChain.Height); + cmds[i].SetScissor (swapChain.Width, swapChain.Height); + + cmds[i].BindDescriptorSet (pipeline.Layout, descriptorSet); + + cmds[i].BindPipeline (pipeline); + + cmds[i].BindVertexBuffer (vbo); + //cmds[i].BindIndexBuffer (ibo, VkIndexType.Uint16); + + statPool.Begin (cmds[i]); + for (int j = 0; j < 100; j++) + { + cmds[i].Draw((uint)verts.Count, 1); + //cmds[i].DrawIndexed ((uint)indices.Count); + } + statPool.End (cmds[i]); + + pipeline.RenderPass.End (cmds[i]); + + cmds[i].End (); + } + } + + protected override void OnResize () { + base.OnResize (); + UpdateView (); + + frameBuffers?.Dispose(); + frameBuffers = pipeline.RenderPass.CreateFrameBuffers(swapChain); + + buildCommandBuffers (); + } + //clean up + protected override void Dispose (bool disposing) { + dev.WaitIdle (); + if (disposing) { + if (!isDisposed) { + //pipeline clean up will dispose PipelineLayout, DescriptorSet layouts and render pass automatically. If their reference count is zero, their handles will be destroyed. + pipeline.Dispose (); + //frame buffers are automatically activated on creation as for resources, so it requests an explicit call to dispose. + frameBuffers?.Dispose(); + //the descriptor pool + descriptorPool.Dispose (); + //resources have to be explicityly disposed. + vbo.Dispose (); + ibo?.Dispose (); + uboMats.Dispose (); + } + } + + base.Dispose (disposing); + } + public override void Update () { + dev.WaitIdle (); + + results = statPool.GetResults (); + for (int i = 0; i < statPool.RequestedStats.Length; i++) { + Console.WriteLine ($"{statPool.RequestedStats[i].ToString(),-30} :{results[i],12:0,0} "); + } + Console.WriteLine(); + } + } +} diff --git a/samples/Circle/shaders/main.frag b/samples/Circle/shaders/main.frag new file mode 100644 index 0000000..5ff09f5 --- /dev/null +++ b/samples/Circle/shaders/main.frag @@ -0,0 +1,9 @@ +#include + +layout (location = 0) in vec3 inColor; +layout (location = 0) out vec4 outFragColor; + +void main() +{ + outFragColor = vec4(inColor, 1.0); +} \ No newline at end of file diff --git a/samples/Circle/shaders/main.vert b/samples/Circle/shaders/main.vert new file mode 100644 index 0000000..1199ac6 --- /dev/null +++ b/samples/Circle/shaders/main.vert @@ -0,0 +1,25 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 inPos; + +layout (binding = 0) uniform UBO +{ + mat4 mvp; +}; + +layout (location = 0) out vec3 outColor; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + + +void main() +{ + outColor = vec3(1,0,0); + gl_Position = mvp * vec4(inPos.xyz, 1.0); +} diff --git a/samples/ClearScreen/main.cs b/samples/ClearScreen/main.cs index c343e99..b7bf2cd 100644 --- a/samples/ClearScreen/main.cs +++ b/samples/ClearScreen/main.cs @@ -4,11 +4,17 @@ using vke; using Vulkan; + //Most simple example of the `VkWindow` class usage to output something on screen. namespace ClearScreen { class Program : VkWindow { + + //excutable entry point static void Main (string[] args) { +#if NETCOREAPP + DllMapCore.Resolve.Enable (true); +#endif //the base constructor will create the window with GLFW using (Program vke = new Program ()) { vke.Run (); diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index f90c8ce..8d91036 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -4,7 +4,7 @@ $(MSBuildThisFileDirectory)../ true - net472 + netcoreapp3.1 https://github.com/jpbruyere/vke.net MIT @@ -25,6 +25,7 @@ +