From: Jean-Philippe Bruyère Date: Sat, 23 Oct 2021 12:53:17 +0000 (+0200) Subject: doc, update data download link X-Git-Tag: v0.2.2-beta~1 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=e76142cac4d715eee79cf6e45e68b9b124b5f51c;p=jp%2Fvke.net.git doc, update data download link --- diff --git a/.travis.yml b/.travis.yml index 4996a99..56dc2e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: csharp -dist: bionic +dist: bionic dotnet: 3.1 @@ -10,11 +10,11 @@ env: before_install: - wget -qO - http://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add - - - sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-bionic.list https://packages.lunarg.com/vulkan/lunarg-vulkan-bionic.list + - sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-bionic.list https://packages.lunarg.com/vulkan/lunarg-vulkan-bionic.list - sudo apt -qq update - sudo apt -y install vulkan-sdk script: - dotnet build /p:Configuration=ReleaseSpirVTasks - dotnet build /p:Configuration=Release - + diff --git a/.vscode/launch.json b/.vscode/launch.json index d5a945d..a933a89 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -60,11 +60,11 @@ "console": "internalConsole" }, { - "name": ".NET Core Launch (console)", + "name": ".NET Core Launch (ImmutableSampler)", "type": "coreclr", "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/Triangle", + "preLaunchTask": "build immutableSampler", + "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/ImmutableSampler", "args": [], "cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/", "console": "internalConsole", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 9f2434f..8aa8d5a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -71,6 +71,20 @@ ], "problemMatcher": "$msCompile" }, + { + "label": "build immutableSampler", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/samples/ImmutableSampler/ImmutableSampler.csproj", + "/property:GenerateFullPaths=true", + "/property:SolutionDir=${workspaceFolder}/", + "/property:Configuration=Debug", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, { "label": "publish", "command": "dotnet", diff --git a/Directory.Build.props b/Directory.Build.props index 2457375..527f40a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ $(SolutionDir)build\$(Configuration)\ 0.1.45 $(SpirVTasksReleaseVersion) - 0.2.1 + 0.2.2 $(VkeReleaseVersion)-beta true false diff --git a/README.md b/README.md index 0a41155..986c081 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@

vke.net -
+
Vulkan Engine for .NET -
+

@@ -25,11 +25,15 @@

### Presentation -**vke.net** (_vulkan engine for .net_) a vulkan abstraction layer writen in **c#** composed of high level classes encapsulating [vulkan](https://www.khronos.org/vulkan/) objects and commands with `IDispose` model and **reference counting**. [GLFW](https://www.glfw.org/) handles the windowing system. +**vke.net** (_vulkan engine for .net_) is a vulkan abstraction layer writen in **c#** composed of high level classes encapsulating [vulkan](https://www.khronos.org/vulkan/) objects and commands with `IDispose` model and **reference counting**. [GLFW](https://www.glfw.org/) handles the default windowing system. + +vke aims to provide a simple api for all common vulkan tasks, ideal to quickly prototype vulkan applications, but fits also the needs to build complete application or game. + +To see **vke.net** in action check [vkChess.net](https://github.com/jpbruyere/vkChess.net). Vke use autogenerated [vk.net](https://github.com/jpbruyere/vk.net) library for low level binding to vulkan. -Use the 'download_datas.sh' script for downloading sample's datas. +Use the `download_datas.sh` script for downloading sample's datas. vke is in early development stage. @@ -44,21 +48,21 @@ Create a new dotnet console project, and add the [vke nuget package](https://www ```xml - net472 - Exe + net472 + Exe - - - + + + ``` For automatic shader compilation to SpirV, add also the [SpirVTasks](SpirVTasks/README.md) nuget package. ```xml - - - - + + + + ``` ### Samples @@ -69,7 +73,6 @@ For automatic shader compilation to SpirV, add also the [SpirVTasks](SpirVTasks/ | [Textured](samples/Textured/README.md) | ![screenshot](samples/screenShots/Textured.png) | - ### Features - physicaly based rendering, direct and deferred diff --git a/SpirVTasks/README.md b/SpirVTasks/README.md index b5e805d..40d12ee 100644 --- a/SpirVTasks/README.md +++ b/SpirVTasks/README.md @@ -1,13 +1,13 @@

SpirVTasks MSBuild add-on -
+

- +

@@ -19,11 +19,11 @@ To enable SpirV compilation, you need to add the [nuget package](https://www.nug ```xml - + - + - + ``` Resulting `.spv` files are automatically embedded with the resource ID: `ProjectName.file.ext.spv`. You can override this default id by adding a custom **LogicalName**. ```xml @@ -31,7 +31,7 @@ Resulting `.spv` files are automatically embedded with the resource ID: `Project shaders.%(Filename)%(Extension).spv - + ``` `VULKAN_SDK/bin` then `PATH` are searched for the **`glslc`** executable. You can also use the `SpirVglslcPath` property. @@ -52,12 +52,12 @@ SpirVTasks add the ability to use **include** statements in your shader sources. layout (location = 0) in vec3 inColor; layout (location = 0) out vec4 outFragColor; -void main() +void main() { outFragColor = vec4(inColor, 1.0); } ``` -Included files are searched from the location of the current parsed file, then in the `SpirVAdditionalIncludeDirectories`directories if present. +Included files are searched from the location of the current parsed file, then in the `SpirVAdditionalIncludeDirectories` directories if present. ```xml $(MSBuildThisFileDirectory)common;testdir;../anotherdir @@ -71,7 +71,7 @@ It is also valid to add additional include search paths individually for each `G ../include - + ``` @@ -86,7 +86,7 @@ Default optimization if this attribute is not present is **PERF**, accepted valu - PERF: spirv will be optimized for performances. - SIZE: resulting code size will be minimized. -**DefineConstants** attribute may contains a semicolon separated list of implicit **MACRO** to define for compilation. Note that **project constants** are automatically to the compilation unit. +**DefineConstants** attribute may contains a semicolon separated list of implicit **MACRO** to define for compilation. Note that **project constants** are automatically added to the compilation unit. ```xml diff --git a/addons/DistanceFieldFont/BMFont.cs b/addons/DistanceFieldFont/BMFont.cs index 9b0a704..b836363 100644 --- a/addons/DistanceFieldFont/BMFont.cs +++ b/addons/DistanceFieldFont/BMFont.cs @@ -66,7 +66,7 @@ namespace vke.DistanceFieldFont { if (path.EndsWith ("ktx", StringComparison.OrdinalIgnoreCase)) return KTX.KTX.Load (staggingQ, cmdPool, path, VkImageUsageFlags.Sampled, imgProp, genMipMaps, tiling); - return Image.Load (staggingQ.Dev, staggingQ, cmdPool, path, VkFormat.R8g8b8a8Unorm, imgProp, tiling, genMipMaps); + return Image.Load (staggingQ, cmdPool, path, VkFormat.R8g8b8a8Unorm, imgProp, tiling, genMipMaps); } } diff --git a/addons/gltfLoader/glTFLoader.cs b/addons/gltfLoader/glTFLoader.cs index 9d39f47..9a08362 100644 --- a/addons/gltfLoader/glTFLoader.cs +++ b/addons/gltfLoader/glTFLoader.cs @@ -524,7 +524,7 @@ namespace vke.glTF { vkimg = Image.Load (dev, transferQ, cmdPool, glTFLoader.loadDataUri (img)); } else { Debug.WriteLine ("loading image {0} : {1} : {2}", img.Name, img.MimeType, img.Uri);//load image from file path in uri - vkimg = Image.Load (dev, transferQ, cmdPool, Path.Combine (baseDirectory, img.Uri)); + vkimg = Image.Load (transferQ, cmdPool, Path.Combine (baseDirectory, img.Uri)); imgName += ";" + img.Uri; } diff --git a/download_datas.sh b/download_datas.sh index 64d3cc2..faa256f 100755 --- a/download_datas.sh +++ b/download_datas.sh @@ -1,3 +1,3 @@ #!/bin/bash -wget --no-check-certificate "https://onedrive.live.com/download?cid=B3181664476E9B48&resid=B3181664476E9B48%21167&authkey=APMbPmUMFnlrN6s" -O datas.zip +wget --no-check-certificate "https://onedrive.live.com/download?cid=B3181664476E9B48&resid=B3181664476E9B48%21167&authkey=AIDq3olkU5xnxkQ" -O datas.zip unzip datas.zip diff --git a/samples/ClearScreen/README.md b/samples/ClearScreen/README.md index 3851d61..b9f623f 100644 --- a/samples/ClearScreen/README.md +++ b/samples/ClearScreen/README.md @@ -4,19 +4,18 @@ To build a minimal vulkan application, add the [vke](https://www.nuget.org/packa ```xml - - net472 - Exe - - - - - - - - + + net472 + Exe + + + + + + + + - ``` ### VkWindow class @@ -45,7 +44,7 @@ There are several method to clear the screen with vulkan. One is to use the rend renderPass = new RenderPass (dev, swapChain.ColorFormat); renderPass.ClearValues[0] = new VkClearValue (0.1f, 0.2f, 1); renderPass.Activate (); - + cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount); } ``` @@ -63,7 +62,7 @@ protected override void OnResize () { frameBuffers?.Dispose(); frameBuffers = renderPass.CreateFrameBuffers(swapChain); - + buildCommandBuffers (); } ``` @@ -73,7 +72,7 @@ It's common to rebuild the command buffers targeting the swap chain images after ### The command buffers -The `VkWindow` class has a default array of command buffers, one for each swap chain image. But it's up to you to allocate and populate them. +The `VkWindow` class has a default array of command buffers, one for each swap chain image. But it's up to you to allocate and populate them. Here we simply record a begin/end render pass to clear the screen with the load operation of it. ```csharp diff --git a/samples/ClearScreen/main.cs b/samples/ClearScreen/main.cs index 2792850..caf5cbc 100644 --- a/samples/ClearScreen/main.cs +++ b/samples/ClearScreen/main.cs @@ -55,7 +55,7 @@ namespace ClearScreen { } //The resize method is called at least once before any rendering, so it's - //a safe place to initialize output size related vulkan objects like the + //a safe place to initialize output size related vulkan objects like the //frame buffers. protected override void OnResize () { base.OnResize (); @@ -66,7 +66,7 @@ namespace ClearScreen { buildCommandBuffers (); } //clean up - protected override void Dispose (bool disposing) { + protected override void Dispose (bool disposing) { dev.WaitIdle (); renderPass.Dispose (); diff --git a/samples/Textured/README.md b/samples/Textured/README.md index ece9973..f2bad66 100644 --- a/samples/Textured/README.md +++ b/samples/Textured/README.md @@ -18,8 +18,8 @@ the physical device selection, available features list is automatically queried ```csharp protected override void configureEnabledFeatures ( VkPhysicalDeviceFeatures available_features, - ref VkPhysicalDeviceFeatures enabled_features) { - + ref VkPhysicalDeviceFeatures enabled_features) { + enabled_features.samplerAnisotropy = available_features.samplerAnisotropy; } ``` @@ -31,4 +31,24 @@ To create queues, override the **`createQueues`** method of **`VkWindow`**. This protected override void createQueues () { base.createQueues (); transferQ = new Queue (dev, VkQueueFlags.Transfer); -} \ No newline at end of file +} +``` + +### Loading images + +The `vke.Image` classes has facilities to load bitmaps from disk (jpg, gif, ...). KTX images use the `KTX.KTX.Load` static method. + +```csharp +KTX.KTX.Load (presentQueue, cmdPool, path, ... +Image.Load (dev, presentQueue, cmdPool, path, ... +``` + +Once the image is loaded, you may create the associated View and Sampler by calling image instance methods. View and Sampler lifecycle will be bound to the image and disposed when the image is disposed. + +The `Descriptor` property of the image will old the created handles. + +```csharp +nextTexture.CreateView (); +nextTexture.CreateSampler (); +nextTexture.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; +``` \ No newline at end of file diff --git a/samples/Textured/main.cs b/samples/Textured/main.cs index 31337f4..15e6567 100644 --- a/samples/Textured/main.cs +++ b/samples/Textured/main.cs @@ -68,9 +68,9 @@ namespace Textured { protected override void initVulkan () { base.initVulkan (); - + cmds = cmdPool.AllocateCommandBuffer(swapChain.ImageCount); - + loadTexture (imgPathes[currentImgIndex]); vbo = new GPUBuffer (presentQueue, cmdPool, VkBufferUsageFlags.VertexBuffer, vertices); @@ -134,7 +134,7 @@ namespace Textured { pipeline.RenderPass.End (cmd); - cmd.End (); + cmd.End (); } } @@ -151,7 +151,7 @@ namespace Textured { nextTexture = KTX.KTX.Load (presentQueue, cmdPool, path, VkImageUsageFlags.Sampled, imgProp, genMipMaps, tiling); else - nextTexture = Image.Load (dev, presentQueue, cmdPool, path, VkFormat.R8g8b8a8Unorm, imgProp, tiling, genMipMaps); + nextTexture = Image.Load (presentQueue, cmdPool, path, VkFormat.R8g8b8a8Unorm, imgProp, tiling, genMipMaps); updateViewRequested = true; } catch (Exception ex) { Console.WriteLine (ex); @@ -160,7 +160,7 @@ namespace Textured { } //in the main vulkan thread - void updateTextureSet (){ + void updateTextureSet (){ nextTexture.CreateView (); nextTexture.CreateSampler (); nextTexture.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; @@ -175,7 +175,7 @@ namespace Textured { nextTexture = null; } - void updateMatrices () { + void updateMatrices () { matrices.projection = Matrix4x4.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (60f), (float)swapChain.Width / (float)swapChain.Height, 0.1f, 256.0f); matrices.view = Matrix4x4.CreateTranslation (0, 0, -2.5f * zoom); matrices.model = @@ -190,7 +190,7 @@ namespace Textured { if (nextTexture != null) { updateTextureSet (); buildCommandBuffers (); - }else + }else updateMatrices (); updateViewRequested = false; @@ -202,11 +202,11 @@ namespace Textured { 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; } - - updateViewRequested = true; } protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { @@ -232,7 +232,7 @@ namespace Textured { frameBuffers = pipeline.RenderPass.CreateFrameBuffers(swapChain); buildCommandBuffers (); - } + } protected override void Dispose (bool disposing) { dev.WaitIdle (); diff --git a/samples/TexturedCube/main.cs b/samples/TexturedCube/main.cs index 0346914..5b00644 100644 --- a/samples/TexturedCube/main.cs +++ b/samples/TexturedCube/main.cs @@ -58,35 +58,35 @@ namespace TextureCube { -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f,-1.0f, 0.0f, 0.0f, -1.0f,-1.0f,-1.0f, 0.0f, 1.0f, - + -1.0f,-1.0f,-1.0f, 1.0f, 1.0f, // -Z side 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, 1.0f,-1.0f,-1.0f, 0.0f, 1.0f, -1.0f,-1.0f,-1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, - + -1.0f,-1.0f,-1.0f, 1.0f, 0.0f, // -Y side 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, -1.0f,-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, -1.0f,-1.0f, 1.0f, 0.0f, 0.0f, - + -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, // +Y side -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, - + 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, // +X side 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, - + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // +Z side -1.0f,-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, @@ -142,12 +142,12 @@ namespace TextureCube { void buildCommandBuffers () { cmdPool.Reset(); - for (int i = 0; i < swapChain.ImageCount; ++i) { + for (int i = 0; i < swapChain.ImageCount; ++i) { cmds[i].Start (); recordDraw (cmds[i], frameBuffers[i]); - cmds[i].End (); + cmds[i].End (); } - } + } void recordDraw (PrimaryCommandBuffer cmd, FrameBuffer fb) { pipeline.RenderPass.Begin (cmd, fb); @@ -179,19 +179,19 @@ namespace TextureCube { } //in the main vulkan thread - void updateTextureSet (){ + void updateTextureSet (){ nextTexture.CreateView (VkImageViewType.Cube,VkImageAspectFlags.Color,6); nextTexture.CreateSampler (); nextTexture.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; - DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descriptorSet, dsLayout.Bindings[1]); + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descriptorSet, dsLayout.Bindings[1]); uboUpdate.Write (dev, nextTexture.Descriptor); texture?.Dispose (); texture = nextTexture; nextTexture = null; } - void updateMatrices () { + void updateMatrices () { matrices.projection = Matrix4x4.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (60f), (float)swapChain.Width / (float)swapChain.Height, 0.1f, 5.0f); matrices.view = Matrix4x4.CreateFromAxisAngle (Vector3.UnitZ, rotZ) * @@ -211,7 +211,7 @@ namespace TextureCube { dev.WaitIdle (); updateTextureSet (); buildCommandBuffers (); - }else + }else updateMatrices (); updateViewRequested = false; @@ -256,7 +256,7 @@ namespace TextureCube { buildCommandBuffers(); } - + protected override void Dispose (bool disposing) { if (disposing) { if (!isDisposed) { diff --git a/samples/Triangle/README.md b/samples/Triangle/README.md index 27f9eb3..d9343df 100644 --- a/samples/Triangle/README.md +++ b/samples/Triangle/README.md @@ -1,13 +1,13 @@ ### Creating buffers -Vke has two classes to handle buffers. Mappable [`HostBuffer`](../../../../wiki/vke.HostBuffer) and device only [`GPUBuffer`](../../../../wiki/vke.GPUBuffer). +Vke has two classes to handle buffers. Mappable [`HostBuffer`](../../../../wiki/vke.HostBuffer) and device only [`GPUBuffer`](../../../../wiki/vke.GPUBuffer). For this first simple example, we will only use host mappable buffers. Those classes can handle a Generic argument of a blittable type to handle arrays. Resources like buffers or images are activated in constructor, and they need to be explicitly disposed on cleanup. Create them in the `initVulkan` override. ```csharp //the vertex buffer vbo = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vertices); //the index buffer -ibo = new HostBuffer (dev, VkBufferUsageFlags.IndexBuffer, indices); +ibo = new HostBuffer (dev, VkBufferUsageFlags.IndexBuffer, indices); //a permanantly mapped buffer for the mvp matrice uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, mvp, true); ``` @@ -16,15 +16,17 @@ To be able to access the mvp matrix in a shader, we need a descriptor. This impl ```csharp descriptorPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer)); ``` +### Creating 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 -GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault ( - VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); - -cfg.Layout = new PipelineLayout (dev, - new DescriptorSetLayout (dev, - new VkDescriptorSetLayoutBinding ( - 0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer))); +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 @@ -41,6 +43,9 @@ shader are automatically compiled by [`SpirVTasks`](../../SpirVTasks/README.md) cfg.AddShader (dev, VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"); cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.main.frag.spv"); ``` +Because native ShaderModule used during pipeline creation may be disposed once the pipeline is created, The PipelineConfig class implement the +'IDisposable' interface to release those pointers automaticaly. + 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); @@ -49,6 +54,9 @@ Because descriptor layouts used for a pipeline are only activated on pipeline ac ```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. @@ -58,3 +66,24 @@ DescriptorSetWrites uboUpdate = 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 ()); + 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/Triangle/main.cs b/samples/Triangle/main.cs index d3804af..82b7374 100644 --- a/samples/Triangle/main.cs +++ b/samples/Triangle/main.cs @@ -67,7 +67,10 @@ namespace Triangle { //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. + //Graphic pipeline configuration are predefined by the GraphicPipelineConfig class, + //which ease sharing config for several pipelines having lots in common. + //Because 'ShaderInfo' instantiate temporary native ShaderModule, the GraphicPipelineConfig + //class implement 'IDisposable' interface to dispose those modules once the pipeline(s) is created. 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. @@ -156,7 +159,8 @@ namespace Triangle { protected override void OnResize () { base.OnResize (); - UpdateView (); + + updateViewRequested = true; frameBuffers?.Dispose(); frameBuffers = pipeline.RenderPass.CreateFrameBuffers(swapChain); diff --git a/vke/src/base/Activable.cs b/vke/src/base/Activable.cs index 1c3d0be..9b746e9 100644 --- a/vke/src/base/Activable.cs +++ b/vke/src/base/Activable.cs @@ -34,7 +34,7 @@ namespace vke { /// The activables that trigger activation only on usage does not require an additional dispose at the end. /// public abstract class Activable : IDisposable { - //count number of activation, only the first one will create a handle + //count number of activation, only the first one will create a handle [XmlIgnore] protected uint references; //keep track of the current state of activation. protected ActivableState state; @@ -75,7 +75,7 @@ namespace vke { VkDebugUtilsObjectNameInfoEXT dmo = DebugUtilsInfo; dmo.pObjectName = name.Pin(); Utils.CheckResult (vkSetDebugUtilsObjectNameEXT (Dev.VkDev, ref dmo)); - name.Unpin (); + name.Unpin (); } /// /// Activation of the object, the reference count is incremented and if Debug utils is enabled, name is set. @@ -84,7 +84,7 @@ namespace vke { references++; if (state == ActivableState.Activated) return; - if (state == ActivableState.Disposed) + if (state == ActivableState.Disposed) GC.ReRegisterForFinalize (this); state = ActivableState.Activated; SetName (name); diff --git a/vke/src/base/DescriptorSetLayout.cs b/vke/src/base/DescriptorSetLayout.cs index d09c4c4..3bcc963 100644 --- a/vke/src/base/DescriptorSetLayout.cs +++ b/vke/src/base/DescriptorSetLayout.cs @@ -13,7 +13,7 @@ namespace vke { /// public sealed class DescriptorSetLayout : Activable { internal VkDescriptorSetLayout handle; - + public VkDescriptorSetLayoutCreateFlags Flags { get; private set; } = 0; public List Bindings { get; private set; } = new List (); @@ -22,7 +22,7 @@ namespace vke { #region CTORS DescriptorSetLayout () : base (null) { } - public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags) : base (device) { + public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags) : base (device) { Flags = flags; } public DescriptorSetLayout (Device device, params VkDescriptorSetLayoutBinding[] bindings) @@ -30,8 +30,8 @@ namespace vke { } public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags, params VkDescriptorSetLayoutBinding[] bindings) : this (device, flags) { - foreach (VkDescriptorSetLayoutBinding b in bindings) - Bindings.Add (b); + foreach (VkDescriptorSetLayoutBinding b in bindings) + Bindings.Add (b); } #endregion diff --git a/vke/src/base/Device.cs b/vke/src/base/Device.cs index 293585d..434a3ab 100644 --- a/vke/src/base/Device.cs +++ b/vke/src/base/Device.cs @@ -161,33 +161,33 @@ namespace vke { // 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 - for (uint i = 0; i < phy.memoryProperties.memoryTypeCount; i++) { - if ((typeBits & 1) == 1) { - if ((phy.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } - } - typeBits >>= 1; - } - - throw new InvalidOperationException ("Could not find a suitable memory type!"); - } - public VkFormat GetSuitableDepthFormat () { - VkFormat[] formats = new VkFormat[] {VkFormat.D32SfloatS8Uint, VkFormat.D32Sfloat, VkFormat.D24UnormS8Uint, VkFormat.D16UnormS8Uint, VkFormat.D16Unorm }; - foreach (VkFormat f in formats) { + // Iterate over all memory types available for the Device used in this example + for (uint i = 0; i < phy.memoryProperties.memoryTypeCount; i++) { + if ((typeBits & 1) == 1) { + if ((phy.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { + return i; + } + } + typeBits >>= 1; + } + + throw new InvalidOperationException ("Could not find a suitable memory type!"); + } + public VkFormat GetSuitableDepthFormat () { + VkFormat[] formats = new VkFormat[] {VkFormat.D32SfloatS8Uint, VkFormat.D32Sfloat, VkFormat.D24UnormS8Uint, VkFormat.D16UnormS8Uint, VkFormat.D16Unorm }; + foreach (VkFormat f in formats) { Console.WriteLine ( (int)phy.GetFormatProperties (f).optimalTilingFeatures); - if (phy.GetFormatProperties (f).optimalTilingFeatures.HasFlag(VkFormatFeatureFlags.DepthStencilAttachment)) - return f; - } - throw new InvalidOperationException ("No suitable depth format found."); - } + if (phy.GetFormatProperties (f).optimalTilingFeatures.HasFlag(VkFormatFeatureFlags.DepthStencilAttachment)) + return f; + } + throw new InvalidOperationException ("No suitable depth format found."); + } /// /// Load compiled SpirvShader. /// /// the vulkan shader module. /// path of the spv shader. - public VkShaderModule CreateShaderModule (string filename) { + public VkShaderModule CreateShaderModule (string filename) { using (Stream stream = Utils.GetStreamFromPath (filename)) { using (BinaryReader br = new BinaryReader (stream)) { byte[] shaderCode = br.ReadBytes ((int)stream.Length); @@ -197,13 +197,13 @@ namespace vke { return shaderModule; } } - }/// - /// Load spirv code from unmanaged native pointer. - /// - /// the vulkan shader module. - /// unmanaged pointer holding the spirv code. Pointer must stay valid only during + }/// + /// Load spirv code from unmanaged native pointer. + /// + /// the vulkan shader module. + /// unmanaged pointer holding the spirv code. Pointer must stay valid only during /// the call to this method. - /// spirv code byte size. + /// spirv code byte size. public VkShaderModule CreateShaderModule (IntPtr code, UIntPtr codeSize) { VkShaderModuleCreateInfo moduleCreateInfo = VkShaderModuleCreateInfo.New (); moduleCreateInfo.codeSize = codeSize; @@ -215,8 +215,8 @@ namespace vke { #region IDisposable Support private bool disposedValue = false; // Pour détecter les appels redondants - protected virtual void Dispose (bool disposing) { - if (!disposedValue) { + protected virtual void Dispose (bool disposing) { + if (!disposedValue) { if (disposing) { #if MEMORY_POOLS resourceManager.Dispose (); @@ -224,21 +224,21 @@ namespace vke { } else System.Diagnostics.Debug.WriteLine ("Device disposed by Finalizer."); - vkDestroyDevice (dev, IntPtr.Zero); + vkDestroyDevice (dev, IntPtr.Zero); - disposedValue = true; - } - } + disposedValue = true; + } + } - ~Device() { - Dispose(false); - } + ~Device() { + Dispose(false); + } - // Ce code est ajouté pour implémenter correctement le modèle supprimable. - public void Dispose () { - Dispose (true); - GC.SuppressFinalize(this); - } + // Ce code est ajouté pour implémenter correctement le modèle supprimable. + public void Dispose () { + Dispose (true); + GC.SuppressFinalize(this); + } #endregion - } + } } diff --git a/vke/src/base/Image.cs b/vke/src/base/Image.cs index 88ab2be..a49c035 100644 --- a/vke/src/base/Image.cs +++ b/vke/src/base/Image.cs @@ -267,13 +267,15 @@ namespace vke { /// Load bitmap into Image with stagging and mipmap generation if necessary /// and usage. /// - public static Image Load (Device dev, Queue staggingQ, CommandPool staggingCmdPool, + public static Image Load (Queue staggingQ, CommandPool staggingCmdPool, string path, VkFormat format = VkFormat.Undefined, VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.DeviceLocal, VkImageTiling tiling = VkImageTiling.Optimal, bool generateMipmaps = true, VkImageType imageType = VkImageType.Image2D, VkImageUsageFlags usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst) { + Device dev = staggingQ.dev; + if (format == VkFormat.Undefined) format = DefaultTextureFormat; if (tiling == VkImageTiling.Optimal) diff --git a/vke/src/base/RenderPass.cs b/vke/src/base/RenderPass.cs index eed45fc..be32781 100644 --- a/vke/src/base/RenderPass.cs +++ b/vke/src/base/RenderPass.cs @@ -10,7 +10,7 @@ using static Vulkan.Vk; namespace vke { public class RenderPass : Activable { - internal VkRenderPass handle; + internal VkRenderPass handle; public readonly VkSampleCountFlags Samples; @@ -36,7 +36,7 @@ namespace vke { /// Create renderpass with a single color attachment and a resolve one if needed /// public RenderPass (Device device, VkFormat colorFormat, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1, VkAttachmentLoadOp loadOp = VkAttachmentLoadOp.Clear) - : this (device) { + : this (device) { Samples = samples; AddAttachment (colorFormat, (samples == VkSampleCountFlags.SampleCount1) ? VkImageLayout.PresentSrcKHR : VkImageLayout.ColorAttachmentOptimal, samples, @@ -143,7 +143,7 @@ namespace vke { stencilStoreOp = VkAttachmentStoreOp.DontCare, initialLayout = initialLayout, finalLayout = finalLayout, - }); + }); } public void AddAttachment (VkFormat format, VkImageLayout finalLayout, VkAttachmentLoadOp stencilLoadOp, @@ -245,12 +245,12 @@ namespace vke { } return fbs; } - + public override string ToString () { return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString("x")}]"); } - + #region IDisposable Support protected override void Dispose (bool disposing) { if (state == ActivableState.Activated) { diff --git a/vke/src/ktx.cs b/vke/src/ktx.cs index 2c38068..28056bd 100644 --- a/vke/src/ktx.cs +++ b/vke/src/ktx.cs @@ -40,7 +40,7 @@ namespace KTX { UInt32 numberOfFaces = br.ReadUInt32 ();//only for cube map, else 1 UInt32 numberOfMipmapLevels = Math.Max (1, br.ReadUInt32 ()); UInt32 bytesOfKeyValueData = br.ReadUInt32 (); - + VkFormat vkFormat = GLHelper.vkGetFormatFromOpenGLInternalFormat (glInternalFormat); if (vkFormat == VkFormat.Undefined) { vkFormat = GLHelper.vkGetFormatFromOpenGLFormat (glFormat, glType); @@ -56,7 +56,7 @@ namespace KTX { if (numberOfMipmapLevels == 1) requestedMipsLevels = (generateMipmaps && phyFormatSupport.HasFlag (VkFormatFeatureFlags.BlitSrc | VkFormatFeatureFlags.BlitDst)) ? (uint)Math.Floor (Math.Log (Math.Max (pixelWidth, pixelHeight))) + 1 : 1 ; - + if (tiling == VkImageTiling.Optimal) usage |= VkImageUsageFlags.TransferDst; if (generateMipmaps) @@ -68,7 +68,7 @@ namespace KTX { (pixelWidth == 0) ? throw new KtxException ("pixelWidth must be > 0") : (pixelHeight == 0) ? imgType = VkImageType.Image1D : (pixelDepth == 1) ? imgType = VkImageType.Image2D : imgType = VkImageType.Image3D; - + VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1; @@ -89,7 +89,7 @@ namespace KTX { img = new Image (staggingQ.Dev, vkFormat, usage, memoryProperty, pixelWidth, pixelHeight, imgType, samples, tiling, requestedMipsLevels, numberOfArrayElements, pixelDepth, createFlags); - + byte[] keyValueDatas = br.ReadBytes ((int)bytesOfKeyValueData); uint blockW, blockH; @@ -98,7 +98,6 @@ namespace KTX { if (memoryProperty.HasFlag (VkMemoryPropertyFlags.DeviceLocal)) { ulong staggingSize = img.AllocatedDeviceMemorySize; - Console.WriteLine ($"KtxStream size = {ktxStream.Length}, img Allocation = {img.AllocatedDeviceMemorySize}"); using (HostBuffer stagging = new HostBuffer (staggingQ.Dev, VkBufferUsageFlags.TransferSrc, staggingSize)) { stagging.Map (); @@ -138,7 +137,7 @@ namespace KTX { //TODO:handle compressed formats for (uint face = 0; face < numberOfFaces; face++) { Marshal.Copy (br.ReadBytes ((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize); - uint faceOffset = imgSize + (imgSize % 4);//cube padding + uint faceOffset = imgSize + (imgSize % 4);//cube padding bufferOffset += faceOffset; } buffCopies.Add (bufferCopyRegion); @@ -156,7 +155,7 @@ namespace KTX { bufferOffset += imgSize; } - if (isCompressed && bufferOffset % blockSize > 0) + if (isCompressed && bufferOffset % blockSize > 0) bufferOffset += blockSize - bufferOffset % blockSize; imgWidth /= 2; @@ -169,7 +168,7 @@ namespace KTX { buffCopies.Unpin (); if (requestedMipsLevels > numberOfMipmapLevels) - img.BuildMipmaps (cmd); + img.BuildMipmaps (cmd); else img.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal, @@ -183,7 +182,8 @@ namespace KTX { cmd.Free (); } - } else { + } else { + throw new NotImplementedException(); } } }