From: Jean-Philippe Bruyère Date: Sat, 11 Sep 2021 21:54:11 +0000 (+0000) Subject: tesselation support X-Git-Tag: v0.2.1-beta X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=a52659e351d35bf656737ddaeed93a03baf0e569;p=jp%2Fvke.net.git tesselation support --- diff --git a/Directory.Build.props b/Directory.Build.props index 2f2d567..12b32f3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,19 +4,19 @@ $(SolutionDir)build\$(Configuration)\ 0.1.44 $(SpirVTasksReleaseVersion) - 0.2.0 + 0.2.1 $(VkeReleaseVersion)-beta true false 7.2 - + $(DefineConstants);MEMORY_POOLS $(DefineConstants);STB_SHARP - + diff --git a/addons/Directory.Build.props b/addons/Directory.Build.props index f8470f0..b0ee5f7 100644 --- a/addons/Directory.Build.props +++ b/addons/Directory.Build.props @@ -4,7 +4,7 @@ $(MSBuildThisFileDirectory)../ true - netstandard2.0 + netstandard2.0 https://github.com/jpbruyere/vke.net MIT @@ -15,24 +15,24 @@ $(SolutionDir)build\$(Configuration)\ true false - + $(MSBuildThisFileDirectory)common\shaders - + $(SolutionDir)build\$(Configuration)\ - + - + - - - + + + diff --git a/addons/gltfLoader/PbrModel.cs b/addons/gltfLoader/PbrModel.cs index d5e04a8..0fc7fb5 100644 --- a/addons/gltfLoader/PbrModel.cs +++ b/addons/gltfLoader/PbrModel.cs @@ -17,6 +17,11 @@ namespace vke.glTF { public Buffer materialUBO; protected PbrModel () { } + /// + /// Load gltf file and load solids into vbo and ibo + /// + /// + /// public PbrModel (Queue transferQ, string path) { dev = transferQ.Dev; using (CommandPool cmdPool = new CommandPool (dev, transferQ.index)) { @@ -62,7 +67,7 @@ namespace vke.glTF { public void DrawAll (CommandBuffer cmd, PipelineLayout pipelineLayout, bool shadowPass = false) { foreach (Scene sc in Scenes) { foreach (Node node in sc.Root.Children) - RenderNode (cmd, pipelineLayout, node, sc.Root.localMatrix, shadowPass); + RenderNode (cmd, pipelineLayout, node, sc.Root.localMatrix, shadowPass); } } public void Draw(CommandBuffer cmd, PipelineLayout pipelineLayout, Scene scene, bool shadowPass = false) diff --git a/addons/gltfLoader/PbrModelTexArray.cs b/addons/gltfLoader/PbrModelTexArray.cs index a91e099..e743924 100644 --- a/addons/gltfLoader/PbrModelTexArray.cs +++ b/addons/gltfLoader/PbrModelTexArray.cs @@ -73,15 +73,15 @@ namespace vke.glTF { VkMemoryPropertyFlags.DeviceLocal, TEXTURE_DIM, TEXTURE_DIM, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal, Image.ComputeMipLevels (TEXTURE_DIM), 1); PrimaryCommandBuffer cmd = cmdPool.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); - texArray.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ShaderReadOnlyOptimal); - transferQ.EndSubmitAndWait (cmd, true); + texArray.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ShaderReadOnlyOptimal); + transferQ.EndSubmitAndWait (cmd, true); } texArray.CreateView (VkImageViewType.ImageView2DArray, VkImageAspectFlags.Color, texArray.CreateInfo.arrayLayers); texArray.CreateSampler (); texArray.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; texArray.SetName ("model texArray"); - + loadMaterials (ctx); materialUBO = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, materials); @@ -125,7 +125,7 @@ namespace vke.glTF { if (node.Mesh != null) { foreach (Primitive p in node.Mesh.Primitives) { - if (!shadowPass) + if (!shadowPass) cmd.PushConstant (pipelineLayout, VkShaderStageFlags.Fragment, (int)p.material, (uint)Marshal.SizeOf ()); cmd.DrawIndexed (p.indexCount, 1, p.indexBase, p.vertexBase, 0); } @@ -139,7 +139,7 @@ namespace vke.glTF { protected override void Dispose (bool disposing) { if (!isDisposed) { if (disposing) { - texArray?.Dispose (); + texArray?.Dispose (); } else Debug.WriteLine ("model was not disposed"); } diff --git a/addons/gltfLoader/glTFLoader.cs b/addons/gltfLoader/glTFLoader.cs index 5942dea..9d39f47 100644 --- a/addons/gltfLoader/glTFLoader.cs +++ b/addons/gltfLoader/glTFLoader.cs @@ -17,6 +17,7 @@ namespace vke.glTF { using static Vulkan.Utils; using static vke.Model; using System.Runtime.CompilerServices; + using System.Reflection; /// /// Loading context with I as the vertex index type (uint16,uint32) @@ -133,7 +134,7 @@ namespace vke.glTF { } public uint ImageCount => gltf.Images == null ? 0 : (uint)gltf.Images.Length; - + //TODO: some buffer data are reused between primitives, and I duplicate the datas //buffers must be constructed without duplications @@ -151,6 +152,9 @@ namespace vke.glTF { int vertexCount = 0, indexCount = 0; int autoNamedMesh = 1; + bool secondUv = typeof (TVertex).GetFields (). + Select (f => f.GetCustomAttribute ()).Where (va=>va.Type == VertexAttributeType.UVs).Count() > 1; + meshes = new List (); using (HostBuffer stagging = new HostBuffer (dev, VkBufferUsageFlags.TransferSrc, size)) { @@ -235,7 +239,8 @@ namespace vke.glTF { inUvPtr = inUvPtr.Slice (8); } if (inUv1Ptr != null) { - inUv1Ptr.Slice (0, 8).CopyTo (stagVertPtr.Slice (32)); + if (secondUv) + inUv1Ptr.Slice (0, 8).CopyTo (stagVertPtr.Slice (32)); inUv1Ptr = inUvPtr.Slice (8); } stagVertPtr = stagVertPtr.Slice (vertexByteSize); @@ -274,7 +279,7 @@ namespace vke.glTF { Span usPtr = MemoryMarshal.Cast (stagIdxPtr); Span inPtr = MemoryMarshal.Cast (inIdxPtr); - for (int i = 0; i < acc.Count; i++) + for (int i = 0; i < acc.Count; i++) usPtr[i] = (ushort)inPtr[i]; stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2); } @@ -337,8 +342,8 @@ namespace vke.glTF { return new Scene[] {}; List scenes = new List (); - defaultScene = (int)gltf.Scene; - + defaultScene = (int)gltf.Scene; + for (int i = 0; i < gltf.Scenes.Length; i++) { GL.Scene scene = gltf.Scenes[i]; Debug.WriteLine ("Loading Scene {0}", scene.Name); @@ -378,11 +383,11 @@ namespace vke.glTF { M[12],M[13],M[14],M[15]); } - if (gltfNode.Translation != null) + if (gltfNode.Translation != null) FromFloatArray (ref translation, gltfNode.Translation); - if (gltfNode.Translation != null) - FromFloatArray (ref rotation, gltfNode.Rotation); - if (gltfNode.Translation != null) + if (gltfNode.Translation != null) + FromFloatArray (ref rotation, gltfNode.Rotation); + if (gltfNode.Translation != null) FromFloatArray (ref scale, gltfNode.Scale); localTransform *= @@ -418,10 +423,10 @@ namespace vke.glTF { int texDim = (int)texArray.CreateInfo.extent.width; PrimaryCommandBuffer cmd = cmdPool.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); - texArray.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, + texArray.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.Transfer); transferQ.EndSubmitAndWait (cmd, true); - + VkImageBlit imageBlit = new VkImageBlit { srcSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1, 0), dstOffsets_1 = new VkOffset3D (texDim, texDim, 1) @@ -455,8 +460,8 @@ namespace vke.glTF { Vk.vkCmdBlitImage (cmd.Handle, vkimg.Handle, VkImageLayout.TransferSrcOptimal, texArray.Handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, VkFilter.Linear); - - transferQ.EndSubmitAndWait (cmd, true); + + transferQ.EndSubmitAndWait (cmd, true); vkimg.Dispose (); } diff --git a/clean.sh b/clean.sh deleted file mode 100755 index d39df8f..0000000 --- a/clean.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -rm -fr build && find . -iname bin -o -iname obj | xargs rm -rf diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index 994e2c6..c2598c2 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -4,7 +4,7 @@ $(MSBuildThisFileDirectory)../ true - netcoreapp3.1 + netcoreapp3.1 https://github.com/jpbruyere/vke.net MIT @@ -12,32 +12,32 @@ $(SolutionDir)build\$(Configuration)\ Exe - + false $(MSBuildThisFileDirectory)common\shaders - + $(SolutionDir)build\$(Configuration)\ - + - + - + shaders.%(Filename)%(Extension).spv - + ui.%(Filename)%(Extension) - + diff --git a/samples/Tesselation/README.md b/samples/Tesselation/README.md new file mode 100644 index 0000000..27f9eb3 --- /dev/null +++ b/samples/Tesselation/README.md @@ -0,0 +1,60 @@ +### Creating buffers + +Vke has two classes to handle buffers. Mappable [`HostBuffer`](../../../../wiki/vke.HostBuffer) and device only [`GPUBuffer`](../../../../wiki/vke.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/vke.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/vke.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 (dev, VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"); +cfg.AddShader (dev, 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/vke.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/Tesselation/Tesselation.csproj b/samples/Tesselation/Tesselation.csproj new file mode 100644 index 0000000..672fb5a --- /dev/null +++ b/samples/Tesselation/Tesselation.csproj @@ -0,0 +1,5 @@ + + + false + + diff --git a/samples/Tesselation/main.cs b/samples/Tesselation/main.cs new file mode 100644 index 0000000..6f95779 --- /dev/null +++ b/samples/Tesselation/main.cs @@ -0,0 +1,186 @@ +// 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 vke; +using Vulkan; +using Glfw; + +namespace Tesselation { + class Program : SampleBase { + static void Main (string[] args) { +#if DEBUG + Instance.VALIDATION = true; +#endif + using (Program vke = new Program ()) { + vke.Run (); + } + } + + const float rotSpeed = 0.01f, zoomSpeed = 0.01f; + float rotX, rotY, zoom = 1f; + + //vertex structure + [StructLayout(LayoutKind.Sequential)] + struct Vertex { + Vector3 position; + Vector3 color; + + public Vertex (float x, float y, float z, float r, float g, float b) { + position = new Vector3 (x, y, z); + color = new Vector3 (r, g, b); + } + } + + Matrix4x4 mvp; //the model view projection matrix + + HostBuffer ibo; //a host mappable buffer to hold the indices. + HostBuffer 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 + + //triangle vertices (position + color per vertex) and indices. + Vertex[] vertices = { + new Vertex (-1.0f, -1.0f, 0.0f , 1.0f, 0.0f, 0.0f), + new Vertex ( 1.0f, -1.0f, 0.0f , 0.0f, 1.0f, 0.0f), + new Vertex ( 0.0f, 1.0f, 0.0f , 0.0f, 0.0f, 1.0f), + }; + ushort[] indices = new ushort[] { 0, 1, 2 }; + + protected override void initVulkan () { + base.initVulkan (); + + //first create the needed buffers + vbo = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vertices); + ibo = new HostBuffer (dev, VkBufferUsageFlags.IndexBuffer, indices); + //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. + using (GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, 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, VkFormat.R32g32b32Sfloat);//position + color + + //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); + } + + //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, -3f * 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 (MouseButton.Left) == InputAction.Press) { + rotY -= rotSpeed * (float)diffX; + rotX += rotSpeed * (float)diffY; + updateViewRequested = true; + } else if (GetButton (MouseButton.Right) == InputAction.Press) { + zoom += zoomSpeed * (float)diffY; + 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); + cmds[i].DrawIndexed ((uint)indices.Length); + + 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); + } + } +} diff --git a/samples/Tesselation/shaders/main.frag b/samples/Tesselation/shaders/main.frag new file mode 100644 index 0000000..a3cafac --- /dev/null +++ b/samples/Tesselation/shaders/main.frag @@ -0,0 +1,12 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +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/Tesselation/shaders/main.vert b/samples/Tesselation/shaders/main.vert new file mode 100644 index 0000000..0997ca9 --- /dev/null +++ b/samples/Tesselation/shaders/main.vert @@ -0,0 +1,26 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inColor; + +layout (binding = 0) uniform UBO +{ + mat4 mvp; +}; + +layout (location = 0) out vec3 outColor; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + + +void main() +{ + outColor = inColor; + gl_Position = mvp * vec4(inPos.xyz, 1.0); +} diff --git a/samples/Triangle/Triangle.csproj b/samples/Triangle/Triangle.csproj index 1b81ff7..672fb5a 100644 --- a/samples/Triangle/Triangle.csproj +++ b/samples/Triangle/Triangle.csproj @@ -1,5 +1,5 @@ - - false - + + false + diff --git a/samples/Triangle/main.cs b/samples/Triangle/main.cs index 1d6e97d..d3804af 100644 --- a/samples/Triangle/main.cs +++ b/samples/Triangle/main.cs @@ -55,7 +55,7 @@ namespace Triangle { }; ushort[] indices = new ushort[] { 0, 1, 2 }; - protected override void initVulkan () { + protected override void initVulkan () { base.initVulkan (); //first create the needed buffers @@ -91,7 +91,7 @@ namespace Triangle { pipeline = new GraphicPipeline (cfg); } - //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, + //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]); @@ -164,7 +164,7 @@ namespace Triangle { buildCommandBuffers (); } //clean up - protected override void Dispose (bool disposing) { + protected override void Dispose (bool disposing) { dev.WaitIdle (); if (disposing) { if (!isDisposed) { diff --git a/samples/Triangle/shaders/main.frag b/samples/Triangle/shaders/main.frag index 5ff09f5..a3cafac 100644 --- a/samples/Triangle/shaders/main.frag +++ b/samples/Triangle/shaders/main.frag @@ -1,4 +1,7 @@ -#include +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable layout (location = 0) in vec3 inColor; layout (location = 0) out vec4 outFragColor; diff --git a/samples/deferred/DeferredPbrRenderer.cs b/samples/deferred/DeferredPbrRenderer.cs index 9a898a4..e1f394a 100644 --- a/samples/deferred/DeferredPbrRenderer.cs +++ b/samples/deferred/DeferredPbrRenderer.cs @@ -117,7 +117,7 @@ namespace deferred { new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 6), new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 5), new VkDescriptorPoolSize (VkDescriptorType.StorageImage, 4) - ); + ); uboMatrices = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices, true); uboLights = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, lights, true); @@ -216,14 +216,14 @@ namespace deferred { if (TEXTURE_ARRAY) { descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (7, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));//texture array - } else { + } else { descLayoutTextures = new DescriptorSetLayout (dev, new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler) - ); + ); } descLayoutGBuff = new DescriptorSetLayout (dev, @@ -277,7 +277,7 @@ namespace deferred { cfg.rasterizationState.cullMode = VkCullModeFlags.Front; //COMPOSE PIPELINE cfg.blendAttachments.Clear (); - cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); cfg.SubpassIndex = SP_COMPOSE; cfg.Layout = gBuffPipeline.Layout; cfg.depthStencilState.depthTestEnable = false; @@ -310,7 +310,7 @@ namespace deferred { matrices.prefilteredCubeMipLevels = envCube.prefilterCube.CreateInfo.mipLevels; DescriptorSetWrites dsMainWrite = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings.GetRange (0, 5).ToArray ()); - dsMainWrite.Write (dev, + dsMainWrite.Write (dev, uboMatrices.Descriptor, envCube.irradianceCube.Descriptor, envCube.prefilterCube.Descriptor, @@ -329,10 +329,10 @@ namespace deferred { model?.Dispose (); if (TEXTURE_ARRAY) { - PbrModelTexArray mod = new PbrModelTexArray (transferQ, path); + PbrModelTexArray mod = new PbrModelTexArray (transferQ, path); DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5], descLayoutMain.Bindings[7]); uboUpdate.Write (dev, mod.materialUBO.Descriptor, mod.texArray.Descriptor); - + model = mod; } else { model = new PbrModelSeparatedTextures (transferQ, path, @@ -468,7 +468,7 @@ namespace deferred { frameBuffer?.Dispose (); createGBuff (); - frameBuffer = new FrameBuffer (renderPass, width, height, new Image[] { + frameBuffer = new FrameBuffer (renderPass, width, height, 1, new Image[] { hdrImgResolved, null, gbColorRough, gbEmitMetal, gbN_AO, gbPos}); } diff --git a/vke.net.sln b/vke.net.sln index eebcb5d..c19d4ed 100644 --- a/vke.net.sln +++ b/vke.net.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30104.148 MinimumVisualStudioVersion = 10.0.40219.1 @@ -44,6 +44,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "deferred", "samples\deferre EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "pbr", "samples\pbr\pbr.csproj", "{7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tesselation", "samples\Tesselation\Tesselation.csproj", "{FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution BuildPackages|Any CPU = BuildPackages|Any CPU @@ -137,6 +139,14 @@ Global {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.Release|Any CPU.ActiveCfg = Release|Any CPU {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.Release|Any CPU.Build.0 = Release|Any CPU {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Release|Any CPU + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}.BuildPackages|Any CPU.ActiveCfg = Debug|Any CPU + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}.BuildPackages|Any CPU.Build.0 = Debug|Any CPU + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}.Release|Any CPU.Build.0 = Release|Any CPU + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -153,6 +163,7 @@ Global {8185163E-A67C-4C0E-8548-67E2A9F16309} = {16439374-B8DB-4643-8116-EB3358B49A12} {D9A41382-444E-44ED-B638-3D8F06F2FBC2} = {16439374-B8DB-4643-8116-EB3358B49A12} {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5} = {16439374-B8DB-4643-8116-EB3358B49A12} + {FCE58652-47B9-4A3C-90B0-3B2EE2C8042D} = {16439374-B8DB-4643-8116-EB3358B49A12} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1360F94D-CF3C-4121-A8D7-E227F41668F1} diff --git a/vke/src/Camera.cs b/vke/src/Camera.cs index d0da1d1..383e700 100644 --- a/vke/src/Camera.cs +++ b/vke/src/Camera.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Jean-Philippe Bruyère +// Copyright (c) 2019-2021 Jean-Philippe Bruyère // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System.Numerics; @@ -29,94 +29,146 @@ namespace vke { public float FarPlane => zFar; public CamType Type; - + public float AspectRatio { - get { return aspectRatio; } + get => aspectRatio; set { aspectRatio = value; - Update (); + update (); } } public float FieldOfView { - get { return fov; } + get => fov; set { fov = value; - Update (); + update (); } } - public Matrix4x4 Perspective { - get { return Matrix4x4.CreatePerspectiveFieldOfView (fov, aspectRatio, zNear, zFar); } - } public Camera (float fieldOfView, float aspectRatio, float nearPlane = 0.1f, float farPlane = 16f) { fov = fieldOfView; this.aspectRatio = aspectRatio; zNear = nearPlane; zFar = farPlane; - Update (); + Model = Matrix4x4.Identity; + update (); } - + /// + /// Rotate the camera by an angle given in radian for each axes. + /// + /// rotation around the x axis + /// rotation around the y axis + /// rotation around the z axis public void Rotate (float x, float y, float z = 0) { rotation.X += rotSpeed * x; rotation.Y += rotSpeed * y; rotation.Z += rotSpeed * z; - Update (); + update (); + } + public void Rotate (Vector3 angle) { + rotation += rotSpeed * angle; + update (); } public float Zoom { - get { return zoom; } + get => zoom; set { zoom = value; - Update (); + update (); } } + /// + /// Set the current rotation angle in radian around each axes + /// + /// current rotation around the x axis + /// current rotation around the y axis + /// current rotation around the z axis public void SetRotation (float x, float y, float z = 0) { rotation.X = x; rotation.Y = y; rotation.Z = z; - Update (); + update (); } + public void SetRotation (Vector3 newRotationVector) { + rotation = newRotationVector; + update (); + } + /// + /// Set the current position of the camera. + /// + /// position on the x axis + /// position on the y axis + /// position on the z axis public void SetPosition (float x, float y, float z = 0) { position.X = x; position.Y = y; position.Z = z; - Update (); + update (); + } + public void SetPosition (Vector3 newPosition) { + position = newPosition; + update (); } + /// + /// Move the camera by an amount given for each axis. + /// + /// displacement on the x axis + /// displacement on the y axis + /// displacement on the z axis public void Move (float x, float y, float z = 0) { position.X += moveSpeed * x; position.Y += moveSpeed * y; position.Z += moveSpeed * z; - Update (); + update (); + } + public void Move (Vector3 displacementVector) { + position += moveSpeed * displacementVector; + update (); } public void SetZoom (float factor) { zoom += zoomSpeed * factor; - Update (); + update (); } - + /// + /// The resulting projection matrix of the camera. + /// Manual update may be triggered by calling the 'Update' method. + /// public Matrix4x4 Projection { get; private set;} + /// + /// The resulting view matrix of the camera. + /// Manual update may be triggered by calling the 'Update' method. + /// public Matrix4x4 View { get; private set;} + /// + /// The model matrix. By default set to identity. It does not influence the + /// view and proj matrices, it's only a convenient store place for the model matrix + /// associated with this camera. + /// public Matrix4x4 Model { - get { return model; } + get => model; set { model = value; - Update (); - } + update (); + } } - - public Matrix4x4 SkyboxView { - get { - return + /// + /// compute the skybox view matrix for this camera using it's rotation angles. + /// + public Matrix4x4 SkyboxView => Matrix4x4.CreateFromAxisAngle (Vector3.UnitZ, rotation.Z) * Matrix4x4.CreateFromAxisAngle (Vector3.UnitY, rotation.Y) * Matrix4x4.CreateFromAxisAngle (Vector3.UnitX, rotation.X); - } - } - - public void Update () { + /// + /// Recompute the projection and the view matrices from the current parameters + /// of this camera (fov, near, far, position, rotation, aspectRatio). + /// After the call to this method, the projection and the view matrices will be + /// in sync with the parameters. It's automatically called after rotation, move, etc... + /// + void update () { Projection = Vulkan.Utils.CreatePerspectiveFieldOfView (fov, aspectRatio, zNear, zFar); - Matrix4x4 translation = Matrix4x4.CreateTranslation (position * zoom);// * new Vector3(1,1,-1)) ; + Matrix4x4 translation = Matrix4x4.CreateTranslation (position * zoom); if (Type == CamType.LookAt) { - View = + View = Matrix4x4.CreateFromAxisAngle (Vector3.UnitZ, rotation.Z) * Matrix4x4.CreateFromAxisAngle (Vector3.UnitY, rotation.Y) * Matrix4x4.CreateFromAxisAngle (Vector3.UnitX, rotation.X) * diff --git a/vke/src/ExtensionMethods.cs b/vke/src/ExtensionMethods.cs index 589ae2a..93c6800 100644 --- a/vke/src/ExtensionMethods.cs +++ b/vke/src/ExtensionMethods.cs @@ -89,7 +89,7 @@ namespace vke { ctx.Handles.Add (hnd); return hnd.AddrOfPinnedObject (); } - public static IntPtr Pin (this List obj, PinnedObjects ctx) { + public static IntPtr Pin (this IList obj, PinnedObjects ctx) { GCHandle hnd = GCHandle.Alloc (obj.ToArray (), GCHandleType.Pinned); ctx.Handles.Add (hnd); return hnd.AddrOfPinnedObject (); diff --git a/vke/src/VkWindow.cs b/vke/src/VkWindow.cs index 0c165e0..bd92295 100644 --- a/vke/src/VkWindow.cs +++ b/vke/src/VkWindow.cs @@ -18,17 +18,17 @@ namespace vke { public abstract class VkWindow : IDisposable { /** GLFW callback may return a custom pointer, this list makes the link between the GLFW window pointer and the - manage VkWindow instance. */ + manage VkWindow instance. */ static Dictionary windows = new Dictionary(); /** GLFW window native pointer. */ IntPtr hWin; /**Vulkan Surface */ protected VkSurfaceKHR hSurf; /**vke Instance encapsulating a VkInstance. */ - protected Instance instance; + protected Instance instance; /**vke Physical device associated with this window*/ protected PhysicalDevice phy; - /**vke logical device */ + /**vke logical device */ protected Device dev; protected PresentQueue presentQueue; protected SwapChain swapChain; @@ -47,7 +47,7 @@ namespace vke { /**Default camera initialized with a Field of view of 40° and and aspect ratio of 1. */ protected Camera camera = new Camera (Utils.DegreesToRadians (45f), 1f); - + public Modifier KeyModifiers = 0; IntPtr currentCursor; uint frameCount; @@ -323,7 +323,7 @@ namespace vke { /// - if the `updateViewRequested` field is set to 'true', call the `UpdateView` method. /// - frame counting and chrono. /// - if elapsed time reached `UpdateFrequency` value, the `Update` method is called and the elapsed time chrono is reseet. - /// - GLFW events are polled at the end of the loop. + /// - GLFW events are polled at the end of the loop. /// public virtual void Run () { initVulkan (); @@ -348,7 +348,7 @@ namespace vke { frameChrono.Stop (); totTime += frameChrono.ElapsedMilliseconds; fps = (uint)((double)frameCount / (double)totTime * 1000.0); - Glfw3.SetWindowTitle (hWin, "FPS: " + fps.ToString ()); + Glfw3.SetWindowTitle (hWin, "FPS: " + fps.ToString ()); if (totTime > 2000) { frameCount = 0; totTime = 0; diff --git a/vke/src/base/Activable.cs b/vke/src/base/Activable.cs index 2f7edf5..1c3d0be 100644 --- a/vke/src/base/Activable.cs +++ b/vke/src/base/Activable.cs @@ -50,6 +50,7 @@ namespace vke { /// Vulkan logical device this activable is bound to. /// [XmlIgnore] public Device Dev { get; private set; } + public PNextNode PNext; #region CTOR protected Activable (Device dev) { diff --git a/vke/src/base/Device.cs b/vke/src/base/Device.cs index fca29f2..293585d 100644 --- a/vke/src/base/Device.cs +++ b/vke/src/base/Device.cs @@ -20,7 +20,7 @@ namespace vke { public readonly PhysicalDevice phy; /**Vulkan physical device class*/ VkDevice dev; - public VkDevice VkDev => dev; /**Vulkan logical device handle*/ + public VkDevice VkDev => dev; /**Vulkan logical device handle*/ internal List queues = new List (); @@ -66,8 +66,8 @@ namespace vke { //enable only supported exceptions List deviceExtensions = new List (); for (int i = 0; i < extensions.Length; i++) { - if (phy.GetDeviceExtensionSupported (extensions[i])) - deviceExtensions.Add (new FixedUtf8String (extensions[i])); + if (phy.GetDeviceExtensionSupported (extensions[i])) + deviceExtensions.Add (new FixedUtf8String (extensions[i])); } VkDeviceCreateInfo deviceCreateInfo = VkDeviceCreateInfo.New (); @@ -158,7 +158,7 @@ namespace vke { // This function is used to request a Device memory type that supports all the property flags we request (e.g. Device local, host visibile) // Upon success it will return the index of the memory type that fits our requestes memory properties // This is necessary as implementations can offer an arbitrary number of memory types with different - // memory properties. + // memory properties. // You can check http://vulkan.gpuinfo.org/ for details on different memory configurations internal uint GetMemoryTypeIndex (uint typeBits, VkMemoryPropertyFlags properties) { // Iterate over all memory types available for the Device used in this example diff --git a/vke/src/base/FrameBuffer.cs b/vke/src/base/FrameBuffer.cs index a6220c5..f2bdd69 100644 --- a/vke/src/base/FrameBuffer.cs +++ b/vke/src/base/FrameBuffer.cs @@ -45,7 +45,18 @@ namespace vke { /// Array of image views. If null and not in unused state, attachment image and view will be automatically created from the /// supplied renderpass configuration. public FrameBuffer (RenderPass _renderPass, uint _width, uint _height, params Image[] views) - : this (_renderPass, _width, _height) { + : this (_renderPass, _width, _height, 1, views) {} + /// + /// Create and Activate a new frabuffer for the supplied RenderPass. + /// + /// Render pass. + /// Width. + /// Height. + /// layers count + /// Array of image views. If null and not in unused state, attachment image and view will be automatically created from the + /// supplied renderpass configuration. + public FrameBuffer (RenderPass _renderPass, uint _width, uint _height, uint layers, params Image[] views) + : this (_renderPass, _width, _height, layers) { for (int i = 0; i < views.Length; i++) { Image v = views[i]; if (v == null) { @@ -79,9 +90,15 @@ namespace vke { createInfo.attachmentCount = (uint)views.Length; createInfo.pAttachments = views.Pin (); + if (PNext != null) + createInfo.pNext = PNext.GetPointer(); + Utils.CheckResult (vkCreateFramebuffer (renderPass.Dev.VkDev, ref createInfo, IntPtr.Zero, out handle)); views.Unpin (); + if (PNext != null) + PNext.ReleasePointer (); + } base.Activate (); } diff --git a/vke/src/base/GraphicPipeline.cs b/vke/src/base/GraphicPipeline.cs index dafacab..bb9c3e1 100644 --- a/vke/src/base/GraphicPipeline.cs +++ b/vke/src/base/GraphicPipeline.cs @@ -42,9 +42,14 @@ namespace vke { RenderPass.Activate (); Cache?.Activate (); + bool enableTesselation = false; + List shaderStages = new List (); - foreach (ShaderInfo shader in cfg.Shaders) + foreach (ShaderInfo shader in cfg.Shaders) { + if (shader.Stage == VkShaderStageFlags.TessellationControl || shader.Stage == VkShaderStageFlags.TessellationEvaluation) + enableTesselation = true; shaderStages.Add (shader.Info); + } using (PinnedObjects pctx = new PinnedObjects ()) { @@ -98,6 +103,12 @@ namespace vke { info.pStages = shaderStages.Pin (pctx); info.subpass = cfg.SubpassIndex; + if (enableTesselation) { + VkPipelineTessellationStateCreateInfo tessellationInfo = VkPipelineTessellationStateCreateInfo.New(); + tessellationInfo.patchControlPoints = cfg.TessellationPatchControlPoints; + info.pTessellationState = tessellationInfo.Pin (pctx); + } + Utils.CheckResult (vkCreateGraphicsPipelines (Dev.VkDev, Cache == null ? VkPipelineCache.Null : Cache.handle, 1, ref info, IntPtr.Zero, out handle)); } } diff --git a/vke/src/base/GraphicPipelineConfig.cs b/vke/src/base/GraphicPipelineConfig.cs index b576e7c..1269f5c 100644 --- a/vke/src/base/GraphicPipelineConfig.cs +++ b/vke/src/base/GraphicPipelineConfig.cs @@ -37,24 +37,25 @@ namespace vke { public VkPipelineBindPoint bindPoint = VkPipelineBindPoint.Graphics; public VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = VkPipelineInputAssemblyStateCreateInfo.New (); public VkPipelineRasterizationStateCreateInfo rasterizationState = VkPipelineRasterizationStateCreateInfo.New (); - public List Viewports = new List (); - public List Scissors = new List (); + public IList Viewports = new List (); + public IList Scissors = new List (); public VkPipelineDepthStencilStateCreateInfo depthStencilState = VkPipelineDepthStencilStateCreateInfo.New (); public VkPipelineMultisampleStateCreateInfo multisampleState = VkPipelineMultisampleStateCreateInfo.New (); - public List blendAttachments = new List (); - public List dynamicStates = new List (); - public List vertexBindings = new List (); - public List vertexAttributes = new List (); + public IList blendAttachments = new List (); + public IList dynamicStates = new List (); + public IList vertexBindings = new List (); + public IList vertexAttributes = new List (); /// /// List of ShaderInfo's used to in this pipeline configuration. Those shaders have to be Disposed /// after pipeline creation from this configuration. The 'DisposeShaders' helper method with clear the list. /// To replace a single shader between two use of this configuration object to create two different pipelines, use /// the 'ReplaceShader' helper method to automatically dispose the replace shader. /// - public List Shaders = new List (); + public IList Shaders = new List (); public VkBool32 ColorBlendLogicOpEnable = false; public VkLogicOp ColorBlendLogicOp; public Vector4 ColorBlendConstants; + public uint TessellationPatchControlPoints = 0; public VkSampleCountFlags Samples { get { return multisampleState.rasterizationSamples; } @@ -144,19 +145,20 @@ namespace vke { AddVertexAttributes (binding, attribs); } /// - /// Add shaders to this pipeline configuration. + /// Add shaders to this pipeline configuration. /// public void AddShaders (params ShaderInfo[] shaderInfos) { - Shaders.AddRange (shaderInfos); + foreach (ShaderInfo si in shaderInfos) + Shaders.Add (si); } /// - /// Add a new shader to this pipeline configuration. + /// Add a new shader to this pipeline configuration. /// public void AddShader (VkShaderStageFlags stageFlags, VkShaderModule module, SpecializationInfo specializationInfo = null, string entryPoint = "main") { Shaders.Add (new ShaderInfo (stageFlags, module, specializationInfo, entryPoint)); } /// - /// Add a new shader to this pipeline configuration. + /// Add a new shader to this pipeline configuration. /// public void AddShader (Device dev, VkShaderStageFlags stageFlags, string spirvShaderPath, SpecializationInfo specializationInfo = null, string entryPoint = "main") { Shaders.Add (new ShaderInfo (dev, stageFlags, spirvShaderPath, specializationInfo, entryPoint)); diff --git a/vke/src/base/PNextNode.cs b/vke/src/base/PNextNode.cs new file mode 100644 index 0000000..9afd001 --- /dev/null +++ b/vke/src/base/PNextNode.cs @@ -0,0 +1,47 @@ +// 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.Reflection; + +namespace vke { + public abstract class PNextNode { + protected bool isPinned; + public abstract IntPtr GetPointer (); + public abstract void ReleasePointer (); + } + public class PNextNode : PNextNode { + protected T nodeStruct; + public PNextNode (T thisNodeStructure) { + nodeStruct = thisNodeStructure; + } + public override IntPtr GetPointer () { + isPinned = true; + return nodeStruct.Pin(); + } + public override void ReleasePointer () { + nodeStruct.Unpin (); + isPinned = false; + } + } + public class PNextNode : PNextNode { + PNextNode nextNodeStruct; + //T.pNext to store pinned reference of next struct + FieldInfo fiPnextFromNodeStruct; + public PNextNode (T thisNodeStruct, PNextNode nextStruct) : base (thisNodeStruct) { + nextNodeStruct = nextStruct; + fiPnextFromNodeStruct = typeof(T).GetField ("pNext"); + } + + public override IntPtr GetPointer() + { + fiPnextFromNodeStruct.SetValue (nodeStruct, nextNodeStruct.GetPointer ()); + return base.GetPointer(); + } + public override void ReleasePointer() + { + nextNodeStruct.ReleasePointer (); + base.ReleasePointer(); + } + } +} \ No newline at end of file diff --git a/vke/src/base/PhysicalDevice.cs b/vke/src/base/PhysicalDevice.cs index dee264e..91645b4 100644 --- a/vke/src/base/PhysicalDevice.cs +++ b/vke/src/base/PhysicalDevice.cs @@ -143,7 +143,7 @@ namespace vke { modes.Unpin (); VkPresentModeKHR[] mds = new VkPresentModeKHR[count]; for (int i = 0; i < count; i++) - mds[i] = (VkPresentModeKHR)modes[i]; + mds[i] = (VkPresentModeKHR)modes[i]; return mds; } else { VkPresentModeKHR[] modes = new VkPresentModeKHR[count];//enums not blittable on ms.Net diff --git a/vke/src/base/RenderPass.cs b/vke/src/base/RenderPass.cs index d632045..eed45fc 100644 --- a/vke/src/base/RenderPass.cs +++ b/vke/src/base/RenderPass.cs @@ -9,14 +9,14 @@ using Vulkan; using static Vulkan.Vk; namespace vke { - public class RenderPass : Activable { - internal VkRenderPass handle; + public class RenderPass : Activable { + internal VkRenderPass handle; public readonly VkSampleCountFlags Samples; - internal List attachments = new List (); - internal List subpasses = new List (); - List dependencies = new List (); + internal List attachments = new List (); + internal List subpasses = new List (); + List dependencies = new List (); public List ClearValues = new List (); public VkAttachmentDescription [] Attachments => attachments.ToArray (); public SubPass [] SubPasses => subpasses.ToArray (); @@ -41,7 +41,7 @@ namespace vke { AddAttachment (colorFormat, (samples == VkSampleCountFlags.SampleCount1) ? VkImageLayout.PresentSrcKHR : VkImageLayout.ColorAttachmentOptimal, samples, loadOp, VkAttachmentStoreOp.Store); - ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); SubPass subpass0 = new SubPass (); subpass0.AddColorReference (0, VkImageLayout.ColorAttachmentOptimal); @@ -52,29 +52,29 @@ namespace vke { subpass0.AddResolveReference (1, VkImageLayout.ColorAttachmentOptimal); } - AddSubpass (subpass0); + AddSubpass (subpass0); - AddDependency (Vk.SubpassExternal, 0, - VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, - VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentWrite); - AddDependency (0, Vk.SubpassExternal, - VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, - VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + AddDependency (Vk.SubpassExternal, 0, + VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, + VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentWrite); + AddDependency (0, Vk.SubpassExternal, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, + VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); } - /// - /// Create default renderpass with one color, one depth attachments, and a resolve one if needed. - /// - public RenderPass (Device device, VkFormat colorFormat, VkFormat depthFormat, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1) - : this (device){ + /// + /// Create default renderpass with one color, one depth attachments, and a resolve one if needed. + /// + public RenderPass (Device device, VkFormat colorFormat, VkFormat depthFormat, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1) + : this (device){ Samples = samples; AddAttachment (colorFormat, (samples == VkSampleCountFlags.SampleCount1) ? VkImageLayout.PresentSrcKHR : VkImageLayout.ColorAttachmentOptimal, samples); AddAttachment (depthFormat, VkImageLayout.DepthStencilAttachmentOptimal, samples); - ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); - ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) }); + ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) }); SubPass subpass0 = new SubPass (); @@ -87,15 +87,15 @@ namespace vke { subpass0.AddResolveReference (2, VkImageLayout.ColorAttachmentOptimal); } - AddSubpass (subpass0); + AddSubpass (subpass0); - AddDependency (Vk.SubpassExternal, 0, - VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, - VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); - AddDependency (0, Vk.SubpassExternal, - VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, - VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); - } + AddDependency (Vk.SubpassExternal, 0, + VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, + VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); + AddDependency (0, Vk.SubpassExternal, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, + VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + } #endregion public override void Activate () { @@ -111,54 +111,58 @@ namespace vke { renderPassInfo.pSubpasses = spDescs.Pin (); renderPassInfo.dependencyCount = (uint)dependencies.Count; renderPassInfo.pDependencies = dependencies.Pin (); + if (PNext != null) + renderPassInfo.pNext = PNext.GetPointer (); handle = Dev.CreateRenderPass (renderPassInfo); foreach (SubPass sp in subpasses) sp.UnpinLists (); + if (PNext != null) + PNext.ReleasePointer (); attachments.Unpin (); spDescs.Unpin (); dependencies.Unpin (); } base.Activate (); - } - - - public void AddAttachment (VkFormat format, - VkImageLayout finalLayout, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1, - VkAttachmentLoadOp loadOp = VkAttachmentLoadOp.Clear, - VkAttachmentStoreOp storeOp = VkAttachmentStoreOp.Store, - VkImageLayout initialLayout = VkImageLayout.Undefined) { - attachments.Add (new VkAttachmentDescription { - format = format, - samples = samples, - loadOp = loadOp, - storeOp = storeOp, - stencilLoadOp = VkAttachmentLoadOp.DontCare, - stencilStoreOp = VkAttachmentStoreOp.DontCare, - initialLayout = initialLayout, - finalLayout = finalLayout, - }); - } - public void AddAttachment (VkFormat format, VkImageLayout finalLayout, - VkAttachmentLoadOp stencilLoadOp, - VkAttachmentStoreOp stencilStoreOp, - VkAttachmentLoadOp loadOp = VkAttachmentLoadOp.DontCare, - VkAttachmentStoreOp storeOp = VkAttachmentStoreOp.DontCare, - VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1, - VkImageLayout initialLayout = VkImageLayout.Undefined) { - attachments.Add (new VkAttachmentDescription { - format = format, - samples = samples, - loadOp = loadOp, - storeOp = storeOp, - stencilLoadOp = stencilLoadOp, - stencilStoreOp = stencilStoreOp, - initialLayout = initialLayout, - finalLayout = finalLayout, - }); - } + } + + + public void AddAttachment (VkFormat format, + VkImageLayout finalLayout, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1, + VkAttachmentLoadOp loadOp = VkAttachmentLoadOp.Clear, + VkAttachmentStoreOp storeOp = VkAttachmentStoreOp.Store, + VkImageLayout initialLayout = VkImageLayout.Undefined) { + attachments.Add (new VkAttachmentDescription { + format = format, + samples = samples, + loadOp = loadOp, + storeOp = storeOp, + stencilLoadOp = VkAttachmentLoadOp.DontCare, + stencilStoreOp = VkAttachmentStoreOp.DontCare, + initialLayout = initialLayout, + finalLayout = finalLayout, + }); + } + public void AddAttachment (VkFormat format, VkImageLayout finalLayout, + VkAttachmentLoadOp stencilLoadOp, + VkAttachmentStoreOp stencilStoreOp, + VkAttachmentLoadOp loadOp = VkAttachmentLoadOp.DontCare, + VkAttachmentStoreOp storeOp = VkAttachmentStoreOp.DontCare, + VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1, + VkImageLayout initialLayout = VkImageLayout.Undefined) { + attachments.Add (new VkAttachmentDescription { + format = format, + samples = samples, + loadOp = loadOp, + storeOp = storeOp, + stencilLoadOp = stencilLoadOp, + stencilStoreOp = stencilStoreOp, + initialLayout = initialLayout, + finalLayout = finalLayout, + }); + } //public void AddDependency (SubPass srcSubpass, SubPass dstSubpass, // VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, // VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, @@ -169,57 +173,57 @@ namespace vke { //} public void AddDependency (uint srcSubpass, uint dstSubpass, - VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, - VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, - VkDependencyFlags dependencyFlags = VkDependencyFlags.ByRegion) { - dependencies.Add (new VkSubpassDependency { - srcSubpass = srcSubpass, - dstSubpass = dstSubpass, - srcStageMask = srcStageMask, - dstStageMask = dstStageMask, - srcAccessMask = srcAccessMask, - dstAccessMask = dstAccessMask, - dependencyFlags = dependencyFlags - }); - } - public void AddSubpass (params SubPass[] subPass) { + VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, + VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, + VkDependencyFlags dependencyFlags = VkDependencyFlags.ByRegion) { + dependencies.Add (new VkSubpassDependency { + srcSubpass = srcSubpass, + dstSubpass = dstSubpass, + srcStageMask = srcStageMask, + dstStageMask = dstStageMask, + srcAccessMask = srcAccessMask, + dstAccessMask = dstAccessMask, + dependencyFlags = dependencyFlags + }); + } + public void AddSubpass (params SubPass[] subPass) { for (uint i = 0; i < subPass.Length; i++) { subPass[i].Index = (uint)subpasses.Count + i; subpasses.Add (subPass[i]); } - } - /// - /// Begin Render pass with framebuffer extent dimensions - /// - public void Begin (PrimaryCommandBuffer cmd, FrameBuffer frameBuffer, VkSubpassContents contents = VkSubpassContents.Inline) { - Begin (cmd, frameBuffer, frameBuffer.Width, frameBuffer.Height, contents); - } - /// - /// Begin Render pass with custom render area - /// - public void Begin (PrimaryCommandBuffer cmd, FrameBuffer frameBuffer, uint width, uint height, VkSubpassContents contents = VkSubpassContents.Inline) { - - VkRenderPassBeginInfo info = VkRenderPassBeginInfo.New(); - info.renderPass = handle; - info.renderArea.extent.width = width; - info.renderArea.extent.height = height; - info.clearValueCount = (uint)ClearValues.Count; - info.pClearValues = ClearValues.Pin (); - info.framebuffer = frameBuffer.handle; + } + /// + /// Begin Render pass with framebuffer extent dimensions + /// + public void Begin (PrimaryCommandBuffer cmd, FrameBuffer frameBuffer, VkSubpassContents contents = VkSubpassContents.Inline) { + Begin (cmd, frameBuffer, frameBuffer.Width, frameBuffer.Height, contents); + } + /// + /// Begin Render pass with custom render area + /// + public void Begin (PrimaryCommandBuffer cmd, FrameBuffer frameBuffer, uint width, uint height, VkSubpassContents contents = VkSubpassContents.Inline) { + + VkRenderPassBeginInfo info = VkRenderPassBeginInfo.New(); + info.renderPass = handle; + info.renderArea.extent.width = width; + info.renderArea.extent.height = height; + info.clearValueCount = (uint)ClearValues.Count; + info.pClearValues = ClearValues.Pin (); + info.framebuffer = frameBuffer.handle; vkCmdBeginRenderPass (cmd.Handle, ref info, contents); ClearValues.Unpin (); - } + } /// /// Switch to next subpass /// public void BeginSubPass (PrimaryCommandBuffer cmd, VkSubpassContents subpassContents = VkSubpassContents.Inline) { vkCmdNextSubpass (cmd.Handle, subpassContents); } - public void End (PrimaryCommandBuffer cmd) { - vkCmdEndRenderPass (cmd.Handle); - } + public void End (PrimaryCommandBuffer cmd) { + vkCmdEndRenderPass (cmd.Handle); + } /// /// Create one framebuffer per swapchain images. The presentable attachment of this renderpass is found searching for its final layout that could be PresentSrcKHR or SharedPresentKHR. /// @@ -246,7 +250,7 @@ namespace vke { public override string ToString () { return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString("x")}]"); } - + #region IDisposable Support protected override void Dispose (bool disposing) { if (state == ActivableState.Activated) { diff --git a/vke/src/model/Model.cs b/vke/src/model/Model.cs index c94ae47..1ad79c5 100644 --- a/vke/src/model/Model.cs +++ b/vke/src/model/Model.cs @@ -61,13 +61,13 @@ namespace vke { max = _max; } } - + public class InstancedCmd { public int meshIdx; public uint count; } - + public class Primitive { public string name; public uint indexBase; @@ -149,7 +149,7 @@ namespace vke { aabb = Mesh.bb.getAABB (curTransform); if (Children != null) { - for (int i = 0; i < Children.Count; i++) + for (int i = 0; i < Children.Count; i++) aabb += Children[i].GetAABB (curTransform); } return aabb; @@ -178,6 +178,6 @@ namespace vke { return null; } - + } } diff --git a/vke/vke.csproj b/vke/vke.csproj index fb73c03..19434e5 100644 --- a/vke/vke.csproj +++ b/vke/vke.csproj @@ -2,47 +2,46 @@ netstandard2.0 - + $(VkeReleaseVersion) - + $(VkeReleaseVersion) - C# vulkan library with IDispose model and references counting + C# vulkan library with IDispose model and references counting https://github.com/jpbruyere/vke.net vulkan game engine compute glfw c# $(VkePackageVersion) - + True true - + False https://github.com/jpbruyere/vke.net/blob/master/README.md MIT icon.png MIT Jean-Philippe Bruyère - + false - + $(SolutionDir)build\$(Configuration)\ $(SolutionDir)build\$(Configuration)\ - + true - - false - 7.2 - true - $(NoWarn);1591 - + + false + true + $(NoWarn);1591 + $(SolutionDir)build\$(Configuration)\ - + - + - + @@ -53,7 +52,7 @@ - +