language: csharp
-dist: bionic
+dist: bionic
dotnet: 3.1
before_install:
- wget -qO - http://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
- - sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-bionic.list https://packages.lunarg.com/vulkan/lunarg-vulkan-bionic.list
+ - sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-bionic.list https://packages.lunarg.com/vulkan/lunarg-vulkan-bionic.list
- sudo apt -qq update
- sudo apt -y install vulkan-sdk
script:
- dotnet build /p:Configuration=ReleaseSpirVTasks
- dotnet build /p:Configuration=Release
-
+
"console": "internalConsole"
},
{
- "name": ".NET Core Launch (console)",
+ "name": ".NET Core Launch (ImmutableSampler)",
"type": "coreclr",
"request": "launch",
- "preLaunchTask": "build",
- "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/Triangle",
+ "preLaunchTask": "build immutableSampler",
+ "program": "${workspaceFolder}/build/Debug/netcoreapp3.1/ImmutableSampler",
"args": [],
"cwd": "${workspaceFolder}/build/Debug/netcoreapp3.1/",
"console": "internalConsole",
],
"problemMatcher": "$msCompile"
},
+ {
+ "label": "build immutableSampler",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/samples/ImmutableSampler/ImmutableSampler.csproj",
+ "/property:GenerateFullPaths=true",
+ "/property:SolutionDir=${workspaceFolder}/",
+ "/property:Configuration=Debug",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
{
"label": "publish",
"command": "dotnet",
<RestoreAdditionalProjectSources Condition="Exists('$(SolutionDir)build\$(Configuration)\')">$(SolutionDir)build\$(Configuration)\</RestoreAdditionalProjectSources>
<SpirVTasksReleaseVersion>0.1.45</SpirVTasksReleaseVersion>
<SpirVTasksPackageVersion>$(SpirVTasksReleaseVersion)</SpirVTasksPackageVersion>
- <VkeReleaseVersion>0.2.1</VkeReleaseVersion>
+ <VkeReleaseVersion>0.2.2</VkeReleaseVersion>
<VkePackageVersion>$(VkeReleaseVersion)-beta</VkePackageVersion>
<UseStbSharp>true</UseStbSharp>
<UseMemoryPools>false</UseMemoryPools>
<h1 align="center">
vke.net
- <br>
+ <br>
Vulkan Engine for .NET
- <br>
+ <br>
<p align="center">
<a href="https://www.nuget.org/packages/vke"><img src="https://buildstats.info/nuget/vke"></a>
<a href="https://travis-ci.org/jpbruyere/vke.net">
</p>
### Presentation
-**vke.net** (_vulkan engine for .net_) a vulkan abstraction layer writen in **c#** composed of high level classes encapsulating [vulkan](https://www.khronos.org/vulkan/) objects and commands with `IDispose` model and **reference counting**. [GLFW](https://www.glfw.org/) handles the windowing system.
+**vke.net** (_vulkan engine for .net_) is a vulkan abstraction layer writen in **c#** composed of high level classes encapsulating [vulkan](https://www.khronos.org/vulkan/) objects and commands with `IDispose` model and **reference counting**. [GLFW](https://www.glfw.org/) handles the default windowing system.
+
+vke aims to provide a simple api for all common vulkan tasks, ideal to quickly prototype vulkan applications, but fits also the needs to build complete application or game.
+
+To see **vke.net** in action check [vkChess.net](https://github.com/jpbruyere/vkChess.net).
Vke use autogenerated [vk.net](https://github.com/jpbruyere/vk.net) library for low level binding to vulkan.
-Use the 'download_datas.sh' script for downloading sample's datas.
+Use the `download_datas.sh` script for downloading sample's datas.
vke is in early development stage.
```xml
<Project Sdk="Microsoft.NET.Sdk">
- <TargetFrameworks>net472</TargetFrameworks>
- <OutputType>Exe</OutputType>
+ <TargetFrameworks>net472</TargetFrameworks>
+ <OutputType>Exe</OutputType>
- <ItemGroup>
- <PackageReference Include="vke" />
- </ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="vke" />
+ </ItemGroup>
</Project>
```
For automatic shader compilation to SpirV, add also the [SpirVTasks](SpirVTasks/README.md) nuget package.
```xml
- <ItemGroup>
- <PackageReference Include="SpirVTasks" />
- <GLSLShader Include="shaders\*.*" />
- </ItemGroup>
+<ItemGroup>
+ <PackageReference Include="SpirVTasks" />
+ <GLSLShader Include="shaders\*.*" />
+</ItemGroup>
```
### Samples
| [Textured](samples/Textured/README.md) |  |
-
### Features
- physicaly based rendering, direct and deferred
<h1 align="center">
SpirVTasks MSBuild add-on
- <br>
+ <br>
<p align="center">
<a href="https://www.nuget.org/packages/SpirVTasks">
<img src="https://buildstats.info/nuget/SpirVTasks">
</a>
<a href="https://www.paypal.me/GrandTetraSoftware">
<img src="https://img.shields.io/badge/Donate-PayPal-green.svg">
- </a>
+ </a>
</p>
</h1>
```xml
<ItemGroup>
- <PackageReference Include="SpirVTasks"/>
+ <PackageReference Include="SpirVTasks"/>
</ItemGroup>
-<ItemGroup>
+<ItemGroup>
<GLSLShader Include="shaders\*.frag;shaders\*.vert;shaders\*.comp;shaders\*.geom" />
-</ItemGroup>
+</ItemGroup>
```
Resulting `.spv` files are automatically embedded with the resource ID: `ProjectName.file.ext.spv`. You can override this default id by adding a custom **LogicalName**.
```xml
<GLSLShader Include="shaders\*.vert">
<LogicalName>shaders.%(Filename)%(Extension).spv</LogicalName>
</GLSLShader>
-</ItemGroup>
+</ItemGroup>
```
`VULKAN_SDK/bin` then `PATH` are searched for the **`glslc`** executable. You can also use the `SpirVglslcPath` property.
layout (location = 0) in vec3 inColor;
layout (location = 0) out vec4 outFragColor;
-void main()
+void main()
{
outFragColor = vec4(inColor, 1.0);
}
```
-Included files are searched from the location of the current parsed file, then in the `SpirVAdditionalIncludeDirectories`directories if present.
+Included files are searched from the location of the current parsed file, then in the `SpirVAdditionalIncludeDirectories` directories if present.
```xml
<PropertyGroup>
<SpirVAdditionalIncludeDirectories>$(MSBuildThisFileDirectory)common;testdir;../anotherdir</SpirVAdditionalIncludeDirectories>
<GLSLShader Include="shaders\*.vert">
<AdditionalIncludeDirectories>../include</AdditionalIncludeDirectories>
</GLSLShader>
-</ItemGroup>
+</ItemGroup>
```
- PERF: spirv will be optimized for performances.
- SIZE: resulting code size will be minimized.
-**DefineConstants** attribute may contains a semicolon separated list of implicit **MACRO** to define for compilation. Note that **project constants** are automatically to the compilation unit.
+**DefineConstants** attribute may contains a semicolon separated list of implicit **MACRO** to define for compilation. Note that **project constants** are automatically added to the compilation unit.
```xml
<GLSLShader Include="shaders\skybox.vert" DefineConstants="DEBUG;SHADOW_FACTOR=0.15"/>
if (path.EndsWith ("ktx", StringComparison.OrdinalIgnoreCase))
return KTX.KTX.Load (staggingQ, cmdPool, path,
VkImageUsageFlags.Sampled, imgProp, genMipMaps, tiling);
- return Image.Load (staggingQ.Dev, staggingQ, cmdPool, path, VkFormat.R8g8b8a8Unorm, imgProp, tiling, genMipMaps);
+ return Image.Load (staggingQ, cmdPool, path, VkFormat.R8g8b8a8Unorm, imgProp, tiling, genMipMaps);
}
}
vkimg = Image.Load (dev, transferQ, cmdPool, glTFLoader.loadDataUri (img));
} else {
Debug.WriteLine ("loading image {0} : {1} : {2}", img.Name, img.MimeType, img.Uri);//load image from file path in uri
- vkimg = Image.Load (dev, transferQ, cmdPool, Path.Combine (baseDirectory, img.Uri));
+ vkimg = Image.Load (transferQ, cmdPool, Path.Combine (baseDirectory, img.Uri));
imgName += ";" + img.Uri;
}
#!/bin/bash
-wget --no-check-certificate "https://onedrive.live.com/download?cid=B3181664476E9B48&resid=B3181664476E9B48%21167&authkey=APMbPmUMFnlrN6s" -O datas.zip
+wget --no-check-certificate "https://onedrive.live.com/download?cid=B3181664476E9B48&resid=B3181664476E9B48%21167&authkey=AIDq3olkU5xnxkQ" -O datas.zip
unzip datas.zip
```xml
<Project Sdk="Microsoft.NET.Sdk">
- <PropertyGroup>
- <TargetFrameworks>net472</TargetFrameworks>
- <OutputType>Exe</OutputType>
- </PropertyGroup>
- <ItemGroup>
- <GLSLShader Include="shaders\*.*" />
- </ItemGroup>
- <ItemGroup>
- <PackageReference Include="SpirVTasks" />
- <PackageReference Include="vke" />
- </ItemGroup>
+ <PropertyGroup>
+ <TargetFrameworks>net472</TargetFrameworks>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+ <ItemGroup>
+ <GLSLShader Include="shaders\*.*" />
+ </ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="SpirVTasks" />
+ <PackageReference Include="vke" />
+ </ItemGroup>
</Project>
-
```
### VkWindow class
renderPass = new RenderPass (dev, swapChain.ColorFormat);
renderPass.ClearValues[0] = new VkClearValue (0.1f, 0.2f, 1);
renderPass.Activate ();
-
+
cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount);
}
```
frameBuffers?.Dispose();
frameBuffers = renderPass.CreateFrameBuffers(swapChain);
-
+
buildCommandBuffers ();
}
```
### The command buffers
-The `VkWindow` class has a default array of command buffers, one for each swap chain image. But it's up to you to allocate and populate them.
+The `VkWindow` class has a default array of command buffers, one for each swap chain image. But it's up to you to allocate and populate them.
Here we simply record a begin/end render pass to clear the screen with the load operation of it.
```csharp
}
//The resize method is called at least once before any rendering, so it's
- //a safe place to initialize output size related vulkan objects like the
+ //a safe place to initialize output size related vulkan objects like the
//frame buffers.
protected override void OnResize () {
base.OnResize ();
buildCommandBuffers ();
}
//clean up
- protected override void Dispose (bool disposing) {
+ protected override void Dispose (bool disposing) {
dev.WaitIdle ();
renderPass.Dispose ();
```csharp
protected override void configureEnabledFeatures (
VkPhysicalDeviceFeatures available_features,
- ref VkPhysicalDeviceFeatures enabled_features) {
-
+ ref VkPhysicalDeviceFeatures enabled_features) {
+
enabled_features.samplerAnisotropy = available_features.samplerAnisotropy;
}
```
protected override void createQueues () {
base.createQueues ();
transferQ = new Queue (dev, VkQueueFlags.Transfer);
-}
\ No newline at end of file
+}
+```
+
+### Loading images
+
+The `vke.Image` classes has facilities to load bitmaps from disk (jpg, gif, ...). KTX images use the `KTX.KTX.Load` static method.
+
+```csharp
+KTX.KTX.Load (presentQueue, cmdPool, path, ...
+Image.Load (dev, presentQueue, cmdPool, path, ...
+```
+
+Once the image is loaded, you may create the associated View and Sampler by calling image instance methods. View and Sampler lifecycle will be bound to the image and disposed when the image is disposed.
+
+The `Descriptor` property of the image will old the created handles.
+
+```csharp
+nextTexture.CreateView ();
+nextTexture.CreateSampler ();
+nextTexture.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+```
\ No newline at end of file
protected override void initVulkan () {
base.initVulkan ();
-
+
cmds = cmdPool.AllocateCommandBuffer(swapChain.ImageCount);
-
+
loadTexture (imgPathes[currentImgIndex]);
vbo = new GPUBuffer<float> (presentQueue, cmdPool, VkBufferUsageFlags.VertexBuffer, vertices);
pipeline.RenderPass.End (cmd);
- cmd.End ();
+ cmd.End ();
}
}
nextTexture = KTX.KTX.Load (presentQueue, cmdPool, path,
VkImageUsageFlags.Sampled, imgProp, genMipMaps, tiling);
else
- nextTexture = Image.Load (dev, presentQueue, cmdPool, path, VkFormat.R8g8b8a8Unorm, imgProp, tiling, genMipMaps);
+ nextTexture = Image.Load (presentQueue, cmdPool, path, VkFormat.R8g8b8a8Unorm, imgProp, tiling, genMipMaps);
updateViewRequested = true;
} catch (Exception ex) {
Console.WriteLine (ex);
}
//in the main vulkan thread
- void updateTextureSet (){
+ void updateTextureSet (){
nextTexture.CreateView ();
nextTexture.CreateSampler ();
nextTexture.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
nextTexture = null;
}
- void updateMatrices () {
+ void updateMatrices () {
matrices.projection = Matrix4x4.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (60f), (float)swapChain.Width / (float)swapChain.Height, 0.1f, 256.0f);
matrices.view = Matrix4x4.CreateTranslation (0, 0, -2.5f * zoom);
matrices.model =
if (nextTexture != null) {
updateTextureSet ();
buildCommandBuffers ();
- }else
+ }else
updateMatrices ();
updateViewRequested = false;
if (GetButton (MouseButton.Left) == InputAction.Press) {
rotY -= rotSpeed * (float)diffX;
rotX += rotSpeed * (float)diffY;
+ updateViewRequested = true;
} else if (GetButton (MouseButton.Right) == InputAction.Press) {
zoom += zoomSpeed * (float)diffY;
+ updateViewRequested = true;
}
-
- updateViewRequested = true;
}
protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
frameBuffers = pipeline.RenderPass.CreateFrameBuffers(swapChain);
buildCommandBuffers ();
- }
+ }
protected override void Dispose (bool disposing) {
dev.WaitIdle ();
-1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 1.0f,-1.0f, 0.0f, 0.0f,
-1.0f,-1.0f,-1.0f, 0.0f, 1.0f,
-
+
-1.0f,-1.0f,-1.0f, 1.0f, 1.0f, // -Z side
1.0f, 1.0f,-1.0f, 0.0f, 0.0f,
1.0f,-1.0f,-1.0f, 0.0f, 1.0f,
-1.0f,-1.0f,-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f, 1.0f, 0.0f,
1.0f, 1.0f,-1.0f, 0.0f, 0.0f,
-
+
-1.0f,-1.0f,-1.0f, 1.0f, 0.0f, // -Y side
1.0f,-1.0f,-1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f,-1.0f,-1.0f, 1.0f, 0.0f,
1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f,-1.0f, 1.0f, 0.0f, 0.0f,
-
+
-1.0f, 1.0f,-1.0f, 1.0f, 0.0f, // +Y side
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, 1.0f,-1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f,-1.0f, 1.0f, 1.0f,
-
+
1.0f, 1.0f,-1.0f, 1.0f, 0.0f, // +X side
1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
1.0f,-1.0f,-1.0f, 1.0f, 1.0f,
1.0f, 1.0f,-1.0f, 1.0f, 0.0f,
-
+
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // +Z side
-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
void buildCommandBuffers () {
cmdPool.Reset();
- for (int i = 0; i < swapChain.ImageCount; ++i) {
+ for (int i = 0; i < swapChain.ImageCount; ++i) {
cmds[i].Start ();
recordDraw (cmds[i], frameBuffers[i]);
- cmds[i].End ();
+ cmds[i].End ();
}
- }
+ }
void recordDraw (PrimaryCommandBuffer cmd, FrameBuffer fb) {
pipeline.RenderPass.Begin (cmd, fb);
}
//in the main vulkan thread
- void updateTextureSet (){
+ void updateTextureSet (){
nextTexture.CreateView (VkImageViewType.Cube,VkImageAspectFlags.Color,6);
nextTexture.CreateSampler ();
nextTexture.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
- DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descriptorSet, dsLayout.Bindings[1]);
+ DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descriptorSet, dsLayout.Bindings[1]);
uboUpdate.Write (dev, nextTexture.Descriptor);
texture?.Dispose ();
texture = nextTexture;
nextTexture = null;
}
- void updateMatrices () {
+ void updateMatrices () {
matrices.projection = Matrix4x4.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (60f), (float)swapChain.Width / (float)swapChain.Height, 0.1f, 5.0f);
matrices.view =
Matrix4x4.CreateFromAxisAngle (Vector3.UnitZ, rotZ) *
dev.WaitIdle ();
updateTextureSet ();
buildCommandBuffers ();
- }else
+ }else
updateMatrices ();
updateViewRequested = false;
buildCommandBuffers();
}
-
+
protected override void Dispose (bool disposing) {
if (disposing) {
if (!isDisposed) {
### Creating buffers
-Vke has two classes to handle buffers. Mappable [`HostBuffer`](../../../../wiki/vke.HostBuffer) and device only [`GPUBuffer`](../../../../wiki/vke.GPUBuffer).
+Vke has two classes to handle buffers. Mappable [`HostBuffer`](../../../../wiki/vke.HostBuffer) and device only [`GPUBuffer`](../../../../wiki/vke.GPUBuffer).
For this first simple example, we will only use host mappable buffers. Those classes can handle a Generic argument of a blittable type to handle arrays. Resources like buffers or images are activated in constructor, and they need to be explicitly disposed on cleanup. Create them in the `initVulkan` override.
```csharp
//the vertex buffer
vbo = new HostBuffer<Vertex> (dev, VkBufferUsageFlags.VertexBuffer, vertices);
//the index buffer
-ibo = new HostBuffer<ushort> (dev, VkBufferUsageFlags.IndexBuffer, indices);
+ibo = new HostBuffer<ushort> (dev, VkBufferUsageFlags.IndexBuffer, indices);
//a permanantly mapped buffer for the mvp matrice
uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, mvp, true);
```
```csharp
descriptorPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer));
```
+### Creating pipelines
+
Graphic pipeline configuration are predefined by the [`GraphicPipelineConfig`](../../../../wiki/vke.GraphicPipelineConfig) class, which ease sharing configs for several pipelines having lots in common. The pipeline layout will be automatically activated on pipeline creation, so that sharing layout among different pipelines will benefit from the reference counting to automatically dispose unused layout on pipeline clean up. It's the same for [`DescriptorSetLayout`](../../wiki/api/DescriptorSetLayout).
```csharp
-GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (
- VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false);
-
-cfg.Layout = new PipelineLayout (dev,
- new DescriptorSetLayout (dev,
- new VkDescriptorSetLayoutBinding (
- 0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer)));
+using (GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (
+ VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false)) {
+
+ cfg.Layout = new PipelineLayout (dev,
+ new DescriptorSetLayout (dev,
+ new VkDescriptorSetLayoutBinding (
+ 0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer)));
```
Next we configure a default [`RenderPass`](../../../../wiki/vke.RenderPass) with just a color attachment for the swap chain image, a default sub-pass is automatically created and the render pass activation will follow the pipeline life cycle and will be automatically disposed when no longer in use.
```csharp
cfg.AddShader (dev, VkShaderStageFlags.Vertex, "#shaders.main.vert.spv");
cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.main.frag.spv");
```
+Because native ShaderModule used during pipeline creation may be disposed once the pipeline is created, The PipelineConfig class implement the
+'IDisposable' interface to release those pointers automaticaly.
+
Once the pipeline configuration is complete, we use it to effectively create and activate a graphic pipeline. Activables used by the pipeline (like the RenderPass, or the PipelineLayout) are referenced in the newly created managed pipeline. So the Configuration object doesn't need cleanup.
```csharp
pipeline = new GraphicPipeline (cfg);
```csharp
descriptorSet = descriptorPool.Allocate (pipeline.Layout.DescriptorSetLayouts[0]);
```
+
+### Descriptor update
+
The descriptor update is a two step operation. First we create a [`DescriptorSetWrites`](../../../../wiki/vke.DescriptorSetWrites) object defining the layout(s), than we write the descriptor(s).
The `Descriptor` property of the mvp HostBuffer will return a default descriptor with no offset of the full size of the buffer.
uboUpdate.Write (dev, uboMats.Descriptor);
```
+
+### Updating the view
+
+Override the `UpdateView` method of the `VkWindow` class to update view related stuff like matrices.
+
+```csharp
+public override void UpdateView () {
+ mvp = Matrix4x4.Create ...
+ uboMats.Update (mvp, (uint)Marshal.SizeOf<Matrix4x4> ());
+ base.UpdateView ();
+}
+```
+This method is called at least once before the rendering loop just after 'OnResize'.
+Then, it is triggered in the render loop each time the `updateViewRequested` field of `VkWindow` is set to 'true',
+don't forget to reset `updateViewRequested` to 'false' or call the `base.UpdateView()` which will reset this boolean.
+
+In a typical application, the mouse movements will set `updateViewRequested` to true.
+```csharp
+protected override void onMouseMove (double xPos, double yPos) {
+ updateViewRequested = true;
+```
//a descriptor pool to allocate the mvp matrice descriptor from.
descriptorPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer));
- //Graphic pipeline configuration are predefined by the GraphicPipelineConfig class, which ease sharing config for several pipelines having lots in common.
+ //Graphic pipeline configuration are predefined by the GraphicPipelineConfig class,
+ //which ease sharing config for several pipelines having lots in common.
+ //Because 'ShaderInfo' instantiate temporary native ShaderModule, the GraphicPipelineConfig
+ //class implement 'IDisposable' interface to dispose those modules once the pipeline(s) is created.
using (GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false)) {
//Create the pipeline layout, it will be automatically activated on pipeline creation, so that sharing layout among different pipelines will benefit
//from the reference counting to automatically dispose unused layout on pipeline clean up. It's the same for DescriptorSetLayout.
protected override void OnResize () {
base.OnResize ();
- UpdateView ();
+
+ updateViewRequested = true;
frameBuffers?.Dispose();
frameBuffers = pipeline.RenderPass.CreateFrameBuffers(swapChain);
/// The activables that trigger activation only on usage does not require an additional dispose at the end.
/// </remarks>
public abstract class Activable : IDisposable {
- //count number of activation, only the first one will create a handle
+ //count number of activation, only the first one will create a handle
[XmlIgnore] protected uint references;
//keep track of the current state of activation.
protected ActivableState state;
VkDebugUtilsObjectNameInfoEXT dmo = DebugUtilsInfo;
dmo.pObjectName = name.Pin();
Utils.CheckResult (vkSetDebugUtilsObjectNameEXT (Dev.VkDev, ref dmo));
- name.Unpin ();
+ name.Unpin ();
}
/// <summary>
/// Activation of the object, the reference count is incremented and if Debug utils is enabled, name is set.
references++;
if (state == ActivableState.Activated)
return;
- if (state == ActivableState.Disposed)
+ if (state == ActivableState.Disposed)
GC.ReRegisterForFinalize (this);
state = ActivableState.Activated;
SetName (name);
/// </summary>
public sealed class DescriptorSetLayout : Activable {
internal VkDescriptorSetLayout handle;
-
+
public VkDescriptorSetLayoutCreateFlags Flags { get; private set; } = 0;
public List<VkDescriptorSetLayoutBinding> Bindings { get; private set; } = new List<VkDescriptorSetLayoutBinding> ();
#region CTORS
DescriptorSetLayout () : base (null) { }
- public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags) : base (device) {
+ public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags) : base (device) {
Flags = flags;
}
public DescriptorSetLayout (Device device, params VkDescriptorSetLayoutBinding[] bindings)
}
public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags, params VkDescriptorSetLayoutBinding[] bindings)
: this (device, flags) {
- foreach (VkDescriptorSetLayoutBinding b in bindings)
- Bindings.Add (b);
+ foreach (VkDescriptorSetLayoutBinding b in bindings)
+ Bindings.Add (b);
}
#endregion
// memory properties.
// You can check http://vulkan.gpuinfo.org/ for details on different memory configurations
internal uint GetMemoryTypeIndex (uint typeBits, VkMemoryPropertyFlags properties) {
- // Iterate over all memory types available for the Device used in this example
- for (uint i = 0; i < phy.memoryProperties.memoryTypeCount; i++) {
- if ((typeBits & 1) == 1) {
- if ((phy.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
- return i;
- }
- }
- typeBits >>= 1;
- }
-
- throw new InvalidOperationException ("Could not find a suitable memory type!");
- }
- public VkFormat GetSuitableDepthFormat () {
- VkFormat[] formats = new VkFormat[] {VkFormat.D32SfloatS8Uint, VkFormat.D32Sfloat, VkFormat.D24UnormS8Uint, VkFormat.D16UnormS8Uint, VkFormat.D16Unorm };
- foreach (VkFormat f in formats) {
+ // Iterate over all memory types available for the Device used in this example
+ for (uint i = 0; i < phy.memoryProperties.memoryTypeCount; i++) {
+ if ((typeBits & 1) == 1) {
+ if ((phy.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
+ return i;
+ }
+ }
+ typeBits >>= 1;
+ }
+
+ throw new InvalidOperationException ("Could not find a suitable memory type!");
+ }
+ public VkFormat GetSuitableDepthFormat () {
+ VkFormat[] formats = new VkFormat[] {VkFormat.D32SfloatS8Uint, VkFormat.D32Sfloat, VkFormat.D24UnormS8Uint, VkFormat.D16UnormS8Uint, VkFormat.D16Unorm };
+ foreach (VkFormat f in formats) {
Console.WriteLine ( (int)phy.GetFormatProperties (f).optimalTilingFeatures);
- if (phy.GetFormatProperties (f).optimalTilingFeatures.HasFlag(VkFormatFeatureFlags.DepthStencilAttachment))
- return f;
- }
- throw new InvalidOperationException ("No suitable depth format found.");
- }
+ if (phy.GetFormatProperties (f).optimalTilingFeatures.HasFlag(VkFormatFeatureFlags.DepthStencilAttachment))
+ return f;
+ }
+ throw new InvalidOperationException ("No suitable depth format found.");
+ }
/// <summary>
/// Load compiled SpirvShader.
/// </summary>
/// <returns>the vulkan shader module.</returns>
/// <param name="filename">path of the spv shader.</param>
- public VkShaderModule CreateShaderModule (string filename) {
+ public VkShaderModule CreateShaderModule (string filename) {
using (Stream stream = Utils.GetStreamFromPath (filename)) {
using (BinaryReader br = new BinaryReader (stream)) {
byte[] shaderCode = br.ReadBytes ((int)stream.Length);
return shaderModule;
}
}
- }/// <summary>
- /// Load spirv code from unmanaged native pointer.
- /// </summary>
- /// <returns>the vulkan shader module.</returns>
- /// <param name="code">unmanaged pointer holding the spirv code. Pointer must stay valid only during
+ }/// <summary>
+ /// Load spirv code from unmanaged native pointer.
+ /// </summary>
+ /// <returns>the vulkan shader module.</returns>
+ /// <param name="code">unmanaged pointer holding the spirv code. Pointer must stay valid only during
/// the call to this method.</param>
- /// <param name="codeSize">spirv code byte size.</param>
+ /// <param name="codeSize">spirv code byte size.</param>
public VkShaderModule CreateShaderModule (IntPtr code, UIntPtr codeSize) {
VkShaderModuleCreateInfo moduleCreateInfo = VkShaderModuleCreateInfo.New ();
moduleCreateInfo.codeSize = codeSize;
#region IDisposable Support
private bool disposedValue = false; // Pour détecter les appels redondants
- protected virtual void Dispose (bool disposing) {
- if (!disposedValue) {
+ protected virtual void Dispose (bool disposing) {
+ if (!disposedValue) {
if (disposing) {
#if MEMORY_POOLS
resourceManager.Dispose ();
} else
System.Diagnostics.Debug.WriteLine ("Device disposed by Finalizer.");
- vkDestroyDevice (dev, IntPtr.Zero);
+ vkDestroyDevice (dev, IntPtr.Zero);
- disposedValue = true;
- }
- }
+ disposedValue = true;
+ }
+ }
- ~Device() {
- Dispose(false);
- }
+ ~Device() {
+ Dispose(false);
+ }
- // Ce code est ajouté pour implémenter correctement le modèle supprimable.
- public void Dispose () {
- Dispose (true);
- GC.SuppressFinalize(this);
- }
+ // Ce code est ajouté pour implémenter correctement le modèle supprimable.
+ public void Dispose () {
+ Dispose (true);
+ GC.SuppressFinalize(this);
+ }
#endregion
- }
+ }
}
/// Load bitmap into Image with stagging and mipmap generation if necessary
/// and usage.
/// </summary>
- public static Image Load (Device dev, Queue staggingQ, CommandPool staggingCmdPool,
+ public static Image Load (Queue staggingQ, CommandPool staggingCmdPool,
string path, VkFormat format = VkFormat.Undefined,
VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.DeviceLocal,
VkImageTiling tiling = VkImageTiling.Optimal, bool generateMipmaps = true,
VkImageType imageType = VkImageType.Image2D,
VkImageUsageFlags usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst) {
+ Device dev = staggingQ.dev;
+
if (format == VkFormat.Undefined)
format = DefaultTextureFormat;
if (tiling == VkImageTiling.Optimal)
namespace vke {
public class RenderPass : Activable {
- internal VkRenderPass handle;
+ internal VkRenderPass handle;
public readonly VkSampleCountFlags Samples;
/// Create renderpass with a single color attachment and a resolve one if needed
/// </summary>
public RenderPass (Device device, VkFormat colorFormat, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1, VkAttachmentLoadOp loadOp = VkAttachmentLoadOp.Clear)
- : this (device) {
+ : this (device) {
Samples = samples;
AddAttachment (colorFormat, (samples == VkSampleCountFlags.SampleCount1) ? VkImageLayout.PresentSrcKHR : VkImageLayout.ColorAttachmentOptimal, samples,
stencilStoreOp = VkAttachmentStoreOp.DontCare,
initialLayout = initialLayout,
finalLayout = finalLayout,
- });
+ });
}
public void AddAttachment (VkFormat format, VkImageLayout finalLayout,
VkAttachmentLoadOp stencilLoadOp,
}
return fbs;
}
-
+
public override string ToString () {
return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString("x")}]");
}
-
+
#region IDisposable Support
protected override void Dispose (bool disposing) {
if (state == ActivableState.Activated) {
UInt32 numberOfFaces = br.ReadUInt32 ();//only for cube map, else 1
UInt32 numberOfMipmapLevels = Math.Max (1, br.ReadUInt32 ());
UInt32 bytesOfKeyValueData = br.ReadUInt32 ();
-
+
VkFormat vkFormat = GLHelper.vkGetFormatFromOpenGLInternalFormat (glInternalFormat);
if (vkFormat == VkFormat.Undefined) {
vkFormat = GLHelper.vkGetFormatFromOpenGLFormat (glFormat, glType);
if (numberOfMipmapLevels == 1)
requestedMipsLevels = (generateMipmaps && phyFormatSupport.HasFlag (VkFormatFeatureFlags.BlitSrc | VkFormatFeatureFlags.BlitDst)) ?
(uint)Math.Floor (Math.Log (Math.Max (pixelWidth, pixelHeight))) + 1 : 1 ;
-
+
if (tiling == VkImageTiling.Optimal)
usage |= VkImageUsageFlags.TransferDst;
if (generateMipmaps)
(pixelWidth == 0) ? throw new KtxException ("pixelWidth must be > 0") :
(pixelHeight == 0) ? imgType = VkImageType.Image1D :
(pixelDepth == 1) ? imgType = VkImageType.Image2D : imgType = VkImageType.Image3D;
-
+
VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;
img = new Image (staggingQ.Dev, vkFormat, usage, memoryProperty, pixelWidth, pixelHeight, imgType, samples,
tiling, requestedMipsLevels, numberOfArrayElements, pixelDepth, createFlags);
-
+
byte[] keyValueDatas = br.ReadBytes ((int)bytesOfKeyValueData);
uint blockW, blockH;
if (memoryProperty.HasFlag (VkMemoryPropertyFlags.DeviceLocal)) {
ulong staggingSize = img.AllocatedDeviceMemorySize;
- Console.WriteLine ($"KtxStream size = {ktxStream.Length}, img Allocation = {img.AllocatedDeviceMemorySize}");
using (HostBuffer stagging = new HostBuffer (staggingQ.Dev, VkBufferUsageFlags.TransferSrc, staggingSize)) {
stagging.Map ();
//TODO:handle compressed formats
for (uint face = 0; face < numberOfFaces; face++) {
Marshal.Copy (br.ReadBytes ((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize);
- uint faceOffset = imgSize + (imgSize % 4);//cube padding
+ uint faceOffset = imgSize + (imgSize % 4);//cube padding
bufferOffset += faceOffset;
}
buffCopies.Add (bufferCopyRegion);
bufferOffset += imgSize;
}
- if (isCompressed && bufferOffset % blockSize > 0)
+ if (isCompressed && bufferOffset % blockSize > 0)
bufferOffset += blockSize - bufferOffset % blockSize;
imgWidth /= 2;
buffCopies.Unpin ();
if (requestedMipsLevels > numberOfMipmapLevels)
- img.BuildMipmaps (cmd);
+ img.BuildMipmaps (cmd);
else
img.SetLayout (cmd, VkImageAspectFlags.Color,
VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal,
cmd.Free ();
}
- } else {
+ } else {
+ throw new NotImplementedException();
}
}
}