From: Jean-Philippe Bruyère Date: Sun, 2 Feb 2020 16:17:42 +0000 (+0100) Subject: Fence as activable + Fence collection, split glfw bindings in glfw-sharp external... X-Git-Tag: v0.1.21~11 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=d7fa232b16846f4945f1d36695d0eb7b30a01bbe;p=jp%2Fvke.net.git Fence as activable + Fence collection, split glfw bindings in glfw-sharp external project, documentation --- diff --git a/README.md b/README.md index f214c62..aad2315 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,9 @@
adaptation of the gltf PBR sample from Sacha Willems

-**vke.net** (_vulkan engine for .net_) is composed of high level classes encapsulating [vulkan]() objects with `IDispose` model and **reference counting**. [GLFW](https://www.glfw.org/) handles the windowing system. - +**vke.net** (_vulkan engine for .net_) is composed of high level classes encapsulating [vulkan]() objects and commands with `IDispose` model and **reference counting**. [GLFW](https://www.glfw.org/) handles the windowing system. +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. @@ -36,6 +36,39 @@ Use the 'download_datas.sh' script for downloading sample's datas. - [Vulkan Sdk](https://www.lunarg.com/vulkan-sdk/), **glslc** has to be in the path. - optionaly for ui, you will need [vkvg](https://github.com/jpbruyere/vkvg). +### Quick Start + +Create a new dotnet console project, and add the [vje nuget package](https://www.nuget.org/packages/vke) to it. + +```xml + + net472 + Exe + + + + + +``` +For automatic shader compilation to SpirV, add also the [SpirVTasks nuget package](https://www.nuget.org/packages/SpirVTasks/0.1.41-beta). For documentation about this module, follow [this link](SpirVTasks/README.md). + +```xml + + + + + +``` +### Samples + +| Title | Screen shots | +| :----------------------------------: | :------------------------------------------------: | +| [ClearScreen](ClearScreen/README.md) | ![screenshot](samples/screenShots/ClearScreen.png) | +| [Triangle](Triangle/README.md) | ![screenshot](samples/screenShots/Triangle.png) | +| [Textured](Textured/README.md) | ![screenshot](samples/screenShots/Textured.png) | + + + ### Features - physicaly based rendering, direct and deferred diff --git a/addons/DistanceFieldFont/DistanceFieldFont.csproj b/addons/DistanceFieldFont/DistanceFieldFont.csproj index 93faa27..357c696 100644 --- a/addons/DistanceFieldFont/DistanceFieldFont.csproj +++ b/addons/DistanceFieldFont/DistanceFieldFont.csproj @@ -3,10 +3,10 @@ DistanceFieldFont vke.DistanceFieldFont - 0.1.0 + $(VkeReleaseVersion) vke.net signed distance field font addons, BMFont file format vulkan C# vke.net gltf - $(AssemblyVersion)-beta + $(VkePackageVersion) True False https://github.com/jpbruyere/vke.net/blob/master/README.md diff --git a/addons/EnvironmentPipeline/EnvironmentPipeline.csproj b/addons/EnvironmentPipeline/EnvironmentPipeline.csproj index 1344f29..c93c847 100644 --- a/addons/EnvironmentPipeline/EnvironmentPipeline.csproj +++ b/addons/EnvironmentPipeline/EnvironmentPipeline.csproj @@ -3,10 +3,10 @@ EnvironmentPipeline vke.EnvironmentPipeline - 0.1.2 + $(VkeReleaseVersion) vke.net Environment cube pipeline vulkan c# vke.net - $(AssemblyVersion)-beta + $(VkePackageVersion) True False https://github.com/jpbruyere/vke.net/blob/master/README.md diff --git a/addons/VkvgPipeline/VkvgPipeline.csproj b/addons/VkvgPipeline/VkvgPipeline.csproj index 16c1daa..d010f02 100644 --- a/addons/VkvgPipeline/VkvgPipeline.csproj +++ b/addons/VkvgPipeline/VkvgPipeline.csproj @@ -3,10 +3,10 @@ vke.vkvgPipeline vke.vkvgPipeline - 0.1.0 + $(VkeReleaseVersion) CVKL vkvg addons, vectorial drawing with cairo like api. vulkan c# vke.net gltf - $(AssemblyVersion)-beta + $(AssemblyVersion) True False https://github.com/jpbruyere/vk.net/blob/master/README.md diff --git a/addons/gltfLoader/gltfLoader.csproj b/addons/gltfLoader/gltfLoader.csproj index a9474c4..b7940e5 100644 --- a/addons/gltfLoader/gltfLoader.csproj +++ b/addons/gltfLoader/gltfLoader.csproj @@ -3,10 +3,10 @@ vke.gltfLoader vke.gltfLoader - 0.1.8 + $(VkeReleaseVersion) vke.net gltf addons C# vulkan CVKL gltf - $(AssemblyVersion)-beta + $(AssemblyVersion) True False https://github.com/jpbruyere/vke.net/blob/master/README.md diff --git a/samples/ClearScreen/ClearScreen.csproj b/samples/ClearScreen/ClearScreen.csproj new file mode 100644 index 0000000..3cf0386 --- /dev/null +++ b/samples/ClearScreen/ClearScreen.csproj @@ -0,0 +1,5 @@ + + + false + + diff --git a/samples/ClearScreen/README.md b/samples/ClearScreen/README.md new file mode 100644 index 0000000..dc9f101 --- /dev/null +++ b/samples/ClearScreen/README.md @@ -0,0 +1,91 @@ +### The Project File. + +To build a minimal vulkan application, add the [vke](https://www.nuget.org/packages/vke/) nuget package, and to enable automatic shader compilation, add the [SpirVTasks](https://www.nuget.org/packages/SpirVTasks/) package and a generic **GLSLShader** item globing a full directory. + +```xml + + net472 + Exe + + + + + + + + + +``` + +### VkWindow class + +**vke** use [GLFW](https://www.glfw.org/) to interface with the windowing system of the OS. Derive your application from the `VkWindow` base class to start with a vulkan enabled window. **Validation** and **RenderDoc** layers loading may be control at startup with public static boolean properties from the `Instance`class. + +```csharp +class Program : VkWindow { + static void Main (string[] args) { + using (Program vke = new Program ()) { + vke.Run (); + } + } +} +``` + +### Vulkan Initialization + +`init_vulkan` is the first method called by the 'Run' method. Default initialization will provide a vulkan window, a default swap chain bound to it, and a draw and present semaphore to sync the rendering. +```csharp +protected override void initVulkan () { + base.initVulkan (); +``` +There are several method to clear the screen with vulkan. One is to use the renderpass CLEAR load operation so that attachment layout transitioning is handled automatically by the render pass. +```csharp + renderPass = new RenderPass (dev, swapChain.ColorFormat); + renderPass.ClearValues[0] = new VkClearValue (0.1f, 0.2f, 1); + renderPass.Activate (); + + cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount); +} +``` + +Note that because we only reset the command buffers when rebuilding these, we need to preallocate them during the initialization. + +### Frame buffer creation + +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 frame buffers. vke provide a FrameBuffer collection object to ease handling of multiple related buffers like those used for a swap chain for example.. +```csharp +FrameBuffers frameBuffers; + +protected override void OnResize () { + base.OnResize (); + + frameBuffers?.Dispose(); + frameBuffers = renderPass.CreateFrameBuffers(swapChain); + + buildCommandBuffers (); +} +``` +It's common to rebuild the command buffers targeting the swap chain images after a resize so that the drawing is scaled. So it's a good idea to build/rebuild your commands here. + + + +### 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. +Here we simply record a begin/end render pass to clear the screen with the load operation of it. + +```csharp +void buildCommandBuffers() { + cmdPool.Reset (VkCommandPoolResetFlags.ReleaseResources); + + for (int i = 0; i < swapChain.ImageCount; ++i) { + cmds[i].Start (); + + renderPass.Begin (cmds[i], frameBuffers[i]); + + renderPass.End (cmds[i]); + + cmds[i].End (); + } +} +``` diff --git a/samples/ClearScreen/main.cs b/samples/ClearScreen/main.cs new file mode 100644 index 0000000..3e11384 --- /dev/null +++ b/samples/ClearScreen/main.cs @@ -0,0 +1,78 @@ +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using vke; +using Vulkan; + +//Most simple example of the `VkWindow` class usage to output something on screen. +namespace ClearScreen { + class Program : VkWindow { + //excutable entry point + static void Main (string[] args) { + //the base constructor will create the window with GLFW + using (Program vke = new Program ()) { + vke.Run (); + } + } + + //frame buffer collection to handle on fb per swapchain image. + FrameBuffers frameBuffers; + RenderPass renderPass; + + //Vulkan initialization is the first method called by the 'Run' method. + //Default initialization will provide a vulkan window, a default swapchain + //bound to it, and a draw and present semaphore to sync the rendering. + protected override void initVulkan () { + base.initVulkan (); + + //there are several method to clear the screen with vulkan. One is to + //use the renderpass CLEAR load operation so that attachment layout transitioning + //is handled automatically by the render pass. + renderPass = new RenderPass (dev, swapChain.ColorFormat); + //default clear values are automatically added for each attacments + renderPass.ClearValues[0] = new VkClearValue (0.1f, 0.2f, 1); + //bound to a pipeline, renderpasses are automatically activated, here we use + //a stand alone renderpass just to clear the screen, so we have to + //activate it manually + renderPass.Activate (); + + //allocate default cmd buffers of the VkWindow class. + cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount); + } + + void buildCommandBuffers() { + cmdPool.Reset (); + + for (int i = 0; i < swapChain.ImageCount; ++i) { + FrameBuffer fb = frameBuffers[i]; + cmds[i].Start (); + + renderPass.Begin (cmds[i], fb); + renderPass.End (cmds[i]); + + cmds[i].End (); + } + } + + //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 + //frame buffers. + protected override void OnResize () { + base.OnResize (); + + frameBuffers?.Dispose(); + frameBuffers = renderPass.CreateFrameBuffers(swapChain); + + buildCommandBuffers (); + } + //clean up + protected override void Dispose (bool disposing) { + dev.WaitIdle (); + + renderPass.Dispose (); + frameBuffers?.Dispose(); + + base.Dispose (disposing); + } + } +} diff --git a/samples/Textured/README.md b/samples/Textured/README.md new file mode 100644 index 0000000..331e752 --- /dev/null +++ b/samples/Textured/README.md @@ -0,0 +1,25 @@ +### Enabling extensions + +The `VkWindow` class provides two properties that you may override to enable additional extensions. + +### Enabling features + +Override the `configureEnabledFeatures` method of `VkWindow` to enable features. +```csharp +protected override void configureEnabledFeatures ( + VkPhysicalDeviceFeatures available_features, + ref VkPhysicalDeviceFeatures enabled_features) +{ + enabled_features.samplerAnisotropy = available_features.samplerAnisotropy; +} +``` +### Creating queues + +To create queues, override the `createQueues` method of `VkWindow`. This function is called before the logical device creation and will take care of physically available queues, creating duplicates if count exceed availability. The `base` method will create a default presentable queue. + +```csharp +protected override void createQueues () { + base.createQueues (); + transferQ = new Queue (dev, VkQueueFlags.Transfer); +} +``` \ No newline at end of file diff --git a/samples/Textured/Textured.csproj b/samples/Textured/Textured.csproj index bd178d8..35e3d84 100644 --- a/samples/Textured/Textured.csproj +++ b/samples/Textured/Textured.csproj @@ -1,6 +1,2 @@ - - - - diff --git a/samples/Textured/main.cs b/samples/Textured/main.cs index fb671bb..78da387 100644 --- a/samples/Textured/main.cs +++ b/samples/Textured/main.cs @@ -13,7 +13,6 @@ namespace Textured { static void Main (string[] args) { #if DEBUG Instance.VALIDATION = true; - Instance.RENDER_DOC_CAPTURE = true; #endif using (Program vke = new Program ()) { vke.Run (); @@ -234,9 +233,10 @@ namespace Textured { } protected override void Dispose (bool disposing) { + dev.WaitIdle (); + if (disposing) { if (!isDisposed) { - dev.WaitIdle (); pipeline.Dispose (); dsLayout.Dispose (); frameBuffers.Dispose(); diff --git a/samples/Triangle/README.md b/samples/Triangle/README.md index 07c2895..436391f 100644 --- a/samples/Triangle/README.md +++ b/samples/Triangle/README.md @@ -1,92 +1,60 @@ -### The Project File. +### Creating buffers -To build a minimal vulkan application, add the [vke](https://www.nuget.org/packages/vke/) nuget package, and to enable automatic shader compilation, add the [SpirVTasks](https://www.nuget.org/packages/SpirVTasks/) package and a generic **GLSLShader** item globing a full directory. - -```xml - - net472 - Exe - - - - - - - - +Vke has two classes to handle buffers. Mappable [`HostBuffer`](../../wiki/api/HostBuffer) and device only [`GPUBuffer`](../../wiki/api/GPUBuffer). +For this first simple example, we will only use host mappable buffers. Those classes can handle a Generic argument of a blittable type to handle arrays. Resources like buffers or images are automatically activated, so they need to be explicitly disposed on cleanup. Create them in the `initVulkan` override. +```csharp + //the vertex buffer + vbo = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vertices); + //the index buffer + ibo = new HostBuffer (dev, VkBufferUsageFlags.IndexBuffer, indices); + //a permanantly mapped buffer for the mvp matrice + uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, mvp, true); ``` -### VkWindow class - -**vke** use [GLFW](https://www.glfw.org/) to interface with the windowing system of the OS. Derive your application from the `VkWindow` base class to start with a vulkan enabled window. **Validation** and **RenderDoc** layers loading may be control at startup with public static boolean properties from the `Instance`class. - +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 -class Program : VkWindow { - static void Main (string[] args) { - Instance.VALIDATION = true; - using (Program vke = new Program ()) { - vke.Run (); - } - } -} + descriptorPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer)); ``` -### Vulkan Initialization - -Default vulkan initialization of the VkWindow class will provide the minimal for running and present simple command buffers. For further initialization steps, override the `init_vulkan`method. - +Graphic pipeline configuration are predefined by the [`GraphicPipelineConfig`](../../wiki/api/GraphicPipelineConfig) class, which ease sharing configs for several pipelines having lots in common. The pipeline layout will be automatically activated on pipeline creation, so that sharing layout among different pipelines will benefit from the reference counting to automatically dispose unused layout on pipeline clean up. It's the same for [`DescriptorSetLayout`](../../wiki/api/DescriptorSetLayout). ```csharp -protected override void initVulkan () { - base.initVulkan (); - vbo = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vertices); - ibo = new HostBuffer (dev, VkBufferUsageFlags.IndexBuffer, indices); - uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices); - ... +GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault ( + VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); + +cfg.Layout = new PipelineLayout (dev, + new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding ( + 0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer))); ``` -### Enabling extensions - -The `VkWindow` class provides two properties that you may override to enable additional extensions. The `Ext` static class of the vulkan package provides up to date lists of existing vulkan extensions for convenience. - +Next we configure a default [`RenderPass`](../../wiki/api/RenderPass) with just a color attachment for the swap chain image, a default sub-pass is automatically created and the render pass activation will follow the pipeline life cycle and will be automatically disposed when no longer in use. ```csharp -public virtual string[] EnabledInstanceExtensions => null; -public virtual string[] EnabledDeviceExtensions => - new string[] { Ext.D.VK_KHR_swapchain }; + cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, cfg.Samples); ``` - -### Enabling features - -Override the `configureEnabledFeatures` method of `VkWindow` to enable features. Available features queried from the selected physical device are provided as argument. +Configuration of vertex bindings and attributes ```csharp -protected override void configureEnabledFeatures ( - VkPhysicalDeviceFeatures available_features, - ref VkPhysicalDeviceFeatures enabled_features) { - - enabled_features.samplerAnisotropy = available_features.samplerAnisotropy; -} + cfg.AddVertexBinding (0); + cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, //position + VkFormat.R32g32b32Sfloat);//color ``` -### Creating queues - -To create queues, override the `createQueues` method of `VkWindow`. This function is called before the logical device creation and will take care of physically available queues, creating duplicates if count exceed availability. The `base` method will create a default presentable queue. - +shader are automatically compiled by [`SpirVTacks`](../../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 -protected override void createQueues () { - base.createQueues (); - transferQ = new Queue (dev, VkQueueFlags.Transfer); -} + cfg.AddShader (VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "#shaders.main.frag.spv"); ``` -### Rendering - -VkWindow will provide the default swapchain, but it's up to you to create the frame buffers. For the triangle example, create them in the `OnResize` override. The `RenderPass` class has the ability to create a framebuffer collection for a given swapchain. The `OnResize` method is guarantied to be called once before entering the rendering loop, so that it is a safe place to call the building of your command buffers. +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 -FrameBuffers frameBuffers; - -protected override void OnResize () { - base.OnResize (); - - frameBuffers?.Dispose(); - frameBuffers = pipeline.RenderPass.CreateFrameBuffers(swapChain); - - buildCommandBuffers (); -} + pipeline = new GraphicPipeline (cfg); +``` +Because descriptor layouts used for a pipeline are only activated on pipeline activation, descriptor sets must not be allocated before, except if the layout has been manually activated, but in this case, layouts will also need to be explicitly disposed. +```csharp + descriptorSet = descriptorPool.Allocate (pipeline.Layout.DescriptorSetLayouts[0]); ``` +The descriptor update is a two step operation. First we create a [`DescriptorSetWrites`](../../wiki/api/DescriptorSetWrites) object defining the layout(s), than we write the descriptor(s). +The `Descriptor` property of the mvp HostBuffer will return a default descriptor with no offset of the full size of the buffer. +```csharp + DescriptorSetWrites uboUpdate = + new DescriptorSetWrites (descriptorSet, pipeline.Layout.DescriptorSetLayouts[0]); + + uboUpdate.Write (dev, uboMats.Descriptor); +``` diff --git a/samples/Triangle/main.cs b/samples/Triangle/main.cs index e9b1996..70d771c 100644 --- a/samples/Triangle/main.cs +++ b/samples/Triangle/main.cs @@ -1,14 +1,12 @@ // Copyright (c) 2019 Jean-Philippe Bruyère // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -using System; -using System.IO; using System.Numerics; using System.Runtime.InteropServices; -using System.Xml.Serialization; using vke; using Vulkan; +//the traditional triangle sample namespace Triangle { class Program : VkWindow { static void Main (string[] args) { @@ -18,15 +16,9 @@ namespace Triangle { } const float rotSpeed = 0.01f, zoomSpeed = 0.01f; - float rotX, rotY, rotZ = 0f, zoom = 1f; - - [StructLayout (LayoutKind.Sequential)] - struct Matrices { - public Matrix4x4 projection; - public Matrix4x4 view; - public Matrix4x4 model; - } + float rotX, rotY, zoom = 1f; + //vertex structure [StructLayout(LayoutKind.Sequential)] struct Vertex { Vector3 position; @@ -38,18 +30,19 @@ namespace Triangle { } } - Matrices matrices; + Matrix4x4 mvp; //the model view projection matrix - HostBuffer ibo; - HostBuffer vbo; - HostBuffer uboMats; + 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; + DescriptorSet descriptorSet;//descriptor set for the mvp matrice. - FrameBuffers frameBuffers; - GraphicPipeline pipeline; + 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), @@ -57,57 +50,63 @@ namespace Triangle { }; ushort[] indices = new ushort[] { 0, 1, 2 }; - Program () : base () {} - protected override void initVulkan () { base.initVulkan (); + //first create the needed buffers vbo = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vertices); ibo = new HostBuffer (dev, VkBufferUsageFlags.IndexBuffer, indices); - uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices); + //because mvp matrice may be updated by mouse move, we keep it mapped after creation. + uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, mvp, true); + //a descriptor pool to allocate the mvp matrice descriptor from. descriptorPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer)); + //Graphic pipeline configuration are predefined by the GraphicPipelineConfig class, which ease sharing config for several pipelines having lots in common. GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.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 | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer))); - + new DescriptorSetLayout (dev, new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer))); + //create a default renderpass with just a color attachment for the swapchain image, a default subpass is automatically created and the renderpass activation + //will follow the pipeline life cicle and will be automatically disposed when no longuer used. cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, cfg.Samples); + //configuration of vertex bindings and attributes cfg.AddVertexBinding (0); - cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat); + cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat);//position + color + //shader are automatically compiled by SpirVTacks 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.AddShader (VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"); cfg.AddShader (VkShaderStageFlags.Fragment, "#shaders.main.frag.spv"); + //create and activate the pipeline with the configuration we've just done. pipeline = new GraphicPipeline (cfg); - //note that descriptor set is allocated after the pipeline creation that use this layout, layout is activated - //automaticaly on pipeline creation, and will be disposed automatically when no longuer in use. + //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); - uboMats.Map (); - + //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 () { - matrices.projection = Utils.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (45f), - (float)swapChain.Width / (float)swapChain.Height, 0.1f, 256.0f); - matrices.view = - Matrix4x4.CreateFromAxisAngle (Vector3.UnitZ, rotZ) * + mvp = Matrix4x4.CreateFromAxisAngle (Vector3.UnitY, rotY) * Matrix4x4.CreateFromAxisAngle (Vector3.UnitX, rotX) * - Matrix4x4.CreateTranslation (0, 0, -3f * zoom); - matrices.model = Matrix4x4.Identity; - uboMats.Update (matrices, (uint)Marshal.SizeOf ()); - updateViewRequested = false; - } + Matrix4x4.CreateTranslation (0, 0, -3f * zoom) * + Utils.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (45f), (float)swapChain.Width / (float)swapChain.Height, 0.1f, 256.0f); + uboMats.Update (mvp, (uint)Marshal.SizeOf ()); + base.UpdateView (); + } protected override void onMouseMove (double xPos, double yPos) { double diffX = lastMouseX - xPos; double diffY = lastMouseY - yPos; @@ -118,6 +117,8 @@ namespace Triangle { zoom += zoomSpeed * (float)diffY; } else return; + //VkWindow has a boolean for requesting a call to 'UpdateView', it will be + //reset by the 'UpdateView' base method or the custom override. updateViewRequested = true; } @@ -156,15 +157,18 @@ namespace Triangle { 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 (); diff --git a/samples/Triangle/shaders/main.vert b/samples/Triangle/shaders/main.vert index 542d015..0997ca9 100644 --- a/samples/Triangle/shaders/main.vert +++ b/samples/Triangle/shaders/main.vert @@ -8,10 +8,8 @@ layout (location = 1) in vec3 inColor; layout (binding = 0) uniform UBO { - mat4 projectionMatrix; - mat4 viewMatrix; - mat4 modelMatrix; -} ubo; + mat4 mvp; +}; layout (location = 0) out vec3 outColor; @@ -24,7 +22,5 @@ out gl_PerVertex void main() { outColor = inColor; - gl_Position = ubo.projectionMatrix * ubo.viewMatrix * ubo.modelMatrix * vec4(inPos.xyz, 1.0); - //gl_Position.y = -gl_Position.y; - //gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0; + gl_Position = mvp * vec4(inPos.xyz, 1.0); } diff --git a/samples/screenShots/ClearScreen.png b/samples/screenShots/ClearScreen.png new file mode 100644 index 0000000..c80d070 Binary files /dev/null and b/samples/screenShots/ClearScreen.png differ diff --git a/samples/screenShots/Textured.png b/samples/screenShots/Textured.png new file mode 100644 index 0000000..871f353 Binary files /dev/null and b/samples/screenShots/Textured.png differ diff --git a/samples/screenShots/Triangle.png b/samples/screenShots/Triangle.png new file mode 100644 index 0000000..0340b56 Binary files /dev/null and b/samples/screenShots/Triangle.png differ diff --git a/vke.net.sln b/vke.net.sln index 1ce579e..f8baa1e 100644 --- a/vke.net.sln +++ b/vke.net.sln @@ -8,11 +8,12 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "global", "global", "{7285454A-930F-4536-AB84-C076B44C0C80}" ProjectSection(SolutionItems) = preProject Directory.Build.props = Directory.Build.props + README.md = README.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "addons", "addons", "{4AA67AB0-C331-4CB2-9C00-B74F5DE31658}" ProjectSection(SolutionItems) = preProject - addons/Directory.Build.props = "Directory.Build.props" + addons\Directory.Build.props = addons\Directory.Build.props EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvironmentPipeline", "addons\EnvironmentPipeline\EnvironmentPipeline.csproj", "{F04C3F79-2E08-4D35-A804-43039DCB7F5E}" @@ -25,9 +26,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VkvgPipeline", "addons\Vkvg EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{16439374-B8DB-4643-8116-EB3358B49A12}" ProjectSection(SolutionItems) = preProject - samples/Directory.Build.props = "Directory.Build.props" + samples\Directory.Build.props = samples\Directory.Build.props EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClearScreen", "samples\ClearScreen\ClearScreen.csproj", "{1D2A1968-8F04-4BE0-B03A-573F1F68AB66}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Triangle", "samples\Triangle\Triangle.csproj", "{124152F8-FAE6-4D4B-87B9-6074DD365E9B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Textured", "samples\Textured\Textured.csproj", "{1B2DF710-E500-49E5-8802-EBA71A05E827}" @@ -159,6 +162,16 @@ Global {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.Release|Any CPU.Build.0 = Release|Any CPU {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.Release|Any CPU.Build.0 = Release|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.BuildPackages|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {FEF3AF30-5B88-4D3C-8BD7-8734200E0D1E} = {4AA67AB0-C331-4CB2-9C00-B74F5DE31658} @@ -173,6 +186,7 @@ Global {D9A41382-444E-44ED-B638-3D8F06F2FBC2} = {16439374-B8DB-4643-8116-EB3358B49A12} {124152F8-FAE6-4D4B-87B9-6074DD365E9B} = {16439374-B8DB-4643-8116-EB3358B49A12} {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5} = {16439374-B8DB-4643-8116-EB3358B49A12} + {1D2A1968-8F04-4BE0-B03A-573F1F68AB66} = {16439374-B8DB-4643-8116-EB3358B49A12} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 diff --git a/vke/src/VkWindow.cs b/vke/src/VkWindow.cs index e2e2fb4..acb23eb 100644 --- a/vke/src/VkWindow.cs +++ b/vke/src/VkWindow.cs @@ -35,7 +35,7 @@ namespace vke { protected CommandPool cmdPool; protected CommandBuffer[] cmds; protected VkSemaphore[] drawComplete; - protected VkFence drawFence; + protected Fence drawFence; protected uint fps { get; private set; } protected bool updateViewRequested = true; @@ -173,7 +173,7 @@ namespace vke { cmds = new CommandBuffer[swapChain.ImageCount]; drawComplete = new VkSemaphore[swapChain.ImageCount]; - drawFence = dev.CreateFence (true); + drawFence = new Fence (dev, true, "draw fence"); for (int i = 0; i < swapChain.ImageCount; i++) { drawComplete[i] = dev.CreateSemaphore (); @@ -218,8 +218,8 @@ namespace vke { if (cmds[idx] == null) return; - dev.WaitForFence (drawFence); - dev.ResetFence (drawFence); + drawFence.Wait (); + drawFence.Reset (); presentQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx], drawFence); presentQueue.Present (swapChain, drawComplete[idx]); @@ -393,8 +393,7 @@ namespace vke { dev.DestroySemaphore (drawComplete[i]); cmds[i].Free (); } - dev.DestroyFence (drawFence); - + drawFence.Dispose (); swapChain.Dispose (); vkDestroySurfaceKHR (instance.Handle, hSurf, IntPtr.Zero); diff --git a/vke/src/base/Activable.cs b/vke/src/base/Activable.cs index 5fc2a99..2f7edf5 100644 --- a/vke/src/base/Activable.cs +++ b/vke/src/base/Activable.cs @@ -41,7 +41,8 @@ namespace vke { //With the debug utils extension, setting name to vulkan's object ease the debugging. protected string name; /// - /// This property has to be implemented in every vulkan object. It must return the correct debug marker info. + /// This property has to be implemented in every vulkan object. It must return the correct debug marker info to use + /// if VK_EXT_debug_utils extension is enabled. /// /// The debug marker info. protected abstract VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo { get; } @@ -52,11 +53,11 @@ namespace vke { #region CTOR protected Activable (Device dev) { - this.Dev = dev; - this.name = GetType ().Name; + Dev = dev; + name = GetType ().Name; } protected Activable (Device dev, string name) { - this.Dev = dev; + Dev = dev; this.name = name; } #endregion @@ -76,7 +77,7 @@ namespace vke { name.Unpin (); } /// - /// Activation of the object, the reference count is incremented. + /// Activation of the object, the reference count is incremented and if Debug utils is enabled, name is set. /// public virtual void Activate () { references++; diff --git a/vke/src/base/Buffer.cs b/vke/src/base/Buffer.cs index 9a86f14..aa25004 100644 --- a/vke/src/base/Buffer.cs +++ b/vke/src/base/Buffer.cs @@ -7,33 +7,45 @@ using static Vulkan.Vk; namespace vke { - /// - /// Base class for HostBuffer and GPUBuffer - /// - public class Buffer : Resource { - internal VkBuffer handle; + /// + /// Base class for managed vulkan buffer objects + /// + public class Buffer : Resource { + internal VkBuffer handle; protected VkBufferCreateInfo createInfo = VkBufferCreateInfo.New (); - - public VkDescriptorBufferInfo Descriptor; + /// Native handle of this vulkan buffer. + /// The handle. public VkBuffer Handle => handle; public VkBufferCreateInfo Infos => createInfo; + /// Buffer memory is always linear. public override bool IsLinar => true; protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo => new VkDebugUtilsObjectNameInfoEXT (VkObjectType.Buffer, handle.Handle); #region CTORS - public Buffer (Device device, VkBufferUsageFlags usage, VkMemoryPropertyFlags _memoryPropertyFlags, UInt64 size) - : base (device, _memoryPropertyFlags) { - - createInfo.size = size; - createInfo.usage = usage; - createInfo.sharingMode = VkSharingMode.Exclusive; - - Activate ();//DONT OVERRIDE Activate in derived classes!!!! - } + /// + /// Create a vulkan buffer and automatically activate it. Automatic activation on startup implies to explicitly dispose the buffer. + /// + /// Logical Device. + /// a bitmask specifying allowed usages of the buffer + /// Memory property flags. + /// Desired size in byte of the buffer to be created. + /// value specifying the sharing mode of the buffer when it will be accessed by multiple queue familie + public Buffer (Device device, VkBufferUsageFlags usage, VkMemoryPropertyFlags _memoryPropertyFlags, UInt64 size, VkSharingMode sharingMode = VkSharingMode.Exclusive) + : base (device, _memoryPropertyFlags) { + + createInfo.size = size; + createInfo.usage = usage; + createInfo.sharingMode = VkSharingMode.Exclusive; + + Activate (); + } #endregion - public override void Activate () { + /// + /// Activate this vulkan buffer. Note that buffers are automatically activated on creation. + /// + public sealed override void Activate () { if (state != ActivableState.Activated) { Utils.CheckResult (vkCreateBuffer (Dev.VkDev, ref createInfo, IntPtr.Zero, out handle)); #if MEMORY_POOLS @@ -43,11 +55,11 @@ namespace vke { allocateMemory (); bindMemory (); #endif - SetupDescriptor (); } base.Activate (); - } + } + #region Implement abstract members of the Resource abstract class. internal override void updateMemoryRequirements () { vkGetBufferMemoryRequirements (Dev.VkDev, handle, out memReqs); } @@ -59,49 +71,84 @@ namespace vke { Utils.CheckResult (vkBindBufferMemory (Dev.VkDev, handle, vkMemory, 0)); #endif } + #endregion - public void SetupDescriptor (ulong size = WholeSize, ulong offset = 0) { - Descriptor.buffer = handle; - Descriptor.range = size; - Descriptor.offset = offset; - } - - public void CopyTo (CommandBuffer cmd, Image img, VkImageLayout finalLayout = VkImageLayout.ShaderReadOnlyOptimal) { - img.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal); - - VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy { - imageExtent = img.CreateInfo.extent, - imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color) - }; - - vkCmdCopyBufferToImage (cmd.Handle, handle, img.handle, VkImageLayout.TransferDstOptimal, 1, ref bufferCopyRegion); + /// + /// Get a default buffer descriptor for the full size with no offset. + /// + /// the vulkan buffer descriptor + public VkDescriptorBufferInfo Descriptor { get => GetDescriptor (); } + /// + /// Get a buffer descriptor. + /// + /// a vulkan buffer descriptor + /// Size in byte of the buffer view + /// an offset in the buffer memory at which point this descriptor. + public VkDescriptorBufferInfo GetDescriptor (ulong size = WholeSize, ulong offset = 0) => + new VkDescriptorBufferInfo { buffer = handle, range = size, offset = offset }; + + /// + /// Copy a vulkan buffer to an Image. + /// + /// a command buffer to handle the operation. + /// The Image to copy the buffer to. + /// The final layout to setup for the destination image. + public void CopyTo (CommandBuffer cmd, Image img, VkImageLayout finalLayout = VkImageLayout.ShaderReadOnlyOptimal) { + img.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal); + + VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy { + imageExtent = img.CreateInfo.extent, + imageSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color) + }; + + vkCmdCopyBufferToImage (cmd.Handle, handle, img.handle, VkImageLayout.TransferDstOptimal, 1, ref bufferCopyRegion); img.SetLayout (cmd, VkImageAspectFlags.Color, finalLayout); } - public void CopyTo (CommandBuffer cmd, Buffer buff, ulong size = 0, ulong srcOffset = 0, ulong dstOffset = 0) { - VkBufferCopy bufferCopy = new VkBufferCopy { - size = (size == 0) ? AllocatedDeviceMemorySize : size, - srcOffset = srcOffset, - dstOffset = dstOffset - }; - vkCmdCopyBuffer (cmd.Handle, handle, buff.handle, 1, ref bufferCopy); - } + /// + /// Copy a vulkan buffer to another buffer. + /// + /// a command buffer to handle the operation. + /// the destination buffer. + /// size of the copy operation in byte. + /// a source offset for the copy operation. + /// an offset in the destination buffer for the copy operation. + public void CopyTo (CommandBuffer cmd, Buffer buff, ulong size = 0, ulong srcOffset = 0, ulong dstOffset = 0) { + VkBufferCopy bufferCopy = new VkBufferCopy { + size = (size == 0) ? AllocatedDeviceMemorySize : size, + srcOffset = srcOffset, + dstOffset = dstOffset + }; + vkCmdCopyBuffer (cmd.Handle, handle, buff.handle, 1, ref bufferCopy); + } + /// + /// Fill a vulkan buffer memory with an unsinged integer value. + /// + /// a command buffer to handle the operation. + /// an unsigned integer to fill the buffer with. + /// size in byte to fill. + /// an offset in byte in the buffer for the fill operation. public void Fill (CommandBuffer cmd, uint data, ulong size = 0, ulong offset = 0) { vkCmdFillBuffer (cmd.Handle, handle, offset, (size == 0) ? AllocatedDeviceMemorySize : size, data); } public override string ToString () { - return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString("x")}]"); + return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString ("x")}]"); } -#region IDisposable Support + #region IDisposable Support + /// + /// Destroy the native handle and set the Activable's state to `Disposed`. + /// + /// Note that Buffers have to be always explicitly disposed on cleanup. + /// If set to true, this object is currently disposed by the user, not the finalizer. protected override void Dispose (bool disposing) { if (state == ActivableState.Activated) { base.Dispose (disposing); vkDestroyBuffer (Dev.VkDev, handle, IntPtr.Zero); } state = ActivableState.Disposed; - } -#endregion + } + #endregion } } diff --git a/vke/src/base/CommandBuffer.cs b/vke/src/base/CommandBuffer.cs index 9c65dc1..ef85867 100644 --- a/vke/src/base/CommandBuffer.cs +++ b/vke/src/base/CommandBuffer.cs @@ -33,8 +33,14 @@ namespace vke { //State = States.Init; } - - public void Submit (VkQueue queue, VkSemaphore wait = default(VkSemaphore), VkSemaphore signal = default (VkSemaphore), VkFence fence = default(VkFence)) { + /// + /// Submit an executable command buffer with optional wait and signal semaphores, and an optional fence to be signaled when the commands have been completed. + /// + /// Queue. + /// Wait. + /// Signal. + /// Fence. + public void Submit (VkQueue queue, VkSemaphore wait = default, VkSemaphore signal = default, Fence fence = null) { VkSubmitInfo submit_info = VkSubmitInfo.New(); IntPtr dstStageMask = Marshal.AllocHGlobal (sizeof(uint)); @@ -58,10 +64,17 @@ namespace vke { } Marshal.FreeHGlobal (dstStageMask); } + /// + /// Put the command buffer in the recording state. + /// + /// optional command buffer usage flags. public void Start (VkCommandBufferUsageFlags usage = 0) { VkCommandBufferBeginInfo cmdBufInfo = new VkCommandBufferBeginInfo (usage); Utils.CheckResult (vkBeginCommandBuffer (handle, ref cmdBufInfo)); } + /// + /// Put the command buffer in the executable state if no errors are present in the recording. + /// public void End () { Utils.CheckResult (vkEndCommandBuffer (handle)); } diff --git a/vke/src/base/DescriptorPool.cs b/vke/src/base/DescriptorPool.cs index 26339f5..2970257 100644 --- a/vke/src/base/DescriptorPool.cs +++ b/vke/src/base/DescriptorPool.cs @@ -3,7 +3,6 @@ // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; using System.Collections.Generic; -using System.Xml.Serialization; using Vulkan; using static Vulkan.Vk; @@ -11,20 +10,28 @@ namespace vke { [Serializable] public sealed class DescriptorPool : Activable { internal VkDescriptorPool handle; - [XmlAttribute] public uint MaxSets; - [XmlArrayItem("PoolSize")] - - public List PoolSizes = new List (); + public List PoolSizes { get; private set; } = new List (); protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo => new VkDebugUtilsObjectNameInfoEXT (VkObjectType.DescriptorPool, handle.Handle); #region CTORS DescriptorPool () : base (null) {} + /// + /// Create a new managed descriptor pool that will be manualy activated after the pool sizes had been populated. + /// + /// the logical device that create the pool. + /// maximum number of descriptor sets that can be allocated from the pool public DescriptorPool (Device device, uint maxSets = 1) : base (device) { MaxSets = maxSets; } + /// + /// Create and automatically activate a new Descriptor pool with the supplied pool sizes. + /// + /// the logical device that create the pool. + /// maximum number of descriptor sets that can be allocated from the pool + /// an array of pool sizes describing descriptor types and counts public DescriptorPool (Device device, uint maxSets = 1, params VkDescriptorPoolSize[] poolSizes) : this (device, maxSets) { @@ -34,7 +41,7 @@ namespace vke { } #endregion - public override void Activate () { + public sealed override void Activate () { if (state != ActivableState.Activated) { VkDescriptorPoolCreateInfo info = VkDescriptorPoolCreateInfo.New(); info.poolSizeCount = (uint)PoolSizes.Count; @@ -46,11 +53,12 @@ namespace vke { } base.Activate (); } - - /// - /// Create and allocate a new DescriptorSet - /// - public DescriptorSet Allocate (params DescriptorSetLayout[] layouts) { + /// + /// Allocate a new DescriptorSet from this pool. + /// + /// A managed descriptor set. + /// a variable sized array of descriptor layout(s) to allocate the descriptor for. + public DescriptorSet Allocate (params DescriptorSetLayout[] layouts) { DescriptorSet ds = new DescriptorSet (this, layouts); Allocate (ds); return ds; diff --git a/vke/src/base/DescriptorSet.cs b/vke/src/base/DescriptorSet.cs index 80c583d..8df8be5 100644 --- a/vke/src/base/DescriptorSet.cs +++ b/vke/src/base/DescriptorSet.cs @@ -3,7 +3,7 @@ // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System.Collections.Generic; using Vulkan; - +//TODO: namespace vke { public class DescriptorSet { internal VkDescriptorSet handle; diff --git a/vke/src/base/Device.cs b/vke/src/base/Device.cs index 56e38fe..65aff0f 100644 --- a/vke/src/base/Device.cs +++ b/vke/src/base/Device.cs @@ -97,7 +97,10 @@ namespace vke { resourceManager = new ResourceManager (this); #endif } - + /// + /// Creates a new semaphore. + /// + /// The semaphore native handle public VkSemaphore CreateSemaphore () { VkSemaphore tmp; VkSemaphoreCreateInfo info = VkSemaphoreCreateInfo.New (); @@ -108,38 +111,14 @@ namespace vke { vkDestroySemaphore (dev, semaphore, IntPtr.Zero); semaphore = 0; } - public VkFence CreateFence (bool signaled = false) { - VkFence tmp; - VkFenceCreateInfo info = VkFenceCreateInfo.New (); - info.flags = signaled ? VkFenceCreateFlags.Signaled : 0; - Utils.CheckResult (vkCreateFence (dev, ref info, IntPtr.Zero, out tmp)); - return tmp; - } - /// Destroy the fence. - /// A valid fence handle. - public void DestroyFence (VkFence fence) { - vkDestroyFence (dev, fence, IntPtr.Zero); - fence = 0; - } - public void WaitForFence (VkFence fence, ulong timeOut = UInt64.MaxValue) { - vkWaitForFences (dev, 1, ref fence, 1, timeOut); - } - public void ResetFence (VkFence fence) { - vkResetFences (dev, 1, ref fence); - } - public void WaitForFences (VkFence[] fences, ulong timeOut = UInt64.MaxValue) { - vkWaitForFences (dev, (uint)fences.Length, fences.Pin(), 1, timeOut); - fences.Unpin (); - } - public void ResetFences (params VkFence[] fences) { - vkResetFences (dev, (uint)fences.Length, fences.Pin()); - fences.Unpin (); - } public void DestroyShaderModule (VkShaderModule module) { vkDestroyShaderModule (VkDev, module, IntPtr.Zero); module = 0; } + /// + /// Wait for this logical device to enter the idle state. + /// public void WaitIdle () { Utils.CheckResult (vkDeviceWaitIdle (dev)); } @@ -148,27 +127,8 @@ namespace vke { Utils.CheckResult (vkCreateRenderPass (dev, ref info, IntPtr.Zero, out renderPass)); return renderPass; } - internal VkSwapchainKHR CreateSwapChain (VkSwapchainCreateInfoKHR infos) { - VkSwapchainKHR newSwapChain; - Utils.CheckResult (vkCreateSwapchainKHR (dev, ref infos, IntPtr.Zero, out newSwapChain)); - return newSwapChain; - } - internal void DestroySwapChain (VkSwapchainKHR swapChain) { - vkDestroySwapchainKHR (dev, swapChain, IntPtr.Zero); - } - unsafe public VkImage[] GetSwapChainImages (VkSwapchainKHR swapchain) { - uint imageCount = 0; - Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, out imageCount, IntPtr.Zero)); - if (imageCount == 0) - throw new Exception ("Swapchain image count is 0."); - VkImage[] imgs = new VkImage[imageCount]; - - Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, out imageCount, imgs.Pin ())); - imgs.Unpin (); - return imgs; - } - unsafe public VkImageView CreateImageView (VkImage image, VkFormat format, VkImageViewType viewType = VkImageViewType.ImageView2D, VkImageAspectFlags aspectFlags = VkImageAspectFlags.Color) { + public VkImageView CreateImageView (VkImage image, VkFormat format, VkImageViewType viewType = VkImageViewType.ImageView2D, VkImageAspectFlags aspectFlags = VkImageAspectFlags.Color) { VkImageView view; VkImageViewCreateInfo infos = VkImageViewCreateInfo.New (); infos.image = image; diff --git a/vke/src/base/Fence.cs b/vke/src/base/Fence.cs new file mode 100644 index 0000000..0eb031a --- /dev/null +++ b/vke/src/base/Fence.cs @@ -0,0 +1,82 @@ +// Copyright (c) 2020 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; +using System.Collections.ObjectModel; +using System.Linq; +using Vulkan; +using static Vulkan.Vk; + +namespace vke { + /// + /// Managed activable fence. + /// + public class Fence : Activable { + internal VkFence handle; + VkFenceCreateInfo info = VkFenceCreateInfo.New (); + + public Fence (Device dev, bool signaled = false, string name = "fence") : base (dev, name) { + info.flags = signaled ? VkFenceCreateFlags.Signaled : 0; + Activate (); + } + + protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo + => new VkDebugUtilsObjectNameInfoEXT (VkObjectType.Framebuffer, handle.Handle); + + public sealed override void Activate () { + if (state != ActivableState.Activated) { + Utils.CheckResult (vkCreateFence (Dev.VkDev, ref info, IntPtr.Zero, out handle)); + } + base.Activate (); + } + /// + /// Wait this fence to become signaled. + /// + /// Time out before cancelling the wait. + public void Wait (ulong timeOut = UInt64.MaxValue) { + vkWaitForFences (Dev.VkDev, 1, ref handle, 1, timeOut); + } + /// + /// put this fence in the unsignaled state. + /// + public void Reset () { + vkResetFences (Dev.VkDev, 1, ref handle); + } + + public override string ToString () { + return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString ("x")}]"); + } + + public static implicit operator VkFence (Fence f) => f == null ? 0 : f.handle; + + #region IDisposable Support + protected override void Dispose (bool disposing) { + if (state == ActivableState.Activated) + vkDestroyFence (Dev.VkDev, handle, IntPtr.Zero); + if (!disposing) + System.Diagnostics.Debug.WriteLine ("VKE Activable object disposed by finalizer"); + base.Dispose (disposing); + } + #endregion + } + + + public class Fences : Collection, IDisposable { + public void Wait (ulong timeOut = UInt64.MaxValue) { + VkFence[] fences = Items.Cast ().ToArray (); + vkWaitForFences (Items[0].Dev.VkDev, (uint)Count, fences.Pin (), 1, timeOut); + fences.Unpin (); + } + public void Reset () { + VkFence[] fences = Items.Cast ().ToArray (); + vkResetFences (Items[0].Dev.VkDev, (uint)Count, fences.Pin ()); + fences.Unpin (); + } + + public void Dispose () { + foreach (Fence f in Items) + f.Dispose (); + ClearItems (); + } + } +} diff --git a/vke/src/base/FrameBuffer.cs b/vke/src/base/FrameBuffer.cs index 94a69b9..82f214e 100644 --- a/vke/src/base/FrameBuffer.cs +++ b/vke/src/base/FrameBuffer.cs @@ -10,27 +10,30 @@ using static Vulkan.Vk; namespace vke { - public class FrameBuffer : Activable { - internal VkFramebuffer handle; - RenderPass renderPass; - + /// + /// Managed activable for one Frame buffer + /// + public class FrameBuffer : Activable { + internal VkFramebuffer handle; + RenderPass renderPass; + public List attachments = new List (); - VkFramebufferCreateInfo createInfo = VkFramebufferCreateInfo.New(); + VkFramebufferCreateInfo createInfo = VkFramebufferCreateInfo.New (); - public uint Width => createInfo.width; - public uint Height => createInfo.height; - public uint Layers => createInfo.layers; + public uint Width => createInfo.width; + public uint Height => createInfo.height; + public uint Layers => createInfo.layers; protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo => new VkDebugUtilsObjectNameInfoEXT (VkObjectType.Framebuffer, handle.Handle); #region CTORS - public FrameBuffer (RenderPass _renderPass, uint _width, uint _height, uint _layers = 1) : base(_renderPass.Dev) { - renderPass = _renderPass; - createInfo.width = _width; - createInfo.height = _height; - createInfo.layers = _layers; - createInfo.renderPass = renderPass.handle; - } + public FrameBuffer (RenderPass _renderPass, uint _width, uint _height, uint _layers = 1) : base (_renderPass.Dev) { + renderPass = _renderPass; + createInfo.width = _width; + createInfo.height = _height; + createInfo.layers = _layers; + createInfo.renderPass = renderPass.handle; + } /// /// Create and Activate a new frabuffer for the supplied RenderPass. /// @@ -39,7 +42,7 @@ namespace vke { /// Height. /// Views. public FrameBuffer (RenderPass _renderPass, uint _width, uint _height, params Image[] views) - : this (_renderPass, _width, _height) { + : this (_renderPass, _width, _height) { for (int i = 0; i < views.Length; i++) { Image v = views[i]; if (v == null) { @@ -61,13 +64,13 @@ namespace vke { } else v.Activate ();//increase ref and create handle if not already activated - attachments.Add (v); + attachments.Add (v); } - Activate (); + Activate (); } #endregion - public override void Activate () { + public sealed override void Activate () { if (state != ActivableState.Activated) { VkImageView[] views = attachments.Select (a => a.Descriptor.imageView).ToArray (); createInfo.attachmentCount = (uint)views.Length; @@ -78,26 +81,26 @@ namespace vke { views.Unpin (); } base.Activate (); - } + } public override string ToString () { - return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString("x")}]"); + return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString ("x")}]"); } -#region IDisposable Support + #region IDisposable Support protected override void Dispose (bool disposing) { if (state == ActivableState.Activated) Dev.DestroyFramebuffer (handle); if (disposing) { - foreach (Image img in attachments) - img.Dispose(); - }else + foreach (Image img in attachments) + img.Dispose (); + } else System.Diagnostics.Debug.WriteLine ("VKE Activable object disposed by finalizer"); - + base.Dispose (disposing); } -#endregion + #endregion } } diff --git a/vke/src/base/GPUBuffer.cs b/vke/src/base/GPUBuffer.cs index 50280ba..d5e1c7c 100644 --- a/vke/src/base/GPUBuffer.cs +++ b/vke/src/base/GPUBuffer.cs @@ -16,17 +16,32 @@ namespace vke { } } /// - /// Device local Buffer + /// Device local Buffer for an array of elements of type T. /// public class GPUBuffer : GPUBuffer { - + /// + /// return the current element count of this buffer. + /// public int ElementCount { get; private set; } + /// + /// Create an empty new device local buffer with the size needed to store the specified item count of type T. + /// + /// the logical device that will create this buffer. + /// bitmask of the intended usages for this buffer + /// Element count of type T to reserve the space for. public GPUBuffer (Device device, VkBufferUsageFlags usage, int elementCount) : base (device, usage, (ulong)(Marshal.SizeOf () * elementCount)) { ElementCount = elementCount; } - public GPUBuffer (Queue staggingQ, CommandPool staggingCmdPool, VkBufferUsageFlags usage, T[] elements) + /// + /// Create and polulate by copy a new device local buffer. + /// + /// The managed queue that will be used for the copy of the elements from a temporary stagging buffer to the final device buffer. + /// A command pool for the supplied queue. + /// bitmask of the intended usages for this buffer + /// an array of elements of type T to populate the new device buffer with. + public GPUBuffer (Queue staggingQ, CommandPool staggingCmdPool, VkBufferUsageFlags usage, T[] elements) : base (staggingQ.Dev, usage | VkBufferUsageFlags.TransferDst, (ulong)(Marshal.SizeOf () * elements.Length)) { using (HostBuffer stagging = new HostBuffer (Dev, VkBufferUsageFlags.TransferSrc, elements)) { CommandBuffer cmd = staggingCmdPool.AllocateCommandBuffer (); diff --git a/vke/src/base/GraphicPipeline.cs b/vke/src/base/GraphicPipeline.cs index c538501..6658cc1 100644 --- a/vke/src/base/GraphicPipeline.cs +++ b/vke/src/base/GraphicPipeline.cs @@ -8,20 +8,25 @@ using System.Linq; using static Vulkan.Vk; namespace vke { - public class GraphicPipeline : Pipeline { + public class GraphicPipeline : Pipeline { public readonly RenderPass RenderPass; public VkSampleCountFlags Samples => RenderPass.Samples; #region CTORS - protected GraphicPipeline (RenderPass renderPass, PipelineCache cache = null, string name = "graphic pipeline") : base(renderPass.Dev, cache, name) { + /// + /// Create and activate a new pipeline for supplied render pass. + /// + /// a managed Render pass that will be activated (if not already) during the pipeline creation. + /// an optional pipeline cache to speed up pipeline creation. + /// an optionnal name that will be used by the debug utils extension if enabled. + protected GraphicPipeline (RenderPass renderPass, PipelineCache cache = null, string name = "graphic pipeline") : base (renderPass.Dev, cache, name) { RenderPass = renderPass; } /// /// Create a new Pipeline with supplied RenderPass /// - public GraphicPipeline (GraphicPipelineConfig cfg, string name = "graphic pipeline") : this (cfg.RenderPass, cfg.Cache, name) - { + public GraphicPipeline (GraphicPipelineConfig cfg, string name = "graphic pipeline") : this (cfg.RenderPass, cfg.Cache, name) { layout = cfg.Layout; init (cfg); @@ -46,8 +51,7 @@ namespace vke { VkPipelineColorBlendStateCreateInfo colorBlendInfo = VkPipelineColorBlendStateCreateInfo.New (); colorBlendInfo.logicOpEnable = cfg.ColorBlendLogicOpEnable; colorBlendInfo.logicOp = cfg.ColorBlendLogicOp; - unsafe - { + unsafe { colorBlendInfo.blendConstants[0] = cfg.ColorBlendConstants.X; colorBlendInfo.blendConstants[1] = cfg.ColorBlendConstants.Y; colorBlendInfo.blendConstants[2] = cfg.ColorBlendConstants.Z; @@ -58,7 +62,7 @@ namespace vke { VkPipelineDynamicStateCreateInfo dynStatesInfo = VkPipelineDynamicStateCreateInfo.New (); dynStatesInfo.dynamicStateCount = (uint)cfg.dynamicStates.Count; - dynStatesInfo.pDynamicStates = cfg.dynamicStates.Cast().ToArray().Pin (pctx); + dynStatesInfo.pDynamicStates = cfg.dynamicStates.Cast ().ToArray ().Pin (pctx); VkPipelineVertexInputStateCreateInfo vertInputInfo = VkPipelineVertexInputStateCreateInfo.New (); vertInputInfo.vertexBindingDescriptionCount = (uint)cfg.vertexBindings.Count; @@ -97,7 +101,7 @@ namespace vke { Utils.CheckResult (vkCreateGraphicsPipelines (Dev.VkDev, Cache == null ? VkPipelineCache.Null : Cache.handle, 1, ref info, IntPtr.Zero, out handle)); for (int i = 0; i < cfg.shaders.Count; i++) - Dev.DestroyShaderModule (shaderStages [i].module); + Dev.DestroyShaderModule (shaderStages[i].module); } } base.Activate (); @@ -112,9 +116,9 @@ namespace vke { protected override void Dispose (bool disposing) { if (disposing) { - if (state == ActivableState.Activated) + if (state == ActivableState.Activated) RenderPass.Dispose (); - }else + } else System.Diagnostics.Debug.WriteLine ("GraphicPipeline disposed by finalizer"); base.Dispose (disposing); diff --git a/vke/src/base/HostBuffer.cs b/vke/src/base/HostBuffer.cs index 2ce0094..f61cb84 100644 --- a/vke/src/base/HostBuffer.cs +++ b/vke/src/base/HostBuffer.cs @@ -8,80 +8,144 @@ using Vulkan; using static Vulkan.Vk; namespace vke { - + /// + /// Host visible mappable buffer to handle array of blittable type T + /// public class HostBuffer : HostBuffer { - int TSize; - + int TSize; + /// + /// Create an empty mappable vulkan buffer for elements of type T whith specified size. + /// + /// Logical Device. + /// Buffer Usage. + /// Array element count. + /// If set to true, buffer will stay mapped after the constructor. + /// If set to true vulkan memory with have the coherent flag. public HostBuffer (Device device, VkBufferUsageFlags usage, uint arrayElementCount, bool keepMapped = false, bool coherentMem = true) - : base (device, usage, (ulong)(Marshal.SizeOf () * arrayElementCount), keepMapped, coherentMem) { - TSize = Marshal.SizeOf(); - } + : base (device, usage, (ulong)(Marshal.SizeOf () * arrayElementCount), keepMapped, coherentMem) { + TSize = Marshal.SizeOf (); + } + /// + /// Create and populate a mappable vulkan buffer. + /// + /// Logical Device. + /// Buffer Usage. + /// a list of T implementing the IList interface which will be used to populate the buffer. + /// If set to true, buffer will stay mapped after the constructor. + /// If set to true vulkan memory with have the coherent flag. public HostBuffer (Device device, VkBufferUsageFlags usage, IList data, bool keepMapped = false, bool coherentMem = true) - : base (device, usage, (ulong)(Marshal.SizeOf () * data.Count), keepMapped, coherentMem) { - TSize = Marshal.SizeOf(); - Map(); - Update (data, createInfo.size); + : base (device, usage, (ulong)(Marshal.SizeOf () * data.Count), keepMapped, coherentMem) { + TSize = Marshal.SizeOf (); + Map (); + Update (data, createInfo.size); if (!keepMapped) - Unmap (); - } - public HostBuffer (Device device, VkBufferUsageFlags usage, T[] data, bool keepMapped = false, bool coherentMem = true) - : base (device, usage, (ulong)(Marshal.SizeOf () * data.Length), keepMapped, coherentMem) { - TSize = Marshal.SizeOf(); - Map(); - Update (data, createInfo.size); + Unmap (); + } + /// + /// Create and populate a mappable vulkan buffer. + /// + /// Logical Device. + /// Buffer Usage. + /// an array of T which will be used to populate the buffer. + /// If set to true, buffer will stay mapped after the constructor. + /// If set to true vulkan memory with have the coherent flag. + public HostBuffer (Device device, VkBufferUsageFlags usage, T[] data, bool keepMapped = false, bool coherentMem = true) + : base (device, usage, (ulong)(Marshal.SizeOf () * data.Length), keepMapped, coherentMem) { + TSize = Marshal.SizeOf (); + Map (); + Update (data, createInfo.size); if (!keepMapped) - Unmap (); - } + Unmap (); + } + /// + /// Update content of the buffer with array of given length with no offset. + /// + /// Data. public void Update (T[] data) { Update (data, (ulong)(TSize * data.Length)); } - public void Update (uint index, T data) { - GCHandle ptr = GCHandle.Alloc(data, GCHandleType.Pinned); - unsafe { - System.Buffer.MemoryCopy(ptr.AddrOfPinnedObject().ToPointer(), (mappedData + (int)(TSize*index)).ToPointer(), TSize, TSize); - } - ptr.Free(); - } - public void Flush (uint startIndex, uint endIndex) { - VkMappedMemoryRange mr = new VkMappedMemoryRange - { - sType = VkStructureType.MappedMemoryRange, + /// + /// Update a single T element in the buffer at specified index. + /// + /// 0 based index of the T element in the array. + /// new value for T to set in the buffer. + public void Update (uint index, T data) { + GCHandle ptr = GCHandle.Alloc (data, GCHandleType.Pinned); + unsafe { + System.Buffer.MemoryCopy (ptr.AddrOfPinnedObject ().ToPointer (), (mappedData + (int)(TSize * index)).ToPointer (), TSize, TSize); + } + ptr.Free (); + } + /// + /// Flush memory, note that coherent memory desn't need it. + /// + /// index of the first T element to flush + /// index of the last T element to flush + public void Flush (uint startIndex, uint endIndex) { + //TODO: vulkan has some alignement constrains on flushing! + VkMappedMemoryRange mr = new VkMappedMemoryRange { + sType = VkStructureType.MappedMemoryRange, #if MEMORY_POOLS memory = memoryPool.vkMemory, - offset = poolOffset + (ulong)(startIndex * TSize), + offset = poolOffset + (ulong)(startIndex * TSize), #else memory = vkMemory, offset = (ulong)(startIndex * TSize), #endif - size = (ulong)((endIndex - startIndex) * TSize) - }; - vkFlushMappedMemoryRanges(Dev.VkDev, 1, ref mr); - } - } + size = (ulong)((endIndex - startIndex) * TSize) + }; + vkFlushMappedMemoryRanges (Dev.VkDev, 1, ref mr); + } + } /// /// Mappable Buffer with HostVisble and HostCoherent memory flags /// public class HostBuffer : Buffer { - public HostBuffer (Device device, VkBufferUsageFlags usage, UInt64 size, bool keepMapped = false, bool coherentMem = true) - : base (device, usage, coherentMem ? VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent : VkMemoryPropertyFlags.HostVisible, size) { - if (keepMapped) - Map(); - } - public HostBuffer (Device device, VkBufferUsageFlags usage, object data, bool keepMapped = false, bool coherentMem = true) - : base (device, usage, coherentMem ? VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent : VkMemoryPropertyFlags.HostVisible, (ulong)Marshal.SizeOf(data)) { - Map (); - Update (data, createInfo.size); + /// + /// Create an empty mappable vulkan buffer whith specified size in byte. + /// + /// Logical Device. + /// Buffer Usage. + /// buffer memory size in byte + /// If set to true, buffer will stay mapped after the constructor. + /// If set to true vulkan memory with have the coherent flag. + public HostBuffer (Device device, VkBufferUsageFlags usage, UInt64 size, bool keepMapped = false, bool coherentMem = true) + : base (device, usage, coherentMem ? VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent : VkMemoryPropertyFlags.HostVisible, size) { + if (keepMapped) + Map (); + } + /// + /// Create a mappable vulkan buffer whith the supplied object. + /// + /// Logical Device. + /// Buffer Usage. + /// Object to set as content of the buffer. It must be blittable to be able to compute size automatically. + /// If set to true, buffer will stay mapped after the constructor. + /// If set to true vulkan memory with have the coherent flag. + public HostBuffer (Device device, VkBufferUsageFlags usage, object data, bool keepMapped = false, bool coherentMem = true) + : base (device, usage, coherentMem ? VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent : VkMemoryPropertyFlags.HostVisible, (ulong)Marshal.SizeOf (data)) { + Map (); + Update (data, createInfo.size); if (!keepMapped) - Unmap (); - } - public HostBuffer (Device device, VkBufferUsageFlags usage, UInt64 size, IntPtr data, bool keepMapped = false, bool coherentMem = true) - : base (device, usage, coherentMem ? VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent : VkMemoryPropertyFlags.HostVisible, size) { - Map (); - unsafe { - System.Buffer.MemoryCopy (data.ToPointer (), mappedData.ToPointer (), size, size); - } + Unmap (); + } + /// + /// Create a mappable vulkan buffer of specified size whith a data pointer. + /// + /// Logical Device. + /// Buffer Usage. + /// Size in byte of the datas supplied with the pointer. + /// Managed pointer which point to the data to copy in the buffer at startup. + /// If set to true, buffer will stay mapped after the constructor. + /// If set to true vulkan memory with have the coherent flag. + public HostBuffer (Device device, VkBufferUsageFlags usage, UInt64 size, IntPtr data, bool keepMapped = false, bool coherentMem = true) + : base (device, usage, coherentMem ? VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent : VkMemoryPropertyFlags.HostVisible, size) { + Map (); + unsafe { + System.Buffer.MemoryCopy (data.ToPointer (), mappedData.ToPointer (), size, size); + } if (!keepMapped) - Unmap (); - } - } + Unmap (); + } + } } diff --git a/vke/src/base/Image.cs b/vke/src/base/Image.cs index 9c1cb8e..b2ae336 100644 --- a/vke/src/base/Image.cs +++ b/vke/src/base/Image.cs @@ -14,59 +14,92 @@ namespace vke { /// such imported image will not be disposed with the sampler and the view. /// public class Image : Resource { + /// Default format to use if not defined by constructor parameters. public static VkFormat DefaultTextureFormat = VkFormat.R8g8b8a8Unorm; - internal VkImage handle; - VkImageCreateInfo info = VkImageCreateInfo.New(); + internal VkImage handle; + VkImageCreateInfo info = VkImageCreateInfo.New (); + uint[] queueFalillies; /// /// if true, the vkImage handle will not be destroyed on dispose, useful to create image for swapchain /// - bool imported; - - public VkDescriptorImageInfo Descriptor; - public VkImageCreateInfo CreateInfo => info; - public VkExtent3D Extent => info.extent; - public VkFormat Format => info.format; + bool imported; + + public VkDescriptorImageInfo Descriptor; + /// Get the create info structure used for creating this image. + public VkImageCreateInfo CreateInfo => info; + /// Get the dimensions in pixel for this image + public VkExtent3D Extent => info.extent; + /// Get image format + public VkFormat Format => info.format; + /// Native vulkan handle for the image. public VkImage Handle => handle; + /// Width in pixel of the image. public uint Width => CreateInfo.extent.width; + /// Height in pixel of the image. public uint Height => CreateInfo.extent.height; + /// Boolean indicating if memory allocated for this image has linear or optimal tiling. public override bool IsLinar => CreateInfo.tiling == VkImageTiling.Linear; - + /// + /// May be used to query the last known layout. It is set when commands explicitly secify the final layout of the image. + /// + /// Due to the automatic layout trasitions handled by several vulkan commands, use this property with caution, it's value + /// may not be the actual layout of the image. public VkImageLayout lastKnownLayout { get; private set; } protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo => new VkDebugUtilsObjectNameInfoEXT (VkObjectType.Image, handle.Handle); #region CTORS + /// + /// Create a new Image. + /// + /// Initial layout will be automatically set to Undefined if tiling is optimal and Preinitialized if tiling is linear. + /// The logical device that create the image. + /// format and type of the texel blocks that will be contained in the image + /// bitmask describing the intended usage of the image. + /// Memory property flags. + /// number of data in the X dimension of the image. + /// number of data in the Y dimension of the image. + /// value specifying the basic dimensionality of the image. Layers in array textures do not count as a dimension for the purposes of the image type. + /// number of sample per texel. + /// tiling arrangement of the texel blocks in memory. + /// describes the number of levels of detail available for minified sampling of the image. + /// number of layers in the image. + /// number of data in the Z dimension of the image + /// bitmask describing additional parameters of the image. + /// value specifying the sharing mode of the image when it will be accessed by multiple queue families. + /// list of queue families that will access this image (ignored if sharingMode is not CONCURRENT). public Image (Device device, VkFormat format, VkImageUsageFlags usage, VkMemoryPropertyFlags _memoryPropertyFlags, - uint width, uint height, - VkImageType type = VkImageType.Image2D, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1, - VkImageTiling tiling = VkImageTiling.Optimal, uint mipsLevels = 1, uint layers = 1, uint depth = 1, - VkImageCreateFlags createFlags = 0) - : base (device, _memoryPropertyFlags) { - - info.imageType = type; - info.format = format; - info.extent.width = width; - info.extent.height = height; - info.extent.depth = depth; - info.mipLevels = mipsLevels; - info.arrayLayers = layers; - info.samples = samples; - info.tiling = tiling; - info.usage = usage; - info.initialLayout = (tiling == VkImageTiling.Optimal) ? VkImageLayout.Undefined : VkImageLayout.Preinitialized; - info.sharingMode = VkSharingMode.Exclusive; + uint width, uint height, + VkImageType type = VkImageType.Image2D, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1, + VkImageTiling tiling = VkImageTiling.Optimal, uint mipsLevels = 1, uint layers = 1, uint depth = 1, + VkImageCreateFlags createFlags = 0, VkSharingMode sharingMode = VkSharingMode.Exclusive, params uint[] queuesFamillies) + : base (device, _memoryPropertyFlags) { + + info.imageType = type; + info.format = format; + info.extent.width = width; + info.extent.height = height; + info.extent.depth = depth; + info.mipLevels = mipsLevels; + info.arrayLayers = layers; + info.samples = samples; + info.tiling = tiling; + info.usage = usage; + info.initialLayout = (tiling == VkImageTiling.Optimal) ? VkImageLayout.Undefined : VkImageLayout.Preinitialized; + info.sharingMode = sharingMode; info.flags = createFlags; + this.queueFalillies = queuesFamillies; lastKnownLayout = info.initialLayout; - Activate ();//DONT OVERRIDE Activate in derived classes!!!! - } + Activate (); + } /// - /// Import vkImage handle into a new Image class, handle will be preserve on destruction. + /// Import vkImage handle into a new Image class, native handle will be preserve on destruction. /// public Image (Device device, VkImage vkHandle, VkFormat format, VkImageUsageFlags usage, uint width, uint height) : base (device, VkMemoryPropertyFlags.DeviceLocal) { @@ -85,13 +118,19 @@ namespace vke { imported = true; state = ActivableState.Activated; - references++;//increment ref because it is bound to swapchain + references++; } #endregion - public static uint ComputeMipLevels(uint size) => (uint)Math.Floor (Math.Log (size)) + 1; - public static uint ComputeMipLevels (int width, int height) => (uint)Math.Floor (Math.Log (Math.Max (width, height))) + 1; + public static uint ComputeMipLevels (uint size) => (uint)Math.Floor (Math.Log (size)) + 1; + public static uint ComputeMipLevels (int width, int height) => (uint)Math.Floor (Math.Log (Math.Max (width, height))) + 1; + /// + /// Check if specified image usage is supported for the given physical image format. + /// + /// true, if usage is supported + /// bitmask of intend usage for an image. + /// Physical format feature bitmask as returned by `GetFormatProperties` of PhysicalDevice public static bool CheckFormatIsSupported (VkImageUsageFlags usage, VkFormatFeatureFlags phyFormatSupport) { if (usage.HasFlag (VkImageUsageFlags.TransferSrc) & !phyFormatSupport.HasFlag (VkFormatFeatureFlags.TransferSrc)) return false; @@ -214,7 +253,7 @@ namespace vke { return img; } - } + } /// /// create host visible linear image without command from byte array /// @@ -293,9 +332,9 @@ namespace vke { #endregion - internal override void updateMemoryRequirements () { - vkGetImageMemoryRequirements (Dev.VkDev, handle, out memReqs); - } + internal override void updateMemoryRequirements () { + vkGetImageMemoryRequirements (Dev.VkDev, handle, out memReqs); + } internal override void bindMemory () { #if MEMORY_POOLS Utils.CheckResult (vkBindImageMemory (Dev.VkDev, handle, memoryPool.vkMemory, poolOffset)); @@ -303,9 +342,15 @@ namespace vke { Utils.CheckResult (vkBindImageMemory (Dev.VkDev, handle, vkMemory, 0)); #endif } - public override void Activate () { + public sealed override void Activate () { if (state != ActivableState.Activated) { - Utils.CheckResult (vkCreateImage (Dev.VkDev, ref info, IntPtr.Zero, out handle)); + if (info.sharingMode == VkSharingMode.Concurrent && queueFalillies?.Length > 0) { + info.queueFamilyIndexCount = (uint)queueFalillies.Length; + info.pQueueFamilyIndices = queueFalillies.Pin (); + Utils.CheckResult (vkCreateImage (Dev.VkDev, ref info, IntPtr.Zero, out handle)); + queueFalillies.Unpin (); + } else + Utils.CheckResult (vkCreateImage (Dev.VkDev, ref info, IntPtr.Zero, out handle)); #if MEMORY_POOLS Dev.resourceManager.Add (this); #else @@ -315,70 +360,78 @@ namespace vke { #endif } - base.Activate (); - } + base.Activate (); + } public void CreateView (VkImageViewType type = VkImageViewType.ImageView2D, VkImageAspectFlags aspectFlags = VkImageAspectFlags.Color, - uint layerCount = 1, - uint baseMipLevel = 0, int levelCount = -1, uint baseArrayLayer = 0, + uint layerCount = 1, uint baseMipLevel = 0, int levelCount = -1, uint baseArrayLayer = 0, VkComponentSwizzle r = VkComponentSwizzle.R, VkComponentSwizzle g = VkComponentSwizzle.G, VkComponentSwizzle b = VkComponentSwizzle.B, VkComponentSwizzle a = VkComponentSwizzle.A) { - VkImageView view = default(VkImageView); - VkImageViewCreateInfo viewInfo = VkImageViewCreateInfo.New(); - viewInfo.image = handle; - viewInfo.viewType = type; - viewInfo.format = Format; - viewInfo.components.r = r; - viewInfo.components.g = g; - viewInfo.components.b = b; - viewInfo.components.a = a; - viewInfo.subresourceRange.aspectMask = aspectFlags; + VkImageView view = default (VkImageView); + VkImageViewCreateInfo viewInfo = VkImageViewCreateInfo.New (); + viewInfo.image = handle; + viewInfo.viewType = type; + viewInfo.format = Format; + viewInfo.components.r = r; + viewInfo.components.g = g; + viewInfo.components.b = b; + viewInfo.components.a = a; + viewInfo.subresourceRange.aspectMask = aspectFlags; viewInfo.subresourceRange.baseMipLevel = baseMipLevel; viewInfo.subresourceRange.levelCount = levelCount < 0 ? info.mipLevels : (uint)levelCount; viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer; viewInfo.subresourceRange.layerCount = layerCount; - Utils.CheckResult (vkCreateImageView (Dev.VkDev, ref viewInfo, IntPtr.Zero, out view)); + Utils.CheckResult (vkCreateImageView (Dev.VkDev, ref viewInfo, IntPtr.Zero, out view)); - if (Descriptor.imageView.Handle != 0) - Dev.DestroyImageView (Descriptor.imageView); - Descriptor.imageView = view; - } + if (Descriptor.imageView.Handle != 0) + Dev.DestroyImageView (Descriptor.imageView); + Descriptor.imageView = view; + } public void CreateSampler (VkSamplerAddressMode addressMode, VkFilter minFilter = VkFilter.Linear, VkFilter magFilter = VkFilter.Linear, VkSamplerMipmapMode mipmapMode = VkSamplerMipmapMode.Linear, float maxAnisotropy = 1.0f, float minLod = 0.0f, float maxLod = -1f) { CreateSampler (minFilter, magFilter, mipmapMode, addressMode, maxAnisotropy, minLod, maxLod); } - + /// + /// Create a Sampler and store it into the Descriptor structure of this image. + /// + /// Minimum filter. + /// Mag filter. + /// Mipmap mode. + /// Address mode. + /// Max anisotropy. + /// Minimum lod. + /// Max lod. public void CreateSampler (VkFilter minFilter = VkFilter.Linear, VkFilter magFilter = VkFilter.Linear, - VkSamplerMipmapMode mipmapMode = VkSamplerMipmapMode.Linear, VkSamplerAddressMode addressMode = VkSamplerAddressMode.Repeat, - float maxAnisotropy = 1.0f, float minLod = 0.0f, float maxLod = -1f) { - VkSampler sampler; - VkSamplerCreateInfo sampInfo = VkSamplerCreateInfo.New(); - sampInfo.maxAnisotropy = maxAnisotropy; + VkSamplerMipmapMode mipmapMode = VkSamplerMipmapMode.Linear, VkSamplerAddressMode addressMode = VkSamplerAddressMode.Repeat, + float maxAnisotropy = 1.0f, float minLod = 0.0f, float maxLod = -1f) { + VkSampler sampler; + VkSamplerCreateInfo sampInfo = VkSamplerCreateInfo.New (); + sampInfo.maxAnisotropy = maxAnisotropy; sampInfo.maxAnisotropy = 1.0f;// device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f; - //samplerInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy; + //samplerInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy; sampInfo.addressModeU = addressMode; - sampInfo.addressModeV = addressMode; - sampInfo.addressModeW = addressMode; - sampInfo.magFilter = magFilter; - sampInfo.minFilter = minFilter; - sampInfo.mipmapMode = mipmapMode; - sampInfo.minLod = minLod; - sampInfo.maxLod = maxLod < 0f ? info.mipLevels > 1 ? info.mipLevels : 0 : maxLod; + sampInfo.addressModeV = addressMode; + sampInfo.addressModeW = addressMode; + sampInfo.magFilter = magFilter; + sampInfo.minFilter = minFilter; + sampInfo.mipmapMode = mipmapMode; + sampInfo.minLod = minLod; + sampInfo.maxLod = maxLod < 0f ? info.mipLevels > 1 ? info.mipLevels : 0 : maxLod; sampInfo.compareOp = VkCompareOp.Never; sampInfo.borderColor = VkBorderColor.FloatOpaqueWhite; - Utils.CheckResult (vkCreateSampler (Dev.VkDev, ref sampInfo, IntPtr.Zero, out sampler)); + Utils.CheckResult (vkCreateSampler (Dev.VkDev, ref sampInfo, IntPtr.Zero, out sampler)); - if (Descriptor.sampler.Handle != 0) - Dev.DestroySampler (Descriptor.sampler); - Descriptor.sampler = sampler; - } + if (Descriptor.sampler.Handle != 0) + Dev.DestroySampler (Descriptor.sampler); + Descriptor.sampler = sampler; + } public void SetLayout (CommandBuffer cmdbuffer, VkImageAspectFlags aspectMask, @@ -387,25 +440,25 @@ namespace vke { } public void SetLayout (CommandBuffer cmdbuffer, VkImageAspectFlags aspectMask, - VkImageLayout oldImageLayout, + VkImageLayout oldImageLayout, VkImageLayout newImageLayout) { SetLayout (cmdbuffer, aspectMask, oldImageLayout, newImageLayout, oldImageLayout.GetDefaultStage (), newImageLayout.GetDefaultStage ()); } public void SetLayout ( - CommandBuffer cmdbuffer, - VkImageAspectFlags aspectMask, - VkImageLayout oldImageLayout, - VkImageLayout newImageLayout, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask) { - VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange { - aspectMask = aspectMask, - baseMipLevel = 0, - levelCount = CreateInfo.mipLevels, - layerCount = CreateInfo.arrayLayers, - }; - SetLayout (cmdbuffer, oldImageLayout, newImageLayout, subresourceRange, srcStageMask, dstStageMask); - } + CommandBuffer cmdbuffer, + VkImageAspectFlags aspectMask, + VkImageLayout oldImageLayout, + VkImageLayout newImageLayout, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask) { + VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange { + aspectMask = aspectMask, + baseMipLevel = 0, + levelCount = CreateInfo.mipLevels, + layerCount = CreateInfo.arrayLayers, + }; + SetLayout (cmdbuffer, oldImageLayout, newImageLayout, subresourceRange, srcStageMask, dstStageMask); + } public void SetLayout ( CommandBuffer cmdbuffer, VkImageAspectFlags aspectMask, @@ -416,8 +469,7 @@ namespace vke { VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands, uint srcQueueFamilyIndex = Vk.QueueFamilyIgnored, - uint dstQueueFamilyIndex = Vk.QueueFamilyIgnored) - { + uint dstQueueFamilyIndex = Vk.QueueFamilyIgnored) { VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange { aspectMask = aspectMask, baseMipLevel = 0, @@ -437,8 +489,7 @@ namespace vke { VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands, uint srcQueueFamilyIndex = Vk.QueueFamilyIgnored, - uint dstQueueFamilyIndex = Vk.QueueFamilyIgnored) - { + uint dstQueueFamilyIndex = Vk.QueueFamilyIgnored) { VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New (); imageMemoryBarrier.srcQueueFamilyIndex = srcQueueFamilyIndex; @@ -464,123 +515,123 @@ namespace vke { // an image and put it into an active command buffer // See chapter 11.4 "Image Layout" for details public void SetLayout ( - CommandBuffer cmdbuffer, - VkImageLayout oldImageLayout, - VkImageLayout newImageLayout, - VkImageSubresourceRange subresourceRange, - VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, - VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands, + CommandBuffer cmdbuffer, + VkImageLayout oldImageLayout, + VkImageLayout newImageLayout, + VkImageSubresourceRange subresourceRange, + VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, + VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands, uint srcQueueFamilyIndex = Vk.QueueFamilyIgnored, uint dstQueueFamilyIndex = Vk.QueueFamilyIgnored) { - // Create an image barrier object - VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New(); - imageMemoryBarrier.srcQueueFamilyIndex = srcQueueFamilyIndex; - imageMemoryBarrier.dstQueueFamilyIndex = dstQueueFamilyIndex; - imageMemoryBarrier.oldLayout = oldImageLayout; - imageMemoryBarrier.newLayout = newImageLayout; - imageMemoryBarrier.image = handle; - imageMemoryBarrier.subresourceRange = subresourceRange; - - // Source layouts (old) - // Source access mask controls actions that have to be finished on the old layout - // before it will be transitioned to the new layout - switch (oldImageLayout) { - case VkImageLayout.Undefined: - // Image layout is undefined (or does not matter) - // Only valid as initial layout - // No flags required, listed only for completeness - imageMemoryBarrier.srcAccessMask = 0; - break; - - case VkImageLayout.Preinitialized: - // Image is preinitialized - // Only valid as initial layout for linear images, preserves memory contents - // Make sure host writes have been finished - imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite; - break; - - case VkImageLayout.ColorAttachmentOptimal: - // Image is a color attachment - // Make sure any writes to the color buffer have been finished - imageMemoryBarrier.srcAccessMask = VkAccessFlags.ColorAttachmentWrite; - break; - - case VkImageLayout.DepthStencilAttachmentOptimal: - // Image is a depth/stencil attachment - // Make sure any writes to the depth/stencil buffer have been finished - imageMemoryBarrier.srcAccessMask = VkAccessFlags.DepthStencilAttachmentWrite; - break; - - case VkImageLayout.TransferSrcOptimal: - // Image is a transfer source - // Make sure any reads from the image have been finished - imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; - break; - - case VkImageLayout.TransferDstOptimal: - // Image is a transfer destination - // Make sure any writes to the image have been finished - imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferWrite; - break; - - case VkImageLayout.ShaderReadOnlyOptimal: - // Image is read by a shader - // Make sure any shader reads from the image have been finished - imageMemoryBarrier.srcAccessMask = VkAccessFlags.ShaderRead; - break; - } - - // Target layouts (new) - // Destination access mask controls the dependency for the new image layout - switch (newImageLayout) { - case VkImageLayout.TransferDstOptimal: - // Image will be used as a transfer destination - // Make sure any writes to the image have been finished - imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferWrite; - break; - - case VkImageLayout.TransferSrcOptimal: - // Image will be used as a transfer source - // Make sure any reads from and writes to the image have been finished - //imageMemoryBarrier.srcAccessMask |= VkAccessFlags.TransferRead; - imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferRead; - break; - - case VkImageLayout.ColorAttachmentOptimal: - // Image will be used as a color attachment - // Make sure any writes to the color buffer have been finished - imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; - imageMemoryBarrier.dstAccessMask = VkAccessFlags.ColorAttachmentWrite; - break; - - case VkImageLayout.DepthStencilAttachmentOptimal: - // Image layout will be used as a depth/stencil attachment - // Make sure any writes to depth/stencil buffer have been finished - imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VkAccessFlags.DepthStencilAttachmentWrite; - break; - - case VkImageLayout.ShaderReadOnlyOptimal: - // Image will be read in a shader (sampler, input attachment) - // Make sure any writes to the image have been finished - if (imageMemoryBarrier.srcAccessMask == 0) { - imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite | VkAccessFlags.TransferWrite; - } - imageMemoryBarrier.dstAccessMask = VkAccessFlags.ShaderRead; - break; - } - - // Put barrier inside setup command buffer - Vk.vkCmdPipelineBarrier ( - cmdbuffer.Handle, - srcStageMask, - dstStageMask, - 0, - 0,IntPtr.Zero, - 0, IntPtr.Zero, - 1, ref imageMemoryBarrier); + // Create an image barrier object + VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New (); + imageMemoryBarrier.srcQueueFamilyIndex = srcQueueFamilyIndex; + imageMemoryBarrier.dstQueueFamilyIndex = dstQueueFamilyIndex; + imageMemoryBarrier.oldLayout = oldImageLayout; + imageMemoryBarrier.newLayout = newImageLayout; + imageMemoryBarrier.image = handle; + imageMemoryBarrier.subresourceRange = subresourceRange; + + // Source layouts (old) + // Source access mask controls actions that have to be finished on the old layout + // before it will be transitioned to the new layout + switch (oldImageLayout) { + case VkImageLayout.Undefined: + // Image layout is undefined (or does not matter) + // Only valid as initial layout + // No flags required, listed only for completeness + imageMemoryBarrier.srcAccessMask = 0; + break; + + case VkImageLayout.Preinitialized: + // Image is preinitialized + // Only valid as initial layout for linear images, preserves memory contents + // Make sure host writes have been finished + imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite; + break; + + case VkImageLayout.ColorAttachmentOptimal: + // Image is a color attachment + // Make sure any writes to the color buffer have been finished + imageMemoryBarrier.srcAccessMask = VkAccessFlags.ColorAttachmentWrite; + break; + + case VkImageLayout.DepthStencilAttachmentOptimal: + // Image is a depth/stencil attachment + // Make sure any writes to the depth/stencil buffer have been finished + imageMemoryBarrier.srcAccessMask = VkAccessFlags.DepthStencilAttachmentWrite; + break; + + case VkImageLayout.TransferSrcOptimal: + // Image is a transfer source + // Make sure any reads from the image have been finished + imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; + break; + + case VkImageLayout.TransferDstOptimal: + // Image is a transfer destination + // Make sure any writes to the image have been finished + imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferWrite; + break; + + case VkImageLayout.ShaderReadOnlyOptimal: + // Image is read by a shader + // Make sure any shader reads from the image have been finished + imageMemoryBarrier.srcAccessMask = VkAccessFlags.ShaderRead; + break; + } + + // Target layouts (new) + // Destination access mask controls the dependency for the new image layout + switch (newImageLayout) { + case VkImageLayout.TransferDstOptimal: + // Image will be used as a transfer destination + // Make sure any writes to the image have been finished + imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferWrite; + break; + + case VkImageLayout.TransferSrcOptimal: + // Image will be used as a transfer source + // Make sure any reads from and writes to the image have been finished + //imageMemoryBarrier.srcAccessMask |= VkAccessFlags.TransferRead; + imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferRead; + break; + + case VkImageLayout.ColorAttachmentOptimal: + // Image will be used as a color attachment + // Make sure any writes to the color buffer have been finished + imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; + imageMemoryBarrier.dstAccessMask = VkAccessFlags.ColorAttachmentWrite; + break; + + case VkImageLayout.DepthStencilAttachmentOptimal: + // Image layout will be used as a depth/stencil attachment + // Make sure any writes to depth/stencil buffer have been finished + imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VkAccessFlags.DepthStencilAttachmentWrite; + break; + + case VkImageLayout.ShaderReadOnlyOptimal: + // Image will be read in a shader (sampler, input attachment) + // Make sure any writes to the image have been finished + if (imageMemoryBarrier.srcAccessMask == 0) { + imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite | VkAccessFlags.TransferWrite; + } + imageMemoryBarrier.dstAccessMask = VkAccessFlags.ShaderRead; + break; + } + + // Put barrier inside setup command buffer + Vk.vkCmdPipelineBarrier ( + cmdbuffer.Handle, + srcStageMask, + dstStageMask, + 0, + 0, IntPtr.Zero, + 0, IntPtr.Zero, + 1, ref imageMemoryBarrier); lastKnownLayout = newImageLayout; - } + } public void BuildMipmaps (Queue copyQ, CommandPool copyCmdPool) { if (info.mipLevels == 1) { @@ -598,6 +649,10 @@ namespace vke { cmd.Free (); } + /// + /// Build mipmap chain for this image. Final layout will be ShaderReadOnlyOptimal. + /// + /// a command buffer to handle the operation. public void BuildMipmaps (CommandBuffer cmd) { VkImageSubresourceRange mipSubRange = new VkImageSubresourceRange (VkImageAspectFlags.Color, 0, 1, 0, info.arrayLayers); @@ -605,7 +660,7 @@ namespace vke { for (int i = 1; i < info.mipLevels; i++) { VkImageBlit imageBlit = new VkImageBlit { - srcSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, info.arrayLayers, (uint)i - 1), + srcSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, info.arrayLayers, (uint)i - 1), srcOffsets_1 = new VkOffset3D ((int)info.extent.width >> (i - 1), (int)info.extent.height >> (i - 1), 1), dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, info.arrayLayers, (uint)i), dstOffsets_1 = new VkOffset3D ((int)info.extent.width >> i, (int)info.extent.height >> i, 1) @@ -621,14 +676,20 @@ namespace vke { SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.TransferSrcOptimal, VkImageLayout.ShaderReadOnlyOptimal, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader); } - public void BlitTo (CommandBuffer cmd, Image dest) { + /// + /// Blit this image into another. + /// + /// a command buffer to handle the blit operation. + /// the destination image to blit to. + /// filtering for the blit operation. + public void BlitTo (CommandBuffer cmd, Image dest, VkFilter filter = VkFilter.Linear) { VkImageBlit imageBlit = new VkImageBlit { srcSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, info.arrayLayers, 0), srcOffsets_1 = new VkOffset3D ((int)info.extent.width, (int)info.extent.height, 1), dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, info.arrayLayers, 0), dstOffsets_1 = new VkOffset3D ((int)dest.info.extent.width, (int)dest.info.extent.height, 1) }; - vkCmdBlitImage (cmd.Handle, handle, VkImageLayout.TransferSrcOptimal, dest.handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, VkFilter.Linear); + vkCmdBlitImage (cmd.Handle, handle, VkImageLayout.TransferSrcOptimal, dest.handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, filter); } public VkSubresourceLayout GetSubresourceLayout (VkImageAspectFlags aspectMask = VkImageAspectFlags.Color, uint mipLevel = 0, uint arrayLayer = 0) { VkImageSubresource subresource = new VkImageSubresource { @@ -641,22 +702,22 @@ namespace vke { } public override string ToString () { - return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString("x")}]"); + return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString ("x")}]"); } #region IDisposable Support - protected override void Dispose (bool disposing) { + protected override void Dispose (bool disposing) { if (state == ActivableState.Activated) { if (Descriptor.sampler.Handle != 0) - Dev.DestroySampler (Descriptor.sampler); - if (Descriptor.imageView.Handle != 0) - Dev.DestroyImageView (Descriptor.imageView); + Dev.DestroySampler (Descriptor.sampler); + if (Descriptor.imageView.Handle != 0) + Dev.DestroyImageView (Descriptor.imageView); if (!imported) { base.Dispose (disposing); Dev.DestroyImage (handle); } } state = ActivableState.Disposed; - } + } #endregion } } diff --git a/vke/src/base/Queue.cs b/vke/src/base/Queue.cs index b37bd94..0f9cd69 100644 --- a/vke/src/base/Queue.cs +++ b/vke/src/base/Queue.cs @@ -86,7 +86,7 @@ namespace vke { if (freeCommandBuffer) cmd.Free (); } - public void Submit (CommandBuffer cmd, VkSemaphore wait = default(VkSemaphore), VkSemaphore signal = default (VkSemaphore), VkFence fence = default (VkFence)) { + public void Submit (CommandBuffer cmd, VkSemaphore wait = default, VkSemaphore signal = default, Fence fence = null) { cmd.Submit (handle, wait, signal, fence); } public void WaitIdle () { diff --git a/vke/src/base/RenderPass.cs b/vke/src/base/RenderPass.cs index 57ceddb..ddbaa64 100644 --- a/vke/src/base/RenderPass.cs +++ b/vke/src/base/RenderPass.cs @@ -221,12 +221,10 @@ namespace vke { vkCmdEndRenderPass (cmd.Handle); } /// - /// Create a one framebuffer per swapchain images of the supplied swapChain. - /// The presentable attachment of this renderpass is found searching for its final layout that could be - /// PresentSrcKHR or SharedPresentKHR. + /// 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. /// /// A collection of FrameBuffer - /// Swap chain. + /// a managed SwapChain instance. public FrameBuffers CreateFrameBuffers (SwapChain swapChain) { FrameBuffers fbs = new FrameBuffers(); Image[] images = new Image[attachments.Count]; diff --git a/vke/src/base/Resource.cs b/vke/src/base/Resource.cs index e489e35..8da99ec 100644 --- a/vke/src/base/Resource.cs +++ b/vke/src/base/Resource.cs @@ -10,6 +10,9 @@ using Vulkan; using static Vulkan.Vk; namespace vke { + /// + /// Abstract base class for Images and Buffers resources. + /// [DebuggerDisplay ("{previous.name} <- {name} -> {next.name}")] public abstract class Resource : Activable { protected VkMemoryRequirements memReqs; @@ -20,13 +23,16 @@ namespace vke { protected VkDeviceMemory vkMemory; #endif - /// double linked list in memory pool + /// Double linked list in memory pool internal Resource previous; public Resource next; + /// Effective memory allocation for the resource. public ulong AllocatedDeviceMemorySize => memReqs.size; public uint TypeBits => memReqs.memoryTypeBits; + /// Alignment constraint of the memory to allocate for the resource. public ulong MemoryAlignment => memReqs.alignment; + /// Boolean indicating if used memory for the resource is linear. public abstract bool IsLinar { get; } protected IntPtr mappedData; @@ -34,25 +40,25 @@ namespace vke { public readonly VkMemoryPropertyFlags MemoryFlags; - protected Resource (Device device, VkMemoryPropertyFlags memoryFlags) : base (device) { - MemoryFlags = memoryFlags; - } + protected Resource (Device device, VkMemoryPropertyFlags memoryFlags) : base (device) { + MemoryFlags = memoryFlags; + } - internal abstract void updateMemoryRequirements (); + internal abstract void updateMemoryRequirements (); internal abstract void bindMemory (); internal VkMappedMemoryRange MapRange => new VkMappedMemoryRange { - sType = VkStructureType.MappedMemoryRange, + sType = VkStructureType.MappedMemoryRange, #if MEMORY_POOLS - memory = memoryPool.vkMemory, - offset = poolOffset, + memory = memoryPool.vkMemory, + offset = poolOffset, #else memory = vkMemory, offset = 0, #endif - size = AllocatedDeviceMemorySize - }; + size = AllocatedDeviceMemorySize + }; #if !MEMORY_POOLS protected void allocateMemory () { VkMemoryAllocateInfo memInfo = VkMemoryAllocateInfo.New (); @@ -67,7 +73,7 @@ namespace vke { #if MEMORY_POOLS if (!memoryPool.IsMapped) memoryPool.Map (); - mappedData = new IntPtr(memoryPool.MappedData.ToInt64() + (long)(poolOffset + offset)); + mappedData = new IntPtr (memoryPool.MappedData.ToInt64 () + (long)(poolOffset + offset)); #else Utils.CheckResult (vkMapMemory (Dev.VkDev, vkMemory, offset, AllocatedDeviceMemorySize, 0, ref mappedData)); #endif @@ -80,19 +86,19 @@ namespace vke { #endif } public void Update (object data, ulong size, ulong offset = 0) { - GCHandle ptr = GCHandle.Alloc (data, GCHandleType.Pinned); - unsafe { - System.Buffer.MemoryCopy (ptr.AddrOfPinnedObject ().ToPointer (), (mappedData + (int)offset).ToPointer (), size, size); - } - ptr.Free (); - } - public void Flush () { + GCHandle ptr = GCHandle.Alloc (data, GCHandleType.Pinned); + unsafe { + System.Buffer.MemoryCopy (ptr.AddrOfPinnedObject ().ToPointer (), (mappedData + (int)offset).ToPointer (), size, size); + } + ptr.Free (); + } + public void Flush () { VkMappedMemoryRange range = MapRange; - vkFlushMappedMemoryRanges (Dev.VkDev, 1, ref range); - } + vkFlushMappedMemoryRanges (Dev.VkDev, 1, ref range); + } -#region IDisposable Support - protected override void Dispose (bool disposing) { + #region IDisposable Support + protected override void Dispose (bool disposing) { if (!disposing) System.Diagnostics.Debug.WriteLine ("VKE Activable object disposed by finalizer"); if (state == ActivableState.Activated) { @@ -106,7 +112,7 @@ namespace vke { } base.Dispose (disposing); - } -#endregion + } + #endregion } } \ No newline at end of file diff --git a/vke/src/base/SwapChain.cs b/vke/src/base/SwapChain.cs index eba607d..f9d5619 100644 --- a/vke/src/base/SwapChain.cs +++ b/vke/src/base/SwapChain.cs @@ -7,7 +7,7 @@ using Vulkan; using static Vulkan.Vk; namespace vke { - public class SwapChain : Activable { + public class SwapChain : Activable { /// /// Set the default swapchain image format. /// @@ -24,7 +24,7 @@ namespace vke { PresentQueue presentQueue; public VkSemaphore presentComplete; - public Image[] images; + public Image[] images; protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo => new VkDebugUtilsObjectNameInfoEXT (VkObjectType.SwapchainKHR, Handle.Handle); @@ -32,47 +32,47 @@ namespace vke { /// Swapchain images count. public uint ImageCount => (uint)images?.Length; public uint Width => createInfos.imageExtent.width; - public uint Height => createInfos.imageExtent.height; - public VkFormat ColorFormat => createInfos.imageFormat; - public VkImageUsageFlags ImageUsage => createInfos.imageUsage; - - public SwapChain (PresentQueue _presentableQueue, uint width = 800, uint height = 600, VkFormat format = VkFormat.B8g8r8a8Unorm, - VkPresentModeKHR presentMode = VkPresentModeKHR.FifoKHR) - : base (_presentableQueue.dev){ - - presentQueue = _presentableQueue; - createInfos = VkSwapchainCreateInfoKHR.New(); - - VkSurfaceFormatKHR[] formats = Dev.phy.GetSurfaceFormats (presentQueue.Surface); - for (int i = 0; i < formats.Length; i++) { - if (formats[i].format == format) { - createInfos.imageFormat = format; - createInfos.imageColorSpace = formats[i].colorSpace; - break; - } - } - if (createInfos.imageFormat == VkFormat.Undefined) - throw new Exception ("Invalid format for swapchain: " + format); - - VkPresentModeKHR[] presentModes = Dev.phy.GetSurfacePresentModes (presentQueue.Surface); - for (int i = 0; i < presentModes.Length; i++) { - if (presentModes[i] == presentMode) { - createInfos.presentMode = presentMode; - break; - } - } - if (createInfos.presentMode != presentMode) - throw new Exception ("Invalid presentMode for swapchain: " + presentMode); - - createInfos.surface = presentQueue.Surface; - createInfos.imageExtent = new VkExtent2D (width, height); - createInfos.imageArrayLayers = 1; - createInfos.imageUsage = IMAGES_USAGE; - createInfos.imageSharingMode = VkSharingMode.Exclusive; - createInfos.compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR; - createInfos.presentMode = presentMode; - createInfos.clipped = 1; - } + public uint Height => createInfos.imageExtent.height; + public VkFormat ColorFormat => createInfos.imageFormat; + public VkImageUsageFlags ImageUsage => createInfos.imageUsage; + + public SwapChain (PresentQueue _presentableQueue, uint width = 800, uint height = 600, VkFormat format = VkFormat.B8g8r8a8Unorm, + VkPresentModeKHR presentMode = VkPresentModeKHR.FifoKHR) + : base (_presentableQueue.dev) { + + presentQueue = _presentableQueue; + createInfos = VkSwapchainCreateInfoKHR.New (); + + VkSurfaceFormatKHR[] formats = Dev.phy.GetSurfaceFormats (presentQueue.Surface); + for (int i = 0; i < formats.Length; i++) { + if (formats[i].format == format) { + createInfos.imageFormat = format; + createInfos.imageColorSpace = formats[i].colorSpace; + break; + } + } + if (createInfos.imageFormat == VkFormat.Undefined) + throw new Exception ("Invalid format for swapchain: " + format); + + VkPresentModeKHR[] presentModes = Dev.phy.GetSurfacePresentModes (presentQueue.Surface); + for (int i = 0; i < presentModes.Length; i++) { + if (presentModes[i] == presentMode) { + createInfos.presentMode = presentMode; + break; + } + } + if (createInfos.presentMode != presentMode) + throw new Exception ("Invalid presentMode for swapchain: " + presentMode); + + createInfos.surface = presentQueue.Surface; + createInfos.imageExtent = new VkExtent2D (width, height); + createInfos.imageArrayLayers = 1; + createInfos.imageUsage = IMAGES_USAGE; + createInfos.imageSharingMode = VkSharingMode.Exclusive; + createInfos.compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR; + createInfos.presentMode = presentMode; + createInfos.clipped = 1; + } public override void Activate () { if (state != ActivableState.Activated) { presentComplete = Dev.CreateSemaphore (); @@ -87,63 +87,69 @@ namespace vke { Dev.WaitIdle (); - VkSurfaceCapabilitiesKHR capabilities = Dev.phy.GetSurfaceCapabilities (presentQueue.Surface); + VkSurfaceCapabilitiesKHR capabilities = Dev.phy.GetSurfaceCapabilities (presentQueue.Surface); - createInfos.minImageCount = capabilities.minImageCount; - createInfos.preTransform = capabilities.currentTransform; - createInfos.oldSwapchain = Handle; + createInfos.minImageCount = capabilities.minImageCount; + createInfos.preTransform = capabilities.currentTransform; + createInfos.oldSwapchain = Handle; - if (capabilities.currentExtent.width == 0xFFFFFFFF) { - if (createInfos.imageExtent.width < capabilities.minImageExtent.width) - createInfos.imageExtent.width = capabilities.minImageExtent.width; - else if (createInfos.imageExtent.width > capabilities.maxImageExtent.width) - createInfos.imageExtent.width = capabilities.maxImageExtent.width; + if (capabilities.currentExtent.width == 0xFFFFFFFF) { + if (createInfos.imageExtent.width < capabilities.minImageExtent.width) + createInfos.imageExtent.width = capabilities.minImageExtent.width; + else if (createInfos.imageExtent.width > capabilities.maxImageExtent.width) + createInfos.imageExtent.width = capabilities.maxImageExtent.width; - if (createInfos.imageExtent.height < capabilities.minImageExtent.height) - createInfos.imageExtent.height = capabilities.minImageExtent.height; - else if (createInfos.imageExtent.height > capabilities.maxImageExtent.height) - createInfos.imageExtent.height = capabilities.maxImageExtent.height; - } else - createInfos.imageExtent = capabilities.currentExtent; + if (createInfos.imageExtent.height < capabilities.minImageExtent.height) + createInfos.imageExtent.height = capabilities.minImageExtent.height; + else if (createInfos.imageExtent.height > capabilities.maxImageExtent.height) + createInfos.imageExtent.height = capabilities.maxImageExtent.height; + } else + createInfos.imageExtent = capabilities.currentExtent; - VkSwapchainKHR newSwapChain = Dev.CreateSwapChain (createInfos); - if (Handle.Handle != 0) - _destroy (); - Handle = newSwapChain; + Utils.CheckResult (vkCreateSwapchainKHR (Dev.VkDev, ref createInfos, IntPtr.Zero, out VkSwapchainKHR newSwapChain)); + + if (Handle.Handle != 0) + _destroy (); + Handle = newSwapChain; if (state != ActivableState.Activated) Activate (); - - VkImage[] tmp = Dev.GetSwapChainImages (Handle); - images = new Image[tmp.Length]; - for (int i = 0; i < tmp.Length; i++) { - images[i] = new Image (Dev, tmp[i], ColorFormat, ImageUsage, Width, Height); - images[i].CreateView (); + + Utils.CheckResult (vkGetSwapchainImagesKHR (Dev.VkDev, Handle, out uint imageCount, IntPtr.Zero)); + if (imageCount == 0) + throw new Exception ("Swapchain image count is 0."); + VkImage[] imgs = new VkImage[imageCount]; + Utils.CheckResult (vkGetSwapchainImagesKHR (Dev.VkDev, Handle, out imageCount, imgs.Pin ())); + imgs.Unpin (); + + images = new Image[imgs.Length]; + for (int i = 0; i < imgs.Length; i++) { + images[i] = new Image (Dev, imgs[i], ColorFormat, ImageUsage, Width, Height); + images[i].CreateView (); images[i].SetName ("SwapChain Img" + i); images[i].Descriptor.imageView.SetDebugMarkerName (Dev, "SwapChain Img" + i + " view"); - } - } + } + } /// /// Acquire next image, recreate swapchain if out of date or suboptimal error. /// /// Swapchain image index or -1 if failed /// Fence param of 'vkAcquireNextImageKHR' - public int GetNextImage (VkFence fence = default(VkFence)) { - VkResult res = vkAcquireNextImageKHR (Dev.VkDev, Handle, UInt64.MaxValue, presentComplete, fence, out currentImageIndex); - if (res == VkResult.ErrorOutOfDateKHR || res == VkResult.SuboptimalKHR) { - Create (); - return -1; - } - Utils.CheckResult (res); - return (int)currentImageIndex; - } + public int GetNextImage (VkFence fence = default (VkFence)) { + VkResult res = vkAcquireNextImageKHR (Dev.VkDev, Handle, UInt64.MaxValue, presentComplete, fence, out currentImageIndex); + if (res == VkResult.ErrorOutOfDateKHR || res == VkResult.SuboptimalKHR) { + Create (); + return -1; + } + Utils.CheckResult (res); + return (int)currentImageIndex; + } void _destroy () { - for (int i = 0; i < ImageCount; i++) - images[i].Dispose (); - - Dev.DestroySwapChain (Handle); - } + for (int i = 0; i < ImageCount; i++) + images[i].Dispose (); + vkDestroySwapchainKHR (Dev.VkDev, Handle, IntPtr.Zero); + } public override string ToString () { return string.Format ($"{base.ToString ()}[0x{Handle.Handle.ToString ("x")}]"); diff --git a/vke/src/glfw/CodePoint.cs b/vke/src/glfw/CodePoint.cs deleted file mode 100644 index a081e9f..0000000 --- a/vke/src/glfw/CodePoint.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -using System.Runtime.InteropServices; -using System.Text; - -namespace Glfw -{ - /// - /// Represents a native UTF32 codepoint. - /// - [StructLayout (LayoutKind.Explicit)] - public struct CodePoint - { - /// - /// The numeric value of the codepoint. - /// - [FieldOffset (0)] public readonly uint Value; - [FieldOffset (0)] readonly byte byte0; - [FieldOffset (1)] readonly byte byte1; - [FieldOffset (2)] readonly byte byte2; - [FieldOffset (3)] readonly byte byte3; - /// - /// Casts the codepoint to System.Char. - /// - /// - /// The character representation of the codepoint. - /// - public char ToChar() => Encoding.UTF32.GetChars (new byte[] { byte0, byte1, byte2, byte3 })[0]; - /// - /// Converts the value of this instance to its equivalent string representation. - /// - /// - /// A string containing the character representation of the codepoint. - /// - public override string ToString() => ToChar().ToString(); - } -} diff --git a/vke/src/glfw/Delegates.cs b/vke/src/glfw/Delegates.cs deleted file mode 100644 index bfcbb0e..0000000 --- a/vke/src/glfw/Delegates.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)using System; -using System; -using System.Runtime.InteropServices; - -namespace Glfw { - /// - /// The function signature for keyboard key callback functions. - /// - /// - /// The window that received the event. - /// - /// - /// The keyboard key that was pressed or released. - /// - /// - /// The system-specific scancode of the key. - /// - /// - /// The input action that occured. - /// - /// - /// Bit field describing which modifier keys were held down. - /// - public delegate void KeyDelegate (IntPtr window, Key key, int scanCode, InputAction action, Modifier modifiers); - /// - /// A delegate representing character events on a WindowHandle. - /// - /// - /// The window raising the event. - /// - /// - /// The Unicode codepoint of the character. - /// - public delegate void CharDelegate (IntPtr window, CodePoint codepoint); - /// - /// A delegate representing character events with modifiers on a WindowHandle. - /// - /// - /// The window raising the event. - /// - /// - /// The Unicode codepoint of the character. - /// - /// - /// The modifiers applied to the character. - /// - public delegate void CharModsDelegate (IntPtr window, CodePoint codepoint, Modifier modifiers); - /// - /// The function signature for cursor position callback functions. - /// - /// - /// The window that received the event. - /// - /// - /// The new cursor x-coordinate, relative to the left edge of the client area. - /// - /// - /// The new cursor y-coordinate, relative to the top edge of the client area. - /// - public delegate void CursorPosDelegate (IntPtr window, double xPosition, double yPosition); - /// - /// The function signature for error callbacks. - /// - /// An error code giving the general category of the error. - /// A string description of the error. - [UnmanagedFunctionPointer (CallingConvention.Cdecl)] - public delegate void ErrorDelegate (ErrorCode error, [MarshalAs (UnmanagedType.LPStr)] string description); - /// - /// The function signature for monitor configuration callback functions. - /// - /// - /// The monitor that was connected or disconnected. - /// - /// - /// The event that was raised. - /// - [UnmanagedFunctionPointer (CallingConvention.Cdecl)] - public delegate void MonitorEventDelegate (MonitorHandle monitor, MonitorEvent eventStatus); - /// - /// The function signature for mouse button callback functions. - /// - /// - /// The window that received the event. - /// - /// - /// The mouse button that was pressed or released. - /// - /// - /// One of or . - /// - /// - /// Bit field describing which modifier keys were held down. - /// - public delegate void MouseButtonDelegate (IntPtr window, MouseButton button, InputAction action, Modifier mods); - /// - /// The function signature for scroll callback functions. - /// - /// - /// The window that received the event. - /// - /// - /// The scroll offset along the x-axis. - /// - /// - /// The scroll offset along the y-axis. - /// - public delegate void ScrollDelegate (IntPtr window, double xOffset, double yOffset); - /// - /// The function signature for window size callback functions. - /// - /// - /// The window that was resized. - /// - /// - /// The new width, in screen coordinates, of the window. - /// - /// - /// The new height, in screen coordinates, of the window. - /// - [UnmanagedFunctionPointer (CallingConvention.Cdecl)] - public delegate void WindowSizeDelegate (IntPtr window, int width, int height); - -} - diff --git a/vke/src/glfw/ErrorCode.cs b/vke/src/glfw/ErrorCode.cs deleted file mode 100644 index ef76890..0000000 --- a/vke/src/glfw/ErrorCode.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -namespace Glfw -{ - /// - /// Indicates the general category of an error. - /// - public enum ErrorCode - { - /// - /// GLFW has not been initialized. - /// - NotInitialised = 0x00010001, - /// - /// No context is current for this thread. - /// - NoCurrentContext, - /// - /// One of the arguments to the function was an invalid enum value. - /// - InvalidEnum, - /// - /// One of the arguments to the function was an invalid value. - /// - InvalidValue, - /// - /// A memory allocation failed. - /// - OutOfMemory, - /// - /// GLFW could not find support for the requested API on the system. - /// - ApiUnavailable, - /// - /// The requested OpenGL or OpenGL ES version is not available. - /// - VersionUnavailable, - /// - /// A platform-specific error occurred that does not match any of the more specific categories. - /// - PlatformError, - /// - /// The requested format is not supported or available. - /// - FormatUnavailable, - /// - /// The specified window does not have an OpenGL or OpenGL ES context. - /// - NoWindowContext - } -} diff --git a/vke/src/glfw/Glfw3.cs b/vke/src/glfw/Glfw3.cs deleted file mode 100644 index 081ec5c..0000000 --- a/vke/src/glfw/Glfw3.cs +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -using System; -using System.Runtime.InteropServices; - -namespace Glfw { - public enum CursorShape - { - Arrow = 0x00036001, - IBeam = 0x00036002, - Crosshair = 0x00036003, - Hand = 0x00036004, - HResize = 0x00036005, - VResize = 0x00036006 - } - /// - /// Interop functions for the GLFW3 API. - /// - public static class Glfw3 - { - /// - /// The base name for the GLFW3 library. - /// - public const string GlfwDll = "glfw"; - - /// - /// Initializes the GLFW library. - /// - /// - /// True if successful, otherwise false. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwInit")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool Init(); - - /// - /// This function destroys all remaining windows and cursors, restores - /// any modified gamma ramps and frees any other allocated resources. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwTerminate")] - public static extern void Terminate(); - - /// - /// This function retrieves the major, minor and revision numbers of - /// the GLFW library. - /// - /// - /// The major version number. - /// - /// - /// The minor version number. - /// - /// - /// The revision number. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetVersion")] - public static extern void GetVersion(out int major, out int minor, out int rev); - - - /// - /// Returns the compile-time generated version string of the GLFW - /// library binary. It describes the version, platform, compiler and - /// any platform-specific compile-time options. - /// - /// - /// The compile-time generated version string of the GLFW library - /// binary. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetVersionString")] - public static extern NativeString GetVersionString(); - - /// - /// Creates a window and its associated OpenGL or OpenGL ES context. - /// Most of the options controlling how the window and its context - /// should be created are specified with window hints. - /// - /// - /// The desired width, in screen coordinates, of the window. This must - /// be greater than zero. - /// - /// - /// The desired height, in screen coordinates, of the window. This must - /// be greater than zero. - /// - /// - /// The initial window title. - /// - /// - /// The monitor to use for full screen mode, or Null for windowed mode. - /// - /// - /// The window whose context to share resources with, or Null to not share resources. - /// - /// - /// The handle of the created window, or Null if an error occurred. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwCreateWindow")] - public static extern IntPtr CreateWindow(int width, int height, [MarshalAs(UnmanagedType.LPStr)] string title, MonitorHandle monitor, IntPtr share); - - /// - /// Destroys the specified window and its context. On calling this - /// function, no further callbacks will be called for that window. - /// - /// - /// The window to destroy. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwDestroyWindow")] - public static extern void DestroyWindow(IntPtr window); - - /// - /// Processes events in the event queue and then returns immediately. - /// Processing events will cause the window and input callbacks - /// associated with those events to be called. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwPollEvents")] - public static extern void PollEvents(); - - /// - /// Sets hints for the next call to CreateWindow. The hints, once set, - /// retain their values until changed by a call to WindowHint or - /// DefaultWindowHints, or until the library is terminated. - /// - /// - /// The window hint to set. - /// - /// - /// The new value of the window hint. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwWindowHint")] - public static extern void WindowHint(WindowAttribute hint, int value); - - /// - /// Returns the value of the close flag of the specified window. - /// - /// - /// The window to query. - /// - /// - /// The value of the close flag. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwWindowShouldClose")] - public static extern bool WindowShouldClose(IntPtr window); - - [DllImport (GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetWindowShouldClose")] - public static extern void SetWindowShouldClose (IntPtr window, int value); - - [DllImport (GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetWindowTitle")] - public static extern void SetWindowTitle (IntPtr window, [MarshalAs (UnmanagedType.LPStr)] string title); - - /// - /// Creates a Vulkan surface for the specified window. - /// - /// - /// The Vulkan instance to create the surface in. - /// - /// - /// The window to create the surface for. - /// - /// - /// The allocator to use, or NULL to use the default allocator. - /// - /// - /// Where to store the handle of the surface. This is set to - /// VK_NULL_HANDLE if an error occurred. - /// - /// - /// Result.Success if successful, or a Vulkan error code if an error - /// occurred. - /// - [DllImport (GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwCreateWindowSurface")] - public static extern int CreateWindowSurface(IntPtr instance, IntPtr window, IntPtr pAllocator, out ulong surface); - - /// - /// Returns an array of names of Vulkan instance extensions required by - /// GLFW for creating Vulkan surfaces for GLFW windows. If successful, - /// the list will always contains VK_KHR_surface, so if you don't - /// require any additional extensions you can pass this list directly - /// to the InstanceCreateInfo struct. - /// - /// - /// Where to store the number of extensions in the returned array. This - /// is set to zero if an error occurred. - /// - /// - /// An array of extension names, or Null if an error occurred. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetRequiredInstanceExtensions")] - public static extern IntPtr GetRequiredInstanceExtensions(out int count); - - /// - /// Sets the size callback of the specified window, which is called - /// when the window is resized. The callback is provided with the size, - /// in screen coordinates, of the client area of the window. - /// - /// - /// The window whose callback to set. - /// - /// - /// The new callback, or Null to remove the currently set callback. - /// - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetWindowSizeCallback")] - public static extern WindowSizeDelegate SetWindowSizeCallback(IntPtr window, WindowSizeDelegate callback); - - /// - /// Sets the error callback, which is called with an error code and a - /// human-readable description each time a GLFW error occurs. - /// - /// - /// The new callback, or Null to remove the currently set callback. - /// - /// - /// The previously set callback, or Null if no callback was set. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetErrorCallback")] - public static extern ErrorDelegate SetErrorCallback(ErrorDelegate callback); - - /// - /// Returns an array of handles for all currently connected monitors. - /// The primary monitor is always first in the returned array. If no - /// monitors were found, this function returns Null. - /// - /// - /// Where to store the number of monitors in the returned array. This - /// is set to zero if an error occurred. - /// - /// - /// An array of monitor handles, or Null if no monitors were found or - /// if an error occurred. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetMonitors")] - public static extern IntPtr GetMonitors(out int count); - - /// - /// Returns the primary monitor. This is usually the monitor where - /// elements like the task bar or global menu bar are located. - /// - /// - /// The primary monitor, or Null if no monitors were found or if an - /// error occurred. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetPrimaryMonitor")] - public static extern MonitorHandle GetPrimaryMonitor(); - - /// - /// Returns the position, in screen coordinates, of the upper-left - /// corner of the specified monitor. - /// - /// - /// The monitor to query. - /// - /// - /// Returns the monitor x-coordinate. - /// - /// - /// Returns the monitor y-coordinate. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetMonitorPos")] - public static extern void GetMonitorPos(MonitorHandle monitor, out int xPos, out int yPos); - - /// - /// Returns the size, in millimetres, of the display area of the - /// specified monitor. - /// - /// - /// The monitor to query. - /// - /// - /// The width, in millimetres, of the monitor's display area. - /// - /// - /// The width, in millimetres, of the monitor's display area. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetMonitorPhysicalSize")] - public static extern void GetMonitorPhysicalSize(MonitorHandle monitor, out int widthMm, out int heightMm); - - /// - /// Returns a human-readable name, of the specified monitor. The name - /// typically reflects the make and model of the monitor and is not - /// guaranteed to be unique among the connected monitors. - /// - /// - /// The monitor to query. - /// - /// - /// The name of the monitor, or Null if an error occurred. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetMonitorName")] - public static extern NativeString GetMonitorName(MonitorHandle monitor); - - /// - /// Sets the monitor configuration callback, or removes the currently - /// set callback. This is called when a monitor is connected to or - /// disconnected from the system. - /// - /// - /// The new callback, or Null to remove the currently set callback. - /// - /// - /// The previously set callback, or NULL if no callback was set or the - /// library had not been initialized. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetMonitorCallback")] - public static extern MonitorEventDelegate SetMonitorCallback(MonitorEventDelegate callback); - - /// - /// Returns an array of all video modes supported by the specified - /// monitor. The returned array is sorted in ascending order, first by - /// color bit depth (the sum of all channel depths) and then by - /// resolution area (the product of width and height). - /// - /// - /// The monitor to query. - /// - /// - /// Tthe number of video modes in the returned array. This is set to - /// zero if an error occurred. - /// - /// - /// An array of video modes, or Null if an error occurred. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetVideoModes")] - public static extern IntPtr GetVideoModes(MonitorHandle monitor, out int count); - - /// - /// Returns the current video mode of the specified monitor. If you - /// have created a full screen window for that monitor, the return - /// value will depend on whether that window is iconified. - /// - /// - /// The monitor to query. - /// - /// - /// A wrapped pointer to the current mode of the monitor, or Null if - /// an error occurred. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetVideoMode")] - public static extern VideoModePointer GetVideoMode(MonitorHandle monitor); - - /// - /// Generates a 256-element gamma ramp from the specified exponent and - /// then calls glfwSetGammaRamp with it. The value must be a finite - /// number greater than zero. - /// - /// - /// The monitor whose gamma ramp to set. - /// - /// - /// The desired exponent. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetGamma")] - public static extern void SetGamma(MonitorHandle monitor, float gamma); - - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetInputMode")] - public static extern int GetInputMode(IntPtr window, int mode); - - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetInputMode")] - public static extern void SetInputMode(IntPtr window, int mode, int value); - - /// - /// Returns the localized name of the specified printable key. This is - /// intended for displaying key bindings to the user. - /// - /// - /// The key to query, or Key.Unknown. - /// - /// - /// The scancode of the key to query, if key is Key.Unknown. - /// - /// - /// The localized name of the key, or Null. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetKeyName")] - public static extern NativeString GetKeyName(Key key, int scancode); - - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetKey")] - public static extern InputAction GetKey(IntPtr window, Key key); - - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetMouseButton")] - public static extern InputAction GetMouseButton(IntPtr window, MouseButton button); - - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwGetCursorPos")] - public static extern void GetCursorPosition(IntPtr window, out double xPosition, out double yPosition); - - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetCursorPos")] - public static extern void SetCursorPosition(IntPtr window, double xPosition, double yPosition); - - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetKeyCallback")] - public static extern KeyDelegate SetKeyCallback(IntPtr window, KeyDelegate callback); - - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetCharCallback")] - public static extern KeyDelegate SetCharCallback(IntPtr window, CharDelegate callback); - - /// - /// Sets a callback for Mouse movement events. Use this for full - /// mouse path resolution between PollEvents() calls. - /// From GLFW Documentation: The callback functions receives the - /// cursor position, measured in screen coordinates but relative to the - /// top-left corner of the window client area. On platforms that - /// provide it, the full sub-pixel cursor position is passed on. - /// - /// - /// The previously set callback, or NULL if no callback was set or the - /// library had not been initialized. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetCursorPosCallback")] - public static extern CursorPosDelegate SetCursorPosCallback(IntPtr window, CursorPosDelegate callback); - - /// - /// Sets a Callback for Button Events (i.e. clicks). This also - /// detects mouse press and release events done between PollEvents() - /// calls. - /// From GLFW Documentation: Whenever you poll state, you risk - /// missing the state change you are looking for. If a pressed mouse - /// button is released again before you poll its state, you will have - /// missed the button press. The recommended solution for this is to - /// use a mouse button callback, but there is also the - /// GLFW_STICKY_MOUSE_BUTTONS input mode. - /// - /// - /// The previously set callback, or NULL if no callback was set or the - /// library had not been initialized. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetMouseButtonCallback")] - public static extern MouseButtonDelegate SetMouseButtonPosCallback(IntPtr window, MouseButtonDelegate callback); - - /// - /// Sets a Callback for Mouse Scrolling Events. (i.e. scroll wheel) - /// There is no polling support for this, so if youre interested in the wheel, you have to set this callback - /// NOTE: your normal desktop mouse variant likely only reports Y-Coordinate - /// - /// - /// The previously set callback, or NULL if no callback was set or the - /// library had not been initialized. - /// - [DllImport(GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetScrollCallback")] - public static extern ScrollDelegate SetScrollCallback(IntPtr window, ScrollDelegate callback); - - /// - /// Returns an array of names of Vulkan instance extensions required by - /// GLFW for creating Vulkan surfaces for GLFW windows. If successful, - /// the list will always contains VK_KHR_surface, so if you don't - /// require any additional extensions you can pass this list directly - /// to the InstanceCreateInfo struct. - /// - /// - /// An array of extension names, or Null if an error occurred. - /// - public static string[] GetRequiredInstanceExtensions() - { - IntPtr names = GetRequiredInstanceExtensions(out int count); - - string[] result = new string[count]; - - for (int nameIndex = 0; nameIndex < count; nameIndex++) - { - IntPtr name = Marshal.ReadIntPtr (names, nameIndex * Marshal.SizeOf()); - result[nameIndex] = Marshal.PtrToStringAnsi(name); - } - - return result; - } - - /// - /// Returns an array of handles for all currently connected monitors. - /// The primary monitor is always first in the returned array. If no - /// monitors were found, this function returns Null. - /// - /// - /// An array of monitor handles, or Null if no monitors were found or - /// if an error occurred. - /// - public static MonitorHandle[] GetMonitors() - { - IntPtr monitors = GetMonitors(out int count); - - var result = new MonitorHandle[count]; - - for (int i = 0; i < count; i++) - result[i] = new MonitorHandle(Marshal.ReadIntPtr(monitors, i)); - - return result; - } - - /// - /// Returns an array of all video modes supported by the specified - /// monitor. The returned array is sorted in ascending order, first by - /// color bit depth (the sum of all channel depths) and then by - /// resolution area (the product of width and height). - /// - /// - /// The monitor to query. - /// - /// - /// An array of video modes, or Null if an error occurred. - /// - public static VideoMode[] GetVideoModes(MonitorHandle monitor) - { - IntPtr videoModes = GetVideoModes(monitor, out int count); - - var result = new VideoMode[count]; - - for (int i = 0; i < count; i++) - result[i] = Marshal.PtrToStructure(Marshal.ReadIntPtr(videoModes, i)); - - return result; - } - - /// - /// This function retrieves the version number of the GLFW library. - /// - /// - /// The version number of the GLFW library. - /// - public static Version GetVersion() - { - GetVersion(out int major, out int minor, out int revision); - - return new Version(major, minor, revision); - } - - [DllImport (GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwCreateStandardCursor")] - public static extern IntPtr CreateStandardCursor (CursorShape shape); - - [DllImport (GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwDestroyCursor")] - public static extern void DestroyCursor (IntPtr cursor); - - [DllImport (GlfwDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "glfwSetCursor")] - public static extern void SetCursor (IntPtr window, IntPtr cursor); - } -} diff --git a/vke/src/glfw/InputAction.cs b/vke/src/glfw/InputAction.cs deleted file mode 100644 index 3ee57f7..0000000 --- a/vke/src/glfw/InputAction.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -namespace Glfw -{ - /// - /// Represents the action of an input key event or the state of a key. - /// - public enum InputAction - { - /// - /// The key was released or is not pressed. - /// - Release = 0, - /// - /// The key was or is pressed. - /// - Press = 1, - /// - /// The key has been held down long enough to repeat. - /// - Repeat = 2 - } -} diff --git a/vke/src/glfw/Key.cs b/vke/src/glfw/Key.cs deleted file mode 100644 index 1e8c19d..0000000 --- a/vke/src/glfw/Key.cs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -namespace Glfw -{ - /// - /// Represents a key on a keyboard. - /// - public enum Key - { - Unknown = -1, - Space = 32, - Apostrophe = 39, - Comma = 44, - Minus = 45, - Period = 46, - Slash = 47, - Num0 = 48, - Num1 = 49, - Num2 = 50, - Num3 = 51, - Num4 = 52, - Num5 = 53, - Num6 = 54, - Num7 = 55, - Num8 = 56, - Num9 = 57, - Semicolon = 59, - Equal = 61, - A = 65, - B = 66, - C = 67, - D = 68, - E = 69, - F = 70, - G = 71, - H = 72, - I = 73, - J = 74, - K = 75, - L = 76, - M = 77, - N = 78, - O = 79, - P = 80, - Q = 81, - R = 82, - S = 83, - T = 84, - U = 85, - V = 86, - W = 87, - X = 88, - Y = 89, - Z = 90, - LeftBracket = 91, - Backslash = 92, - RightBracket = 93, - GraveAccent = 96, - World1 = 161, - World2 = 162, - Escape = 256, - Enter = 257, - Tab = 258, - Backspace = 259, - Insert = 260, - Delete = 261, - Right = 262, - Left = 263, - Down = 264, - Up = 265, - PageUp = 266, - PageDown = 267, - Home = 268, - End = 269, - CapsLock = 280, - ScrollLock = 281, - NumLock = 282, - PrintScreen = 283, - Pause = 284, - F1 = 290, - F2 = 291, - F3 = 292, - F4 = 293, - F5 = 294, - F6 = 295, - F7 = 296, - F8 = 297, - F9 = 298, - F10 = 299, - F11 = 300, - F12 = 301, - F13 = 302, - F14 = 303, - F15 = 304, - F16 = 305, - F17 = 306, - F18 = 307, - F19 = 308, - F20 = 309, - F21 = 310, - F22 = 311, - F23 = 312, - F24 = 313, - F25 = 314, - Keypad0 = 320, - Keypad1 = 321, - Keypad2 = 322, - Keypad3 = 323, - Keypad4 = 324, - Keypad5 = 325, - Keypad6 = 326, - Keypad7 = 327, - Keypad8 = 328, - Keypad9 = 329, - KeypadDecimal = 330, - KeypadDivide = 331, - KeypadMultiply = 332, - KeypadSubtract = 333, - KeypadAdd = 334, - KeypadEnter = 335, - KeypadEqual = 336, - LeftShift = 340, - LeftControl = 341, - LeftAlt = 342, - LeftSuper = 343, - RightShift = 344, - RightControl = 345, - RightAlt = 346, - RightSuper = 347, - Menu = 348, - } -} diff --git a/vke/src/glfw/Modifier.cs b/vke/src/glfw/Modifier.cs deleted file mode 100644 index 98205c7..0000000 --- a/vke/src/glfw/Modifier.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -using System; - -namespace Glfw -{ - /// - /// Bitmask indicating modifer keys. - /// - [Flags] - public enum Modifier - { - Shift = 0x1, - Control = 0x2, - Alt = 0x4, - Super = 0x8, - } -} \ No newline at end of file diff --git a/vke/src/glfw/MonitorEvent.cs b/vke/src/glfw/MonitorEvent.cs deleted file mode 100644 index d93397b..0000000 --- a/vke/src/glfw/MonitorEvent.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -namespace Glfw -{ - /// - /// Events that may be raised from a monitor callback. - /// - public enum MonitorEvent - { - /// - /// The monitor was connected. - /// - Connected = 0x00040001, - /// - /// The monitor was disconnected. - /// - Disconnected = 0x00040002 - } -} diff --git a/vke/src/glfw/MonitorHandle.cs b/vke/src/glfw/MonitorHandle.cs deleted file mode 100644 index 38ed035..0000000 --- a/vke/src/glfw/MonitorHandle.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -using System; - -namespace Glfw -{ - /// - /// Opaque monitor handle. - /// - public struct MonitorHandle - { - readonly IntPtr handle; - - internal MonitorHandle(IntPtr handle) - { - this.handle = handle; - } - /// - /// Gets the underlying native pointer to the monitor object. - /// - public IntPtr RawHandle => handle; - /// - /// A read-only field that represents a MonitorHandle that has been - /// inititalised to zero. - /// - public static readonly MonitorHandle Zero = new MonitorHandle (IntPtr.Zero); - } -} diff --git a/vke/src/glfw/MouseButton.cs b/vke/src/glfw/MouseButton.cs deleted file mode 100644 index b29184a..0000000 --- a/vke/src/glfw/MouseButton.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -namespace Glfw -{ - /// - /// The index and name of mouse buttons for callbacks. - /// - public enum MouseButton - { - /// - /// The first mouse button. - /// - Button1 = 0, - /// - /// The second mouse button. - /// - Button2 = 1, - /// - /// The third mouse button. - /// - Button3 = 2, - /// - /// The fourth mouse button. - /// - Button4 = 3, - /// - /// The fifth mouse button. - /// - Button5 = 4, - /// - /// The sixth mouse button. - /// - Button6 = 5, - /// - /// The seven mouse button. - /// - Button7 = 6, - /// - /// The eighth mouse button. - /// - Button8 = 7, - /// - /// The left mouse button. - /// - Left = Button1, - /// - /// The right mouse button. - /// - Right = Button2, - /// - /// The middle mouse button. - /// - Middle = Button3, - /// - /// The highest-indexed mouse button. - /// - Last = Button8 - } -} diff --git a/vke/src/glfw/NativeString.cs b/vke/src/glfw/NativeString.cs deleted file mode 100644 index 02181cb..0000000 --- a/vke/src/glfw/NativeString.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -namespace Glfw -{ - /// - /// Wraps a pointer to a native, null-terminated ANSI string. - /// - public struct NativeString - { - internal NativeString(IntPtr pointer) - { - this.pointer = pointer; - } - - readonly IntPtr pointer; - - /// - /// Gets the marshalled string value for this native string. - /// - public string Value => IsNull ? throw new NullReferenceException () : Marshal.PtrToStringAnsi (this.pointer); - /// - /// Gets a value indicating whether the pointer wrapped by this - /// instance is null. - /// - public bool IsNull => pointer == IntPtr.Zero; - - /// - /// The underlying pointer wrapped by this instance. - /// - public IntPtr RawPointer => pointer; - - public override string ToString() - { - return Value; - } - } -} diff --git a/vke/src/glfw/VideoMode.cs b/vke/src/glfw/VideoMode.cs deleted file mode 100644 index baeb196..0000000 --- a/vke/src/glfw/VideoMode.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Glfw -{ - /// - /// Represents a single video mode. - /// - [StructLayout(LayoutKind.Sequential)] - public struct VideoMode - { - private readonly int width; - private readonly int height; - private readonly int redBits; - private readonly int greenBits; - private readonly int blueBits; - - /// - /// The resolution, in screen coordinates, of the video mode. - /// - public (int Width, int Height) Resolution => (this.width, this.height); - - /// - /// The bit depth of the red channel of the video mode. - /// - public (int Red, int Green, int Blue) Bits => (this.redBits, this.greenBits, this.blueBits); - - /// - /// The refresh rate, in Hz, of the video mode. - /// - public int RefreshRate; - - /// - /// Returns a string representation of this video mode. - /// - /// - /// A string representation of this video mode. - /// - public override string ToString() - { - return $"[Resolution: {this.Resolution}, Bit Depth: {this.Bits}, Refresh Rate: {this.RefreshRate}Hz]"; - } - } -} diff --git a/vke/src/glfw/VideoModePointer.cs b/vke/src/glfw/VideoModePointer.cs deleted file mode 100644 index 66631c6..0000000 --- a/vke/src/glfw/VideoModePointer.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -using System; -using System.Runtime.InteropServices; - -namespace Glfw -{ - /// - /// Wraps a pointer to a VideoMode struct. - /// - public struct VideoModePointer - { - private readonly IntPtr pointer; - internal VideoModePointer (IntPtr pointer) - { - this.pointer = pointer; - } - /// - /// Gets the VideoMode value at the referenced memory location. - /// - public VideoMode Value => IsNull ? throw new NullReferenceException() : Marshal.PtrToStructure(pointer); - /// - /// Gets a value indicating whether the pointer wrapped by this - /// instance is null. - /// - public bool IsNull => pointer == IntPtr.Zero; - /// - /// The underlying pointer wrapped by this instance. - /// - public IntPtr RawPointer => pointer; - } -} diff --git a/vke/src/glfw/WindowAttribute.cs b/vke/src/glfw/WindowAttribute.cs deleted file mode 100644 index f772667..0000000 --- a/vke/src/glfw/WindowAttribute.cs +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2019 Andrew Armstrong/FacticiusVir -// Copyright (c) 2019 Jean-Philippe Bruyère -// -// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) -namespace Glfw -{ - /// - /// Attributes of a window or its framebuffer or context, that can be - /// configured/queried at runtime or hinted at creation. - /// - public enum WindowAttribute - { - /// - /// Whether the specified window has input focus. This hint is ignored - /// for full screen and initially hidden windows. - /// - Focused = 0x00020001, - /// - /// Whether the specified window is iconified (minimized). - /// - Iconified = 0x00020002, - /// - /// Whether the specified window is resizable by the user. This is set - /// on creation. - /// - Resizable = 0x00020003, - /// - /// Whether the specified window is visible. - /// - Visible = 0x00020004, - /// - /// Whether the specified window has decorations such as a border, a - /// close widget, etc. This is set on creation. - /// - Decorated = 0x00020005, - /// - /// Whether the full screen window will automatically iconify and - /// restore the previous default framebuffer on input focus loss. This hint is - /// ignored for windowed mode windows. - /// - AutoIconify = 0x00020006, - /// - /// Whether the windowed mode window will be floating above other - /// regular windows, also called topmost or always-on-top. This is - /// intended primarily for debugging purposes and cannot be used to - /// implement proper full screen windows. This hint is ignored for full - /// screen windows. - /// - Floating = 0x00020007, - /// - /// Whether the specified window is maximized. - /// - Maximized = 0x00020008, - /// - /// The bit depth of the red channel of the default framebuffer. - /// - RedBits = 0x00021001, - /// - /// The bit depth of the green channel of the default framebuffer. - /// - GreenBits = 0x00021002, - /// - /// The bit depth of the blue channel of the default framebuffer. - /// - BlueBits = 0x00021003, - /// - /// The bit depth of the alpha channel of the default framebuffer. - /// - AlphaBits = 0x00021004, - /// - /// The bit depth of the depth channel of the default framebuffer. - /// - DepthBits = 0x00021005, - /// - /// The bit depth of the stencil channel of the default framebuffer. - /// - StencilBits = 0x00021006, - /// - /// The desired bit depth of the red channel of the accumulation - /// buffer. Accumulation buffers are a legacy OpenGL feature and - /// should not be used in new code. - /// - AccumRedBits = 0x00021007, - /// - /// The desired bit depth of the green channel of the accumulation - /// buffer. Accumulation buffers are a legacy OpenGL feature and - /// should not be used in new code. - /// - AccumGreenBits = 0x00021008, - /// - /// The desired bit depth of the blue channel of the accumulation - /// buffer. Accumulation buffers are a legacy OpenGL feature and - /// should not be used in new code. - /// - AccumBlueBits = 0x00021009, - /// - /// The desired bit depth of the alpha channel of the accumulation - /// buffer. Accumulation buffers are a legacy OpenGL feature and - /// should not be used in new code. - /// - AccumAlphaBits = 0x0002100A, - /// - /// The desired number of auxiliary buffers. Auxiliary buffers are a - /// legacy OpenGL feature and should not be used in new code. - /// - AuxBuffers = 0x0002100B, - /// - /// Whether to use stereoscopic rendering. - /// - Stereo = 0x0002100C, - /// - /// The desired number of samples to use for multisampling. Zero - /// disables multisampling. - /// - Samples = 0x0002100D, - /// - /// Whether the framebuffer should be sRGB capable. - /// - SrgbCapable = 0x0002100E, - /// - /// The desired refresh rate for full screen windows. This hint is - /// ignored for windowed mode windows. - /// - RefreshRate = 0x0002100F, - /// - /// Whether the framebuffer should be double buffered. - /// - DoubleBuffer = 0x00021010, - /// - /// Specifies which client API to create the context for. - /// - ClientApi = 0x00022001, - /// - /// Specifies the major component of the client API version of the - /// window's context. - /// - ContextVersionMajor = 0x00022002, - /// - /// Specifies the minor component of the client API version of the - /// window's context. - /// - ContextVersionMinor = 0x00022003, - /// - /// Specifies the revision component of the client API version of the - /// window's context. - /// - ContextRevision = 0x00022004, - /// - /// The robustness strategy used by the context. - /// - ContextRobustness = 0x00022005, - /// - /// Specifies whether the OpenGL context should be forward-compatible, - /// i.e. one where all functionality deprecated in the requested - /// version of OpenGL is removed. If OpenGL ES is requested, this hint - /// is ignored. - /// - OpenGlForwardCompat = 0x00022006, - /// - /// Specifies whether to create a debug OpenGL context, which may have - /// additional error and performance issue reporting functionality. If - /// OpenGL ES is requested, this hint is ignored. - /// - OpenGlDebugContext = 0x00022007, - /// - /// The OpenGL profile used by the context. - /// - OpenGlProfile = 0x00022008, - /// - /// Specifies the release behavior to be used by the context. - /// - ContextReleaseBehavior = 0x00022009, - /// - /// Specifies whether errors should be generated by the context. If - /// enabled, situations that would have generated errors instead cause - /// undefined behavior. - /// - ContextNoError = 0x0002200A, - /// - /// The context creation API used to create the window's context. - /// - ContextCreationApi = 0x0002200B - } -} diff --git a/vke/vke.csproj b/vke/vke.csproj index 2e3a86b..c81f77b 100644 --- a/vke/vke.csproj +++ b/vke/vke.csproj @@ -10,14 +10,17 @@ https://github.com/jpbruyere/vke.net vulkan game engine compute glfw c# $(VkePackageVersion) + True true + False https://github.com/jpbruyere/vke.net/blob/master/README.md MIT Jean-Philippe Bruyère + false @@ -49,11 +52,12 @@ + - +