<RestoreAdditionalProjectSources Condition="Exists('$(SolutionDir)build\$(Configuration)\')">$(SolutionDir)build\$(Configuration)\</RestoreAdditionalProjectSources>
<SpirVTasksReleaseVersion>0.1.44</SpirVTasksReleaseVersion>
<SpirVTasksPackageVersion>$(SpirVTasksReleaseVersion)</SpirVTasksPackageVersion>
- <VkeReleaseVersion>0.2.0</VkeReleaseVersion>
+ <VkeReleaseVersion>0.2.1</VkeReleaseVersion>
<VkePackageVersion>$(VkeReleaseVersion)-beta</VkePackageVersion>
<UseStbSharp>true</UseStbSharp>
<UseMemoryPools>false</UseMemoryPools>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
-
+
<PropertyGroup Condition=" '$(UseMemoryPools)' == 'true'">
<DefineConstants>$(DefineConstants);MEMORY_POOLS</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(UseStbSharp)' == 'true'">
<DefineConstants>$(DefineConstants);STB_SHARP</DefineConstants>
</PropertyGroup>
-
+
</Project>
<RootDirectory>$(MSBuildThisFileDirectory)../</RootDirectory>
<Deterministic>true</Deterministic>
- <TargetFrameworks>netstandard2.0</TargetFrameworks>
+ <TargetFrameworks>netstandard2.0</TargetFrameworks>
<RepositoryUrl>https://github.com/jpbruyere/vke.net</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IncludeDefaultNoneItems>false</IncludeDefaultNoneItems>
-
+
<SpirVAdditionalIncludeDirectories>$(MSBuildThisFileDirectory)common\shaders</SpirVAdditionalIncludeDirectories>
-
+
<RestoreAdditionalProjectSources Condition="Exists('$(SolutionDir)build\$(Configuration)\')">$(SolutionDir)build\$(Configuration)\</RestoreAdditionalProjectSources>
</PropertyGroup>
-
+
<ItemGroup Condition=" '$(Configuration)|$(Platform)' != 'BuildPackages|AnyCPU' ">
<ProjectReference Include="..\..\vke\vke.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'BuildPackages|AnyCPU' ">
<PackageReference Include="vke" Version="$(VkePackageVersion)" />
</ItemGroup>
-
+
<ItemGroup>
<PackageReference Include="SpirVTasks" Version="$(SpirVTasksPackageVersion)" />
- <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
- </ItemGroup>
-
+ <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
+ </ItemGroup>
+
<ItemGroup>
<GLSLShader Include="shaders\**\*.frag;shaders\**\*.vert;shaders\**\*.comp;shaders\**\*.geom" />
</ItemGroup>
public Buffer materialUBO;
protected PbrModel () { }
+ /// <summary>
+ /// Load gltf file and load solids into vbo and ibo
+ /// </summary>
+ /// <param name="transferQ"></param>
+ /// <param name="path"></param>
public PbrModel (Queue transferQ, string path) {
dev = transferQ.Dev;
using (CommandPool cmdPool = new CommandPool (dev, transferQ.index)) {
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)
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<Material> (dev, VkBufferUsageFlags.UniformBuffer, materials);
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<Matrix4x4> ());
cmd.DrawIndexed (p.indexCount, 1, p.indexBase, p.vertexBase, 0);
}
protected override void Dispose (bool disposing) {
if (!isDisposed) {
if (disposing) {
- texArray?.Dispose ();
+ texArray?.Dispose ();
} else
Debug.WriteLine ("model was not disposed");
}
using static Vulkan.Utils;
using static vke.Model;
using System.Runtime.CompilerServices;
+ using System.Reflection;
/// <summary>
/// Loading context with I as the vertex index type (uint16,uint32)
}
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
int vertexCount = 0, indexCount = 0;
int autoNamedMesh = 1;
+ bool secondUv = typeof (TVertex).GetFields ().
+ Select<FieldInfo, VertexAttributeAttribute> (f => f.GetCustomAttribute<VertexAttributeAttribute> ()).Where (va=>va.Type == VertexAttributeType.UVs).Count() > 1;
+
meshes = new List<Mesh> ();
using (HostBuffer stagging = new HostBuffer (dev, VkBufferUsageFlags.TransferSrc, size)) {
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);
Span<ushort> usPtr = MemoryMarshal.Cast<byte, ushort> (stagIdxPtr);
Span<uint> inPtr = MemoryMarshal.Cast<byte, uint> (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);
}
return new Scene[] {};
List<Scene> scenes = new List<Scene> ();
- 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);
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 *=
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)
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 ();
}
+++ /dev/null
-#!/bin/bash
-rm -fr build && find . -iname bin -o -iname obj | xargs rm -rf
<RootDirectory>$(MSBuildThisFileDirectory)../</RootDirectory>
<Deterministic>true</Deterministic>
- <TargetFrameworks>netcoreapp3.1</TargetFrameworks>
+ <TargetFrameworks>netcoreapp3.1</TargetFrameworks>
<RepositoryUrl>https://github.com/jpbruyere/vke.net</RepositoryUrl>
<License>MIT</License>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<OutputType>Exe</OutputType>
-
+
<IncludeDefaultNoneItems>false</IncludeDefaultNoneItems>
<SpirVAdditionalIncludeDirectories>$(MSBuildThisFileDirectory)common\shaders</SpirVAdditionalIncludeDirectories>
-
+
<RestoreAdditionalProjectSources Condition="Exists('$(SolutionDir)build\$(Configuration)\')">$(SolutionDir)build\$(Configuration)\</RestoreAdditionalProjectSources>
</PropertyGroup>
-
+
<ItemGroup Condition=" '$(Configuration)|$(Platform)' != 'BuildPackages|AnyCPU' ">
<ProjectReference Include="..\..\vke\vke.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'BuildPackages|AnyCPU' ">
<PackageReference Include="vke" Version="$(VkePackageVersion)" />
</ItemGroup>
-
+
<ItemGroup>
<PackageReference Include="SpirVTasks" Version="$(SpirVTasksPackageVersion)" />
- </ItemGroup>
+ </ItemGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)common\Utils.cs;$(MSBuildThisFileDirectory)common\SampleBase.cs"/>
<GLSLShader Include="shaders\**\*.frag;shaders\**\*.vert;shaders\**\*.comp;shaders\**\*.geom">
<LogicalName>shaders.%(Filename)%(Extension).spv</LogicalName>
- </GLSLShader>
+ </GLSLShader>
<EmbeddedResource Include="ui\**\*.*">
<LogicalName>ui.%(Filename)%(Extension)</LogicalName>
</EmbeddedResource>
- </ItemGroup>
+ </ItemGroup>
</Project>
--- /dev/null
+### 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<Vertex> (dev, VkBufferUsageFlags.VertexBuffer, vertices);
+//the index buffer
+ibo = new HostBuffer<ushort> (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<Vertex> (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);
+```
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <IncludeDefaultNoneItems>false</IncludeDefaultNoneItems>
+ </PropertyGroup>
+</Project>
--- /dev/null
+// Copyright (c) 2019 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.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<Vertex> (dev, VkBufferUsageFlags.VertexBuffer, vertices);
+ ibo = new HostBuffer<ushort> (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<Vertex> (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<Matrix4x4> ());
+ 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);
+ }
+ }
+}
--- /dev/null
+#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
--- /dev/null
+#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);
+}
<Project Sdk="Microsoft.NET.Sdk">
- <PropertyGroup>
- <IncludeDefaultNoneItems>false</IncludeDefaultNoneItems>
- </PropertyGroup>
+ <PropertyGroup>
+ <IncludeDefaultNoneItems>false</IncludeDefaultNoneItems>
+ </PropertyGroup>
</Project>
};
ushort[] indices = new ushort[] { 0, 1, 2 };
- protected override void initVulkan () {
+ protected override void initVulkan () {
base.initVulkan ();
//first create the needed buffers
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]);
buildCommandBuffers ();
}
//clean up
- protected override void Dispose (bool disposing) {
+ protected override void Dispose (bool disposing) {
dev.WaitIdle ();
if (disposing) {
if (!isDisposed) {
-#include <preamble.inc>
+#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;
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<Light> (dev, VkBufferUsageFlags.UniformBuffer, lights, true);
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,
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;
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,
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,
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});
}
-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
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
{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
{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}
-// Copyright (c) 2019 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+// Copyright (c) 2019-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System.Numerics;
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 ();
}
-
+ /// <summary>
+ /// Rotate the camera by an angle given in radian for each axes.
+ /// </summary>
+ /// <param name="x">rotation around the x axis</param>
+ /// <param name="y">rotation around the y axis</param>
+ /// <param name="z">rotation around the z axis</param>
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 ();
}
}
+ /// <summary>
+ /// Set the current rotation angle in radian around each axes
+ /// </summary>
+ /// <param name="x">current rotation around the x axis</param>
+ /// <param name="y">current rotation around the y axis</param>
+ /// <param name="z">current rotation around the z axis</param>
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 ();
+ }
+ /// <summary>
+ /// Set the current position of the camera.
+ /// </summary>
+ /// <param name="x">position on the x axis</param>
+ /// <param name="y">position on the y axis</param>
+ /// <param name="z">position on the z axis</param>
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 ();
}
+ /// <summary>
+ /// Move the camera by an amount given for each axis.
+ /// </summary>
+ /// <param name="x">displacement on the x axis</param>
+ /// <param name="y">displacement on the y axis</param>
+ /// <param name="z">displacement on the z axis</param>
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 ();
}
-
+ /// <summary>
+ /// The resulting projection matrix of the camera.
+ /// Manual update may be triggered by calling the 'Update' method.
+ /// </summary>
public Matrix4x4 Projection { get; private set;}
+ /// <summary>
+ /// The resulting view matrix of the camera.
+ /// Manual update may be triggered by calling the 'Update' method.
+ /// </summary>
public Matrix4x4 View { get; private set;}
+ /// <summary>
+ /// 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.
+ /// </summary>
public Matrix4x4 Model {
- get { return model; }
+ get => model;
set {
model = value;
- Update ();
- }
+ update ();
+ }
}
-
- public Matrix4x4 SkyboxView {
- get {
- return
+ /// <summary>
+ /// compute the skybox view matrix for this camera using it's rotation angles.
+ /// </summary>
+ public Matrix4x4 SkyboxView =>
Matrix4x4.CreateFromAxisAngle (Vector3.UnitZ, rotation.Z) *
Matrix4x4.CreateFromAxisAngle (Vector3.UnitY, rotation.Y) *
Matrix4x4.CreateFromAxisAngle (Vector3.UnitX, rotation.X);
- }
- }
-
- public void Update () {
+ /// <summary>
+ /// 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...
+ /// </summary>
+ 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) *
ctx.Handles.Add (hnd);
return hnd.AddrOfPinnedObject ();
}
- public static IntPtr Pin<T> (this List<T> obj, PinnedObjects ctx) {
+ public static IntPtr Pin<T> (this IList<T> obj, PinnedObjects ctx) {
GCHandle hnd = GCHandle.Alloc (obj.ToArray (), GCHandleType.Pinned);
ctx.Handles.Add (hnd);
return hnd.AddrOfPinnedObject ();
public 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<IntPtr,VkWindow> windows = new Dictionary<IntPtr, VkWindow>();
/** 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;
/**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;
/// - 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.
/// </summary>
public virtual void Run () {
initVulkan ();
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;
/// Vulkan logical device this activable is bound to.
/// </summary>
[XmlIgnore] public Device Dev { get; private set; }
+ public PNextNode PNext;
#region CTOR
protected Activable (Device dev) {
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<Queue> queues = new List<Queue> ();
//enable only supported exceptions
List<IntPtr> deviceExtensions = new List<IntPtr> ();
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 ();
// 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
/// <param name="views">Array of image views. If null and not in unused state, attachment image and view will be automatically created from the
/// supplied renderpass configuration.</param>
public FrameBuffer (RenderPass _renderPass, uint _width, uint _height, params Image[] views)
- : this (_renderPass, _width, _height) {
+ : this (_renderPass, _width, _height, 1, views) {}
+ /// <summary>
+ /// Create and Activate a new frabuffer for the supplied RenderPass.
+ /// </summary>
+ /// <param name="_renderPass">Render pass.</param>
+ /// <param name="_width">Width.</param>
+ /// <param name="_height">Height.</param>
+ /// <param name="layers">layers count</param>
+ /// <param name="views">Array of image views. If null and not in unused state, attachment image and view will be automatically created from the
+ /// supplied renderpass configuration.</param>
+ 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) {
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 ();
}
RenderPass.Activate ();
Cache?.Activate ();
+ bool enableTesselation = false;
+
List<VkPipelineShaderStageCreateInfo> shaderStages = new List<VkPipelineShaderStageCreateInfo> ();
- 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 ()) {
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));
}
}
public VkPipelineBindPoint bindPoint = VkPipelineBindPoint.Graphics;
public VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = VkPipelineInputAssemblyStateCreateInfo.New ();
public VkPipelineRasterizationStateCreateInfo rasterizationState = VkPipelineRasterizationStateCreateInfo.New ();
- public List<VkViewport> Viewports = new List<VkViewport> ();
- public List<VkRect2D> Scissors = new List<VkRect2D> ();
+ public IList<VkViewport> Viewports = new List<VkViewport> ();
+ public IList<VkRect2D> Scissors = new List<VkRect2D> ();
public VkPipelineDepthStencilStateCreateInfo depthStencilState = VkPipelineDepthStencilStateCreateInfo.New ();
public VkPipelineMultisampleStateCreateInfo multisampleState = VkPipelineMultisampleStateCreateInfo.New ();
- public List<VkPipelineColorBlendAttachmentState> blendAttachments = new List<VkPipelineColorBlendAttachmentState> ();
- public List<VkDynamicState> dynamicStates = new List<VkDynamicState> ();
- public List<VkVertexInputBindingDescription> vertexBindings = new List<VkVertexInputBindingDescription> ();
- public List<VkVertexInputAttributeDescription> vertexAttributes = new List<VkVertexInputAttributeDescription> ();
+ public IList<VkPipelineColorBlendAttachmentState> blendAttachments = new List<VkPipelineColorBlendAttachmentState> ();
+ public IList<VkDynamicState> dynamicStates = new List<VkDynamicState> ();
+ public IList<VkVertexInputBindingDescription> vertexBindings = new List<VkVertexInputBindingDescription> ();
+ public IList<VkVertexInputAttributeDescription> vertexAttributes = new List<VkVertexInputAttributeDescription> ();
/// <summary>
/// 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.
/// </summary>
- public List<ShaderInfo> Shaders = new List<ShaderInfo> ();
+ public IList<ShaderInfo> Shaders = new List<ShaderInfo> ();
public VkBool32 ColorBlendLogicOpEnable = false;
public VkLogicOp ColorBlendLogicOp;
public Vector4 ColorBlendConstants;
+ public uint TessellationPatchControlPoints = 0;
public VkSampleCountFlags Samples {
get { return multisampleState.rasterizationSamples; }
AddVertexAttributes (binding, attribs);
}
/// <summary>
- /// Add shaders to this pipeline configuration.
+ /// Add shaders to this pipeline configuration.
/// </summary>
public void AddShaders (params ShaderInfo[] shaderInfos) {
- Shaders.AddRange (shaderInfos);
+ foreach (ShaderInfo si in shaderInfos)
+ Shaders.Add (si);
}
/// <summary>
- /// Add a new shader to this pipeline configuration.
+ /// Add a new shader to this pipeline configuration.
/// </summary>
public void AddShader (VkShaderStageFlags stageFlags, VkShaderModule module, SpecializationInfo specializationInfo = null, string entryPoint = "main") {
Shaders.Add (new ShaderInfo (stageFlags, module, specializationInfo, entryPoint));
}
/// <summary>
- /// Add a new shader to this pipeline configuration.
+ /// Add a new shader to this pipeline configuration.
/// </summary>
public void AddShader (Device dev, VkShaderStageFlags stageFlags, string spirvShaderPath, SpecializationInfo specializationInfo = null, string entryPoint = "main") {
Shaders.Add (new ShaderInfo (dev, stageFlags, spirvShaderPath, specializationInfo, entryPoint));
--- /dev/null
+// Copyright (c) 2019 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Reflection;
+
+namespace vke {
+ public abstract class PNextNode {
+ protected bool isPinned;
+ public abstract IntPtr GetPointer ();
+ public abstract void ReleasePointer ();
+ }
+ public class PNextNode<T> : 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<T,U> : PNextNode<T> {
+ PNextNode<U> nextNodeStruct;
+ //T.pNext to store pinned reference of next struct
+ FieldInfo fiPnextFromNodeStruct;
+ public PNextNode (T thisNodeStruct, PNextNode<U> 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
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
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<VkAttachmentDescription> attachments = new List<VkAttachmentDescription> ();
- internal List<SubPass> subpasses = new List<SubPass> ();
- List<VkSubpassDependency> dependencies = new List<VkSubpassDependency> ();
+ internal List<VkAttachmentDescription> attachments = new List<VkAttachmentDescription> ();
+ internal List<SubPass> subpasses = new List<SubPass> ();
+ List<VkSubpassDependency> dependencies = new List<VkSubpassDependency> ();
public List<VkClearValue> ClearValues = new List<VkClearValue> ();
public VkAttachmentDescription [] Attachments => attachments.ToArray ();
public SubPass [] SubPasses => subpasses.ToArray ();
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);
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);
}
- /// <summary>
- /// Create default renderpass with one color, one depth attachments, and a resolve one if needed.
- /// </summary>
- public RenderPass (Device device, VkFormat colorFormat, VkFormat depthFormat, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1)
- : this (device){
+ /// <summary>
+ /// Create default renderpass with one color, one depth attachments, and a resolve one if needed.
+ /// </summary>
+ 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 ();
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 () {
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,
//}
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]);
}
- }
- /// <summary>
- /// Begin Render pass with framebuffer extent dimensions
- /// </summary>
- public void Begin (PrimaryCommandBuffer cmd, FrameBuffer frameBuffer, VkSubpassContents contents = VkSubpassContents.Inline) {
- Begin (cmd, frameBuffer, frameBuffer.Width, frameBuffer.Height, contents);
- }
- /// <summary>
- /// Begin Render pass with custom render area
- /// </summary>
- 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;
+ }
+ /// <summary>
+ /// Begin Render pass with framebuffer extent dimensions
+ /// </summary>
+ public void Begin (PrimaryCommandBuffer cmd, FrameBuffer frameBuffer, VkSubpassContents contents = VkSubpassContents.Inline) {
+ Begin (cmd, frameBuffer, frameBuffer.Width, frameBuffer.Height, contents);
+ }
+ /// <summary>
+ /// Begin Render pass with custom render area
+ /// </summary>
+ 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 ();
- }
+ }
/// <summary>
/// Switch to next subpass
/// </summary>
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);
+ }
/// <summary>
/// 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.
/// </summary>
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) {
max = _max;
}
}
-
+
public class InstancedCmd
{
public int meshIdx;
public uint count;
}
-
+
public class Primitive {
public string name;
public uint indexBase;
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;
return null;
}
-
+
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
-
+
<ReleaseVersion>$(VkeReleaseVersion)</ReleaseVersion>
-
+
<AssemblyVersion>$(VkeReleaseVersion)</AssemblyVersion>
- <Description>C# vulkan library with IDispose model and references counting</Description>
+ <Description>C# vulkan library with IDispose model and references counting</Description>
<RepositoryUrl>https://github.com/jpbruyere/vke.net</RepositoryUrl>
<PackageTags>vulkan game engine compute glfw c#</PackageTags>
<PackageVersion>$(VkePackageVersion)</PackageVersion>
-
+
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
-
+
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
<PackageProjectUrl>https://github.com/jpbruyere/vke.net/blob/master/README.md</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>icon.png</PackageIcon>
<License>MIT</License>
<Authors>Jean-Philippe Bruyère</Authors>
- <PackageReleaseNotes>
+ <PackageReleaseNotes>
</PackageReleaseNotes>
<!--<PackageIconUrl>https://github.com/KhronosGroup/glTF/blob/master/specification/figures/gltf.png</PackageIconUrl>-->
<SynchReleaseVersion>false</SynchReleaseVersion>
-
+
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<IntermediateOutputPath>$(SolutionDir)build\$(Configuration)\</IntermediateOutputPath>
-
+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-
- <EnableDefaultNoneItems>false</EnableDefaultNoneItems>
- <LangVersion>7.2</LangVersion>
- <GenerateDocumentationFile>true</GenerateDocumentationFile>
- <NoWarn>$(NoWarn);1591</NoWarn>
-
+
+ <EnableDefaultNoneItems>false</EnableDefaultNoneItems>
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
+ <NoWarn>$(NoWarn);1591</NoWarn>
+
<RestoreAdditionalProjectSources Condition="Exists('$(SolutionDir)build\$(Configuration)\')">$(SolutionDir)build\$(Configuration)\</RestoreAdditionalProjectSources>
</PropertyGroup>
-
+
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
- <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
+ <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
</ItemGroup>
-
+
<ItemGroup Condition=" '$(UseStbSharp)' == 'true'">
<PackageReference Include="StbImageSharp" Version="2.22.4" />
</ItemGroup>
<PackageReference Include="shaderc.net" Version="0.1.0" />
<PackageReference Include="glfw-sharp" Version="0.2.12-beta" />
</ItemGroup>
-
+
<ItemGroup>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.1" />
</ItemGroup>