]> O.S.I.I.S - jp/vke.net.git/commitdiff
swapchain semaphore queue, shaderObject wip, TargetSpirV and TargetEnv in SpirVTasks...
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Wed, 29 Jan 2025 19:33:44 +0000 (20:33 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Wed, 29 Jan 2025 19:33:44 +0000 (20:33 +0100)
20 files changed:
.vscode/launch.json
.vscode/tasks.json
SpirVTasks/CompileGLSLTask.cs
SpirVTasks/SpirVTasks.csproj
addons/Directory.Build.props
samples/Directory.Build.props
samples/MeshShader/main.cs
samples/MeshShader/shaders/main.mesh
samples/ShaderObject/README.md [new file with mode: 0644]
samples/ShaderObject/ShaderObject.csproj [new file with mode: 0644]
samples/ShaderObject/main.cs [new file with mode: 0644]
samples/ShaderObject/shaders/main.frag [new file with mode: 0644]
samples/ShaderObject/shaders/main.vert [new file with mode: 0644]
samples/Triangle/main.cs
vke.net.sln
vke/src/Helpers.cs
vke/src/VkWindow.cs
vke/src/base/ShaderObject.cs [new file with mode: 0644]
vke/src/base/SwapChain.cs
vke/vke.csproj

index 4a31790b4a6d9218c4c05fd7b4dcebef0845fc55..ee0e70253116684c57630e4a5fbe903889d22aad 100644 (file)
@@ -9,9 +9,9 @@
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build VulkanContext",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/VulkanContext",
+                       "program": "${workspaceFolder}/build/Debug/net6/VulkanContext",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole",
                        "env": {
@@ -23,9 +23,9 @@
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build ClearScreen",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/ClearScreen",
+                       "program": "${workspaceFolder}/build/Debug/net6/ClearScreen",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole",
                        "env": {
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build Triangle",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/Triangle",
+                       "program": "${workspaceFolder}/build/Debug/net6/Triangle",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
+                       "stopAtEntry": false,
+                       "console": "internalConsole"
+               },
+               {
+                       "name": ".NET Core Launch (ShaderObject)",
+                       "type": "coreclr",
+                       "request": "launch",
+                       "preLaunchTask": "build ShaderObject",
+                       "program": "${workspaceFolder}/build/Debug/net6/ShaderObject",
+                       "args": [],
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole"
                },
@@ -48,9 +59,9 @@
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build FillTests",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/FillTests",
+                       "program": "${workspaceFolder}/build/Debug/net6/FillTests",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole"
                },
@@ -59,9 +70,9 @@
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build DynamicRendering",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/DynamicRendering",
+                       "program": "${workspaceFolder}/build/Debug/net6/DynamicRendering",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole"
                },
@@ -70,9 +81,9 @@
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build MeshShader",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/MeshShader",
+                       "program": "${workspaceFolder}/build/Debug/net6/MeshShader",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole",
                        "env": {
@@ -86,9 +97,9 @@
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build Compute",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/compute",
+                       "program": "${workspaceFolder}/build/Debug/net6/compute",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole",
                        "env": {
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build ExternalMemmories",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/ExternalMemmories",
+                       "program": "${workspaceFolder}/build/Debug/net6/ExternalMemmories",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole"
                },
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build Textured",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/Textured",
+                       "program": "${workspaceFolder}/build/Debug/net6/Textured",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole"
                },
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build pbr",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/pbr",
+                       "program": "${workspaceFolder}/build/Debug/net6/pbr",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "internalConsole"
                },
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build deferred",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/deferred",
+                       "program": "${workspaceFolder}/build/Debug/net6/deferred",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "stopAtEntry": false,
                        "console": "integratedTerminal"
                },
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build DistanceFieldFontTest",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/DistanceFieldFontTest",
+                       "program": "${workspaceFolder}/build/Debug/net6/DistanceFieldFontTest",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "console": "internalConsole",
                        "stopAtEntry": false
                },
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build immutableSampler",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/ImmutableSampler",
+                       "program": "${workspaceFolder}/build/Debug/net6/ImmutableSampler",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "console": "internalConsole",
                        "stopAtEntry": false
                },
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build Multithreading",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/Multithreading",
+                       "program": "${workspaceFolder}/build/Debug/net6/Multithreading",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "console": "internalConsole",
                        "stopAtEntry": false
                },
                        "type": "coreclr",
                        "request": "launch",
                        "preLaunchTask": "build Multithreading2",
-                       "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/Multithreading2",
+                       "program": "${workspaceFolder}/build/Debug/net6/Multithreading2",
                        "args": [],
-                       "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
+                       "cwd": "${workspaceFolder}/build/Debug/net6/",
                        "console": "internalConsole",
                        "stopAtEntry": false
                },
index d7522d2088126b118e20db9f24dce03570f9c1e4..e501b277a9b0db51e9ccde9ce32f3b18dcafc2f6 100644 (file)
                        ],
                        "problemMatcher": "$msCompile"
                },
+               {
+                       "label": "build ShaderObject",
+                       "command": "dotnet",
+                       "type": "process",
+                       "args": [
+                               "build",
+                               "${workspaceFolder}/samples/ShaderObject/ShaderObject.csproj",
+                               "/property:GenerateFullPaths=true",
+                               "/property:SolutionDir=${workspaceFolder}/",
+                               "/property:Configuration=Debug",
+                               "/consoleloggerparameters:NoSummary"
+                       ],
+                       "problemMatcher": "$msCompile"
+               },
                {
                        "label": "build FillTests",
                        "command": "dotnet",
index db19af0ee19edaeb01c98d442f025fb82a369690..506c16a0023d24ebf6ec3017edeeed580a82c465 100644 (file)
@@ -75,6 +75,20 @@ namespace SpirVTasks {
                        get;
                        set;
                }
+               /// <summary>
+               /// Optional, Specify the target spirv version. Default depends on TargetEnv
+               /// </summary>
+               public ITaskItem TargetSpirV {
+                       get;
+                       set;
+               }
+               /// <summary>
+               /// Optional, Specify the target client environment. (default=Vulkan1.0)
+               /// </summary>
+               public ITaskItem TargetEnv {
+                       get;
+                       set;
+               }
 
                volatile bool success;
                //due to includes mechanic, file inclusion position has to be recorded
@@ -223,6 +237,13 @@ namespace SpirVTasks {
                        }else
                                optimisationStr = "-O";
 
+                       string targetSpirV = "";
+                       if (!string.IsNullOrEmpty(TargetSpirV?.ItemSpec))
+                               targetSpirV = $"--target-spv={TargetSpirV.ItemSpec}";
+                       string targetEnv = "";
+                       if (!string.IsNullOrEmpty(TargetEnv?.ItemSpec))
+                               targetEnv = $"--target-env={TargetEnv.ItemSpec}";
+
                        Process glslc = new Process();
                        //glslc.StartInfo.StandardOutputEncoding = System.Text.Encoding.ASCII;
                        //glslc.StartInfo.StandardErrorEncoding = System.Text.Encoding.ASCII;
@@ -230,7 +251,7 @@ namespace SpirVTasks {
                        glslc.StartInfo.RedirectStandardOutput = true;
                        glslc.StartInfo.RedirectStandardError = true;
                        glslc.StartInfo.FileName = glslcPath;
-                       glslc.StartInfo.Arguments = $"\"{tempFile}\" -o \"{DestinationFile.ItemSpec}\" {macros.ToString()} {optimisationStr}";
+                       glslc.StartInfo.Arguments = $"\"{tempFile}\" -o \"{DestinationFile.ItemSpec}\" {macros.ToString()} {optimisationStr} {targetEnv} {targetSpirV}";
                        glslc.StartInfo.CreateNoWindow = true;
 
                        glslc.EnableRaisingEvents = true;
index d8f243beb2ee37b3a36fa0977851e73b96d7754f..878c8daac4076f71acea0c462d7942982356ba02 100644 (file)
@@ -13,7 +13,7 @@
                <PackageVersion>$(SpirVTasksPackageVersion)</PackageVersion>
                <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
                <PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
-               <PackageProjectUrl>https://github.com/jpbruyere/vk.net/blob/master/SpirVTasks/README.md</PackageProjectUrl>
+               <PackageProjectUrl>https://github.com/jpbruyere/vke.net/blob/master/SpirVTasks/README.md</PackageProjectUrl>
                <PackageLicenseExpression>MIT</PackageLicenseExpression>
                <PackageIcon>icon.png</PackageIcon>
                <License>MIT</License>
                <AssemblyName>SpirVTasks_$(TargetFramework)</AssemblyName>
                
                <RestoreIgnoreFailedSource>true</RestoreIgnoreFailedSource>
+
+               <PackageReleaseNotes>
+               
+               </PackageReleaseNotes>          
        </PropertyGroup>
        <ItemGroup>
                <PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.0.461" PrivateAssets="all" />
index 5330c53cebf91b574128c75490234c8730179610..add4891b9bc6ac9e9e5d176fcd6bd4c8b445ec72 100644 (file)
@@ -4,7 +4,7 @@
                <RootDirectory>$(MSBuildThisFileDirectory)../</RootDirectory>
                <Deterministic>true</Deterministic>
 
-               <TargetFrameworks>netcoreapp3.1</TargetFrameworks>
+               <TargetFrameworks>net6</TargetFrameworks>
 
                <RepositoryUrl>https://github.com/jpbruyere/vke.net</RepositoryUrl>
                <PackageLicenseExpression>MIT</PackageLicenseExpression>
index 87424d224bb832465f5df444b0daadb3512a42d8..f64ce41b7db072480871d2618c6f5c74a0040efe 100644 (file)
@@ -4,7 +4,7 @@
                <RootDirectory>$(MSBuildThisFileDirectory)../</RootDirectory>
                <Deterministic>true</Deterministic>
 
-               <TargetFrameworks>netcoreapp3.1</TargetFrameworks>
+               <TargetFrameworks>net6</TargetFrameworks>
 
                <RepositoryUrl>https://github.com/jpbruyere/vke.net</RepositoryUrl>
                <License>MIT</License>
index 1c4f446a0cbedb3bd8c1c10cb2ac6586dd45e708..5a889ed9fcf70967689d8bf400c9772b3b5308c5 100644 (file)
@@ -12,9 +12,12 @@ using System.Collections.Generic;
 
 namespace MeshShader {
        class Program : SampleBase {
-               public override string[] EnabledInstanceExtensions => new string[] {
+        public override string[] EnabledLayers => new string[] {
+                       "VK_LAYER_KHRONOS_validation"
+               };
+        public override string[] EnabledInstanceExtensions => new string[] {
                        Ext.I.VK_KHR_get_physical_device_properties2,
-                       //Ext.I.VK_EXT_debug_utils,
+                       Ext.I.VK_EXT_debug_utils,
                };
                public override string[] EnabledDeviceExtensions => new string[] {
                        Ext.D.VK_KHR_swapchain,
index f6001ca5c252189821b844d35afdbccbd1756e1e..b160a7dc5145b8758974a65d20a59e83486e20d7 100644 (file)
@@ -1,6 +1,6 @@
-#version 450
+#version 460
  
-#extension GL_NV_mesh_shader : require
+#extension GL_EXT_mesh_shader : require
  
 layout(local_size_x = 1) in;
 layout(triangles, max_vertices = 3, max_primitives = 1) out;
@@ -28,17 +28,13 @@ const vec3 colors[3] = {vec3(1.0,0.0,0.0), vec3(0.0,1.0,0.0), vec3(0.0,0.0,1.0)}
  
 void main()
 {
-  gl_MeshVerticesNV[0].gl_Position = mvp * vertices[0]; 
-  gl_MeshVerticesNV[1].gl_Position = mvp * vertices[1]; 
-  gl_MeshVerticesNV[2].gl_Position = mvp * vertices[2]; 
+  gl_MeshVerticesEXT[0].gl_Position = mvp * vertices[0]; 
+  gl_MeshVerticesEXT[1].gl_Position = mvp * vertices[1]; 
+  gl_MeshVerticesEXT[2].gl_Position = mvp * vertices[2]; 
  
   v_out[0].color = vec4(colors[0], 1.0);
   v_out[1].color = vec4(colors[1], 1.0);
   v_out[2].color = vec4(colors[2], 1.0);
  
-  gl_PrimitiveIndicesNV[0] = 0;
-  gl_PrimitiveIndicesNV[1] = 1;
-  gl_PrimitiveIndicesNV[2] = 2;
-  gl_PrimitiveCountNV = 1;
+  gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0,1,2);
 }
\ No newline at end of file
diff --git a/samples/ShaderObject/README.md b/samples/ShaderObject/README.md
new file mode 100644 (file)
index 0000000..8bdcb08
--- /dev/null
@@ -0,0 +1,153 @@
+# Shaders
+For this tutorials we'll need a `vertex` and a `fragment` shaders. Vulkan need them to be compiled into [SPIR-V](https://www.khronos.org/spir/). Install the [Vulkan Sdk](https://www.lunarg.com/vulkan-sdk/) and after building it, ensure the `VULKAN_SDK` environment variable points to its binary subdir.
+```bash
+export VULKAN_SDK=/VulkanSDK/1.2.176.1/x86_64
+```
+To enable automatic shader compilation during build, add the [SpirVTasks package](https://www.nuget.org/packages/SpirVTasks/) and a generic **GLSLShader** item globing a full directory.
+```xml
+<ItemGroup>
+  <PackageReference Include="SpirVTasks" />
+</ItemGroup>
+<ItemGroup>
+  <GLSLShader Include="shaders\*.*" />
+</ItemGroup>
+```
+See [SpirVTasks documentation](https://github.com/jpbruyere/vke.net/tree/master/SpirVTasks) for more informations.
+
+# 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));
+```
+# Configuring pipelines
+
+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
+using (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
+```
+# Adding the shaders
+Add both vertex and fragment shaders to the globbed directory of your `.csproj`
+
+##### triangle.vert
+```glsl
+#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);
+}
+```
+##### triangle.frag
+```glsl
+#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);
+}
+```
+
+Shaders will be compiled into spir-v automatically during build by the `SpirVTasks`. The resulting shaders will be 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.triangle.vert.spv");
+cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.triangle.frag.spv");
+```
+Because native ShaderModule used during pipeline creation may be distroyed once the pipeline is created, The PipelineConfig class implement the
+'IDisposable' interface to release those pointers automaticaly.
+
+# Creating the pipeline
+Once the pipeline configuration is complete, we use it to effectively create and activate a new 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);
+```
+# Descriptor allocation
+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]);
+```
+# Descriptor update
+
+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);
+```
+
+# Updating the view
+
+Override the `UpdateView` method of the `VkWindow` class to update view related stuff like matrices.
+
+```csharp
+public override void UpdateView () {
+  mvp = Matrix4x4.Create ...
+  uboMats.Update (mvp, (uint)Marshal.SizeOf<Matrix4x4> ());
+  base.UpdateView ();
+}
+```
+This method is called at least once before the rendering loop just after 'OnResize'.
+Then, it is triggered in the render loop each time the `updateViewRequested` field of `VkWindow` is set to 'true',
+don't forget to reset `updateViewRequested` to 'false' or call the `base.UpdateView()` which will reset this boolean.
+
+In a typical application, the mouse movements will set `updateViewRequested` to true.
+```csharp
+protected override void onMouseMove (double xPos, double yPos) {
+  updateViewRequested = true;
+```
diff --git a/samples/ShaderObject/ShaderObject.csproj b/samples/ShaderObject/ShaderObject.csproj
new file mode 100644 (file)
index 0000000..672fb5a
--- /dev/null
@@ -0,0 +1,5 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <IncludeDefaultNoneItems>false</IncludeDefaultNoneItems>
+  </PropertyGroup>
+</Project>
diff --git a/samples/ShaderObject/main.cs b/samples/ShaderObject/main.cs
new file mode 100644 (file)
index 0000000..e8e74a0
--- /dev/null
@@ -0,0 +1,173 @@
+// Copyright (c) 2023  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;
+using System.Collections.Generic;
+
+//the traditional triangle sample with shader object
+namespace ShaderObjectSample {
+       class Program : SampleBase {
+        public override string[] EnabledDeviceExtensions => new string[] {
+                       Ext.D.VK_KHR_swapchain,
+                       Ext.D.VK_EXT_shader_object
+               };
+        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);
+                       }
+               }
+
+               HostBuffer ibo;     //a host mappable buffer to hold the indices.
+               HostBuffer vbo;     //a host mappable buffer to hold vertices.
+               HostBuffer<Matrix4x4> uboMVPmatrix; //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 ();
+
+                       DescriptorSetLayout dsLayout = new DescriptorSetLayout (dev, new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer));                  
+                       ShaderObject vertexShader = new ShaderObject(dev, VkShaderStageFlags.Vertex, VkShaderStageFlags.Fragment, dsLayout);
+                       vertexShader.FileName = "#shaders.main.vert.spv";
+                       
+                       vertexShader.Activate();
+                       
+                       
+                       vbo = new HostBuffer<Vertex> (dev, VkBufferUsageFlags.VertexBuffer, vertices);
+                       ibo = new HostBuffer<ushort> (dev, VkBufferUsageFlags.IndexBuffer, indices);
+                       
+                       uboMVPmatrix = new HostBuffer<Matrix4x4> (dev, VkBufferUsageFlags.UniformBuffer, 1, true);
+                       
+                       descriptorPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer));
+
+                       /*
+                               cfg.AddVertexBinding<Vertex> (0);
+                               cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat);//position + color
+                               cfg.AddShaders (
+                                       new ShaderInfo (dev, VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"),
+                                       new ShaderInfo (dev, VkShaderStageFlags.Fragment, "#shaders.main.frag.spv")
+                               );
+                       */
+
+                       descriptorSet = descriptorPool.Allocate (pipeline.Layout.DescriptorSetLayouts[0]);
+                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descriptorSet, pipeline.Layout.DescriptorSetLayouts[0]);
+                       uboUpdate.Write (dev, uboMVPmatrix.Descriptor);
+                       cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount);
+               }
+
+               //view update override, see base method for more informations.
+               public override void UpdateView () {
+                       uboMVPmatrix.AsSpan()[0] =
+                               Matrix4x4.CreateFromAxisAngle (Vector3.UnitY, rotY) *
+                               Matrix4x4.CreateFromAxisAngle (Vector3.UnitX, rotX) *
+                               Matrix4x4.CreateTranslation (0, 0, -3f * zoom) *
+                               Helpers.CreatePerspectiveFieldOfView (Helpers.DegreesToRadians (45f), (float)swapChain.Width / (float)swapChain.Height, 0.1f, 256.0f);
+
+                       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 ();
+
+                       updateViewRequested = true;
+
+                       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 ();
+                                       uboMVPmatrix.Dispose ();
+                               }
+                       }
+
+                       base.Dispose (disposing);
+               }
+       }
+}
diff --git a/samples/ShaderObject/shaders/main.frag b/samples/ShaderObject/shaders/main.frag
new file mode 100644 (file)
index 0000000..85aeb08
--- /dev/null
@@ -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/ShaderObject/shaders/main.vert b/samples/ShaderObject/shaders/main.vert
new file mode 100644 (file)
index 0000000..40a3796
--- /dev/null
@@ -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);
+}
index c52f2923e2c7fe4a5a6674e724b0e23b20b496ab..2646543d015dee0209da30e7c00a3c66c4f4bec5 100644 (file)
@@ -13,7 +13,7 @@ namespace FillTests {
        class Program : SampleBase {
                static void Main (string[] args) {
 #if DEBUG
-                       //Instance.VALIDATION = true;
+                       Instance.VALIDATION = true;
 #endif
                        using (Program vke = new Program ()) {
                                vke.Run ();
index 0219e5f3b0fc91f9017234258382e5555c9cd19e..7a04fd8981161fd98aceab4a39a28ccda4b83c1c 100644 (file)
@@ -50,9 +50,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VulkanContext", "samples\Vu
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MeshShader", "samples\MeshShader\MeshShader.csproj", "{5787D082-7E4E-4B18-9C69-529CBC4F105E}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicRendering", "samples\DynamicRendering\DynamicRendering.csproj", "{3A0E5765-911E-4451-9715-ED55095D6C39}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamicRendering", "samples\DynamicRendering\DynamicRendering.csproj", "{3A0E5765-911E-4451-9715-ED55095D6C39}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FillTests", "samples\FillTests\FillTests.csproj", "{273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FillTests", "samples\FillTests\FillTests.csproj", "{273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShaderObject", "samples\ShaderObject\ShaderObject.csproj", "{1B63D92E-7C54-41DA-9BCA-AC0C53F3D371}"
 EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -62,12 +64,6 @@ Global
                ReleaseSpirVTasks|Any CPU = ReleaseSpirVTasks|Any CPU
        EndGlobalSection
        GlobalSection(ProjectConfigurationPlatforms) = postSolution
-               {7B05B5A7-49E2-4D05-BEF8-734F70CDBF17}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
-               {7B05B5A7-49E2-4D05-BEF8-734F70CDBF17}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
-               {7B05B5A7-49E2-4D05-BEF8-734F70CDBF17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-               {7B05B5A7-49E2-4D05-BEF8-734F70CDBF17}.Debug|Any CPU.Build.0 = Debug|Any CPU
-               {7B05B5A7-49E2-4D05-BEF8-734F70CDBF17}.Release|Any CPU.ActiveCfg = Release|Any CPU
-               {7B05B5A7-49E2-4D05-BEF8-734F70CDBF17}.Release|Any CPU.Build.0 = Release|Any CPU
                {7B05B5A7-49E2-4D05-BEF8-734F70CDBF17}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Release|Any CPU
                {7B05B5A7-49E2-4D05-BEF8-734F70CDBF17}.ReleaseSpirVTasks|Any CPU.Build.0 = Release|Any CPU
                {642726F4-0592-4846-8EAF-A5D1964C85A7}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
@@ -138,22 +134,16 @@ Global
                {5787D082-7E4E-4B18-9C69-529CBC4F105E}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {5787D082-7E4E-4B18-9C69-529CBC4F105E}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {5787D082-7E4E-4B18-9C69-529CBC4F105E}.Release|Any CPU.Build.0 = Release|Any CPU
-               {3A0E5765-911E-4451-9715-ED55095D6C39}.BuildPackages|Any CPU.ActiveCfg = Debug|Any CPU
-               {3A0E5765-911E-4451-9715-ED55095D6C39}.BuildPackages|Any CPU.Build.0 = Debug|Any CPU
                {3A0E5765-911E-4451-9715-ED55095D6C39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                {3A0E5765-911E-4451-9715-ED55095D6C39}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {3A0E5765-911E-4451-9715-ED55095D6C39}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {3A0E5765-911E-4451-9715-ED55095D6C39}.Release|Any CPU.Build.0 = Release|Any CPU
-               {3A0E5765-911E-4451-9715-ED55095D6C39}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
-               {3A0E5765-911E-4451-9715-ED55095D6C39}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
-               {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}.BuildPackages|Any CPU.ActiveCfg = Debug|Any CPU
-               {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}.BuildPackages|Any CPU.Build.0 = Debug|Any CPU
                {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}.Release|Any CPU.Build.0 = Release|Any CPU
-               {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
-               {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
+               {1B63D92E-7C54-41DA-9BCA-AC0C53F3D371}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {1B63D92E-7C54-41DA-9BCA-AC0C53F3D371}.Debug|Any CPU.Build.0 = Debug|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -175,6 +165,7 @@ Global
                {5787D082-7E4E-4B18-9C69-529CBC4F105E} = {16439374-B8DB-4643-8116-EB3358B49A12}
                {3A0E5765-911E-4451-9715-ED55095D6C39} = {16439374-B8DB-4643-8116-EB3358B49A12}
                {273C88AE-D095-4CF9-8D6F-D7ABE3E9C8D3} = {16439374-B8DB-4643-8116-EB3358B49A12}
+               {1B63D92E-7C54-41DA-9BCA-AC0C53F3D371} = {16439374-B8DB-4643-8116-EB3358B49A12}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
                SolutionGuid = {1360F94D-CF3C-4121-A8D7-E227F41668F1}
index 86d026b5f3845cea01a7b7d58cfcd8cb9ec64188..45694bfc0ce97f8ab3198e7a0f025ff582a76299 100644 (file)
@@ -12,8 +12,7 @@ using System.Xml.Serialization;
 using Vulkan;
 
 namespace vke {
-       public static partial class Helpers {
-               /// <summary>Throw an erro if VkResult != Success.</summary>
+       public static partial class Helpers {           
                static void xmlMakeTypeFieldsAsAttributes (Type t, ref XmlAttributeOverrides overrides)
                {
                        foreach (FieldInfo fi in t.GetFields (BindingFlags.Public | BindingFlags.Instance))
index d527880ead96acc840b8017dedb45db26bfc040f..4acbc1b682106ec2a521dd17b0126fa82dc66088 100644 (file)
@@ -235,9 +235,10 @@ namespace vke {
                        drawFence.Wait ();
                        drawFence.Reset ();
 
-                       presentQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx], drawFence);
+                       presentQueue.Submit (cmds[idx], swapChain.nextImgAvail, drawComplete[idx], drawFence);
                        presentQueue.Present (swapChain, drawComplete[idx]);
 
+                       swapChain.semaphoresQueue.Enqueue(swapChain.nextImgAvail);
                        //presentQueue.WaitIdle ();
                }
 
diff --git a/vke/src/base/ShaderObject.cs b/vke/src/base/ShaderObject.cs
new file mode 100644 (file)
index 0000000..3cae8ce
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright (c) 2023  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.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Vulkan;
+using static Vulkan.Vk;
+using static Vulkan.Utils;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace vke {
+       /// <summary>
+       /// Collection of FrameBuffers, useful to handle multiple framebuffers for a swapchain.
+       /// </summary>
+       public class ShaderObjects : Collection<ShaderObject>, IDisposable
+       {
+               //public Framebuffer this[int index] => Items[index];
+
+               public void Dispose()
+               {
+                       foreach (ShaderObject fb in Items)
+                               fb.Dispose();
+                       ClearItems();
+               }
+       }       
+       public sealed class ShaderObject : Activable {
+        internal VkShaderEXT handle;
+               public VkShaderEXT Handle => handle;
+               public string FileName;
+               public VkShaderStageFlags Stage;
+               public VkShaderStageFlags NextStage;
+               public VkShaderCreateFlagsEXT Flags = VkShaderCreateFlagsEXT.LinkStageEXT;
+
+               public List<DescriptorSetLayout> DescriptorSetLayouts = new List<DescriptorSetLayout> ();
+               public List<VkPushConstantRange> PushConstantRanges = new List<VkPushConstantRange> ();
+
+               protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo
+                       => new VkDebugUtilsObjectNameInfoEXT (VkObjectType.ShaderEXT, handle.Handle);
+
+               #region CTORS
+               public ShaderObject (Device device, VkShaderStageFlags stage, VkShaderStageFlags nextStage) : base (device) {
+                       Stage = stage;
+                       NextStage = nextStage;
+               }
+               public ShaderObject (Device device, VkShaderStageFlags stage, VkShaderStageFlags nextStage, VkPushConstantRange pushConstantRange, params DescriptorSetLayout[] descriptorSetLayouts)
+               : this (device, stage, nextStage, descriptorSetLayouts) {
+                       PushConstantRanges.Add (pushConstantRange);
+               }
+               public ShaderObject (Device device, VkShaderStageFlags stage, VkShaderStageFlags nextStage, VkPushConstantRange[] pushConstantRanges, params DescriptorSetLayout[] descriptorSetLayouts)
+               : this (device, stage, nextStage, descriptorSetLayouts) {
+                       foreach (VkPushConstantRange pcr in pushConstantRanges)
+                               PushConstantRanges.Add (pcr);
+               }
+               public ShaderObject (Device device, VkShaderStageFlags stage, VkShaderStageFlags nextStage, params DescriptorSetLayout[] descriptorSetLayouts)
+                       :this (device, stage, nextStage) {
+
+                       if (descriptorSetLayouts.Length > 0)
+                               DescriptorSetLayouts.AddRange (descriptorSetLayouts);
+        }
+               #endregion
+
+               public void AddPushConstants (params VkPushConstantRange[] pushConstantRanges) {
+                       foreach (VkPushConstantRange pcr in pushConstantRanges)
+                               PushConstantRanges.Add (pcr);
+               }
+
+               uint[] getCode(out UIntPtr shaderSize) {
+                       using (Stream stream = Helpers.GetStreamFromPath (FileName)) {
+                               using (BinaryReader br = new BinaryReader (stream)) {
+                                       byte[] shaderCode = br.ReadBytes ((int)stream.Length);
+                                       shaderSize = (UIntPtr)shaderCode.Length;
+                                       ReadOnlySpan<uint> tmp = MemoryMarshal.Cast<byte, uint> (shaderCode);
+                                       return tmp.ToArray();
+                               }
+                       }
+               }
+
+               public override void Activate () {
+                       if (state != ActivableState.Activated) {
+                               foreach (DescriptorSetLayout dsl in DescriptorSetLayouts)
+                                       dsl.Activate ();
+
+                               
+                               VkShaderCreateInfoEXT info = default;
+                               info.flags = VkShaderCreateFlagsEXT.LinkStageEXT;
+                               info.stage = VkShaderStageFlags.Vertex;
+                               info.stage = VkShaderStageFlags.Fragment;
+                               info.codeType = VkShaderCodeTypeEXT.SpirvEXT;
+
+                               uint[] code = getCode(out UIntPtr codeSize);
+                               info.codeSize = codeSize;
+                               info.pCode = code.PinPointer();
+
+                               VkDescriptorSetLayout[] dsls = DescriptorSetLayouts.Select (dsl => dsl.handle).ToArray ();
+
+                               if (dsls.Length > 0) {
+                                       info.pSetLayouts = dsls;
+                               }
+                               if (PushConstantRanges.Count > 0) {
+                                       info.pPushConstantRanges = PushConstantRanges;
+                               }
+                               CheckResult (vkCreateShadersEXT (Dev.Handle, 1, ref info, IntPtr.Zero, out handle));
+
+                               code.Unpin();
+                               info.Dispose();
+
+                       }
+                       base.Activate ();
+               }
+
+               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) {
+                               if (disposing) {
+                                       foreach (DescriptorSetLayout dsl in DescriptorSetLayouts)
+                                               dsl.Dispose ();
+                               } else
+                                       System.Diagnostics.Debug.WriteLine ("VKE Activable ShaderObject disposed by finalizer");
+
+                               vkDestroyShaderEXT (Dev.Handle, handle, IntPtr.Zero);
+                       }else if (disposing)
+                               System.Diagnostics.Debug.WriteLine ("Calling dispose on unactive ShaderObject");
+
+                       base.Dispose (disposing);
+               }
+               #endregion
+       }
+}
index aa916b12069631a993581e2479c401f3f1f21982..08b6d884d85ac213e51445ac71d1f7b24f540281 100644 (file)
@@ -6,6 +6,7 @@ using System;
 using Vulkan;
 using static Vulkan.Vk;
 using static Vulkan.Utils;
+using System.Collections.Generic;
 
 namespace vke {
        /// <summary>
@@ -31,7 +32,8 @@ namespace vke {
                VkSwapchainCreateInfoKHR createInfos;
                PresentQueue presentQueue;
 
-               public VkSemaphore presentComplete;
+               public Queue<VkSemaphore> semaphoresQueue = new Queue<VkSemaphore>();
+               public VkSemaphore nextImgAvail;
                public Image[] images;
 
                protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo
@@ -126,12 +128,10 @@ namespace vke {
                        if (Handle.Handle != 0)
                                _destroy ();
 
-                       presentComplete = Dev.CreateSemaphore ();
-                       presentComplete.SetDebugMarkerName (Dev, "Semaphore PresentComplete");
                        Handle = newSwapChain;
 
                        CheckResult (vkGetSwapchainImagesKHR (Dev.Handle, Handle, out uint imageCount, IntPtr.Zero));
-                       if (imageCount == 0)
+                       if (imageCount == 0)                    
                                throw new Exception ("Swapchain image count is 0.");
                        VkImage[] imgs = new VkImage[imageCount];
                        CheckResult (vkGetSwapchainImagesKHR (Dev.Handle, Handle, out imageCount, imgs.Pin ()));
@@ -143,6 +143,12 @@ namespace vke {
                                images[i].CreateView ();
                                images[i].SetName ("SwapChain Img" + i);
                                images[i].Descriptor.imageView.SetDebugMarkerName (Dev, "SwapChain Img" + i + " view");
+
+
+                               nextImgAvail = Dev.CreateSemaphore ();
+                               nextImgAvail.SetDebugMarkerName (Dev, $"Semaphore " + i + " Img Acquired");
+
+                               semaphoresQueue.Enqueue(nextImgAvail);
                        }
                }
                /// <summary>
@@ -151,7 +157,8 @@ namespace vke {
                /// <returns>Swapchain image index or -1 if failed</returns>
                /// <param name="fence">an optional fence to signal.</param>
                public int GetNextImage (Fence fence = null) {
-                       VkResult res = vkAcquireNextImageKHR (Dev.Handle, Handle, UInt64.MaxValue, presentComplete, fence, out currentImageIndex);
+                       nextImgAvail = semaphoresQueue.Dequeue();
+                       VkResult res = vkAcquireNextImageKHR (Dev.Handle, Handle, UInt64.MaxValue, nextImgAvail, fence, out currentImageIndex);
                        if (res == VkResult.ErrorOutOfDateKHR || res == VkResult.SuboptimalKHR) {
                                Create ();
                                return -1;
@@ -161,10 +168,14 @@ namespace vke {
                }
 
                void _destroy () {
-                       for (int i = 0; i < ImageCount; i++)
+                       for (int i = 0; i < ImageCount; i++) {
                                images[i].Dispose ();
+                       }
+                       if (semaphoresQueue.Count < ImageCount)
+                               Dev.DestroySemaphore (nextImgAvail);
+                       while(semaphoresQueue.Count > 0)
+                               Dev.DestroySemaphore (semaphoresQueue.Dequeue());
                        vkDestroySwapchainKHR (Dev.Handle, Handle, IntPtr.Zero);
-                       Dev.DestroySemaphore (presentComplete);
                }
 
                public override string ToString () {
index ceca310a3ca46fcda7cb87ceddff78414efaf8e4..5ff69a023cd07dfdb140305b0ad3dfb6f066b1fc 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project Sdk="Microsoft.NET.Sdk">
        <PropertyGroup>
-               <TargetFramework>netcoreapp3.1</TargetFramework>
+               <TargetFramework>netstandard2.1</TargetFramework>
 
                <ReleaseVersion>$(VkeReleaseVersion)</ReleaseVersion>
 
@@ -48,9 +48,9 @@
 
        <ItemGroup>
                <PackageReference Include="SpirVTasks" Version="$(SpirVTasksPackageVersion)" />
-               <PackageReference Include="Vulkan" Version="0.5.1" />
+               <PackageReference Include="Vulkan" Version="0.5.4" />
                <PackageReference Include="shaderc.net" Version="0.1.0" />
-               <PackageReference Include="glfw-sharp" Version="0.2.14" />
+               <PackageReference Include="glfw-sharp" Version="0.2.15" />
        </ItemGroup>
 
        <ItemGroup>