diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2019-05-08 01:41:55 +0200 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2019-05-08 01:41:55 +0200 |
| commit | b4fb4b4067534f69c1aa055ad6b4b3a7a488b13d (patch) | |
| tree | 76d9d3198bb26d78b8f6f0c0c97c20c1fbfa8e75 | |
| parent | f89a45f4083ad1b1d7129fde4616ca35e29d3e58 (diff) | |
wip
29 files changed, 1244 insertions, 687 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..610673e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: csharp +dist: xenial + +dotnet: 2.1.502 +mono: latest + +script: + - nuget restore + - msbuild + - dotnet restore + - dotnet build + diff --git a/samples/Triangle/main.cs b/samples/Triangle/main.cs index 55ce742..347f83a 100644 --- a/samples/Triangle/main.cs +++ b/samples/Triangle/main.cs @@ -49,7 +49,7 @@ namespace Triangle { }; ushort[] indices = new ushort[] { 0, 1, 2 }; - Program () : base (true) { + Program () : base (false) { vbo = new HostBuffer<Vertex> (dev, VkBufferUsageFlags.VertexBuffer, vertices); ibo = new HostBuffer<ushort> (dev, VkBufferUsageFlags.IndexBuffer, indices); uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices); @@ -61,10 +61,6 @@ namespace Triangle { GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1); cfg.Layout = new PipelineLayout (dev, dsLayout); - cfg.Layout.AddPushConstants ( - new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()), - new VkPushConstantRange (VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf<PbrModel.PbrMaterial> (), 64) - ); cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), cfg.Samples); cfg.AddVertexBinding<Vertex> (0); cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat); diff --git a/samples/common/CrowWin.cs b/samples/common/CrowWin.cs index 5f59e83..ae3ca71 100644 --- a/samples/common/CrowWin.cs +++ b/samples/common/CrowWin.cs @@ -33,7 +33,7 @@ namespace Crow { crowThread.Start (); while (crow == null) - Thread.Sleep (5); + Thread.Sleep (2); initUISurface (); diff --git a/samples/compute/delaunay.cs b/samples/compute/delaunay.cs index d87c02a..a0af948 100644 --- a/samples/compute/delaunay.cs +++ b/samples/compute/delaunay.cs @@ -49,15 +49,14 @@ namespace delaunay { public Program () : base () { -#if DEBUG - dbgReport = new DebugReport (instance, - VkDebugReportFlagsEXT.ErrorEXT - | VkDebugReportFlagsEXT.DebugEXT - | VkDebugReportFlagsEXT.WarningEXT - | VkDebugReportFlagsEXT.PerformanceWarningEXT - - ); -#endif + if (Instance.DebugUtils) + dbgReport = new DebugReport (instance, + VkDebugReportFlagsEXT.ErrorEXT + | VkDebugReportFlagsEXT.DebugEXT + | VkDebugReportFlagsEXT.WarningEXT + | VkDebugReportFlagsEXT.PerformanceWarningEXT + + ); imgResult = new Image (dev, VkFormat.R32g32b32a32Sfloat, VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, imgDim, imgDim); imgResult.CreateView (); @@ -313,9 +312,7 @@ namespace delaunay { imgResult.Dispose (); -#if DEBUG - dbgReport.Dispose (); -#endif + dbgReport?.Dispose (); } } diff --git a/samples/deferred/deferred.csproj b/samples/deferred/deferred.csproj index 4d0a27c..a670d9f 100644 --- a/samples/deferred/deferred.csproj +++ b/samples/deferred/deferred.csproj @@ -31,8 +31,7 @@ <Compile Include="EnvironmentPipeline.cs;deferredPbrRenderer.cs;shadowMapRenderer.cs" /> </ItemGroup> - <ItemGroup Condition="$(Configuration) == 'DebugCrow' "> - <PackageReference Include="Crow.VK" Version="0.9.0-beta" /> + <ItemGroup Condition="'$(Configuration)' == 'DebugCrow' "> <Compile Include="../common/CrowWin.cs" /> <Compile Include="main-crow.cs" /> <EmbeddedResource Include="ui\**\*.*"> @@ -51,6 +50,7 @@ <ItemGroup> <PackageReference Include="Vulkan" Version="0.1.2.8-beta" /> <ProjectReference Include="..\..\vke\CVKL.csproj" /> + <PackageReference Include="Crow.VK" Version="0.9.0-beta" /> </ItemGroup> <Import Project="$(SolutionDir)spirv.targets" /> diff --git a/samples/deferred/deferredPbrRenderer.cs b/samples/deferred/deferredPbrRenderer.cs index 74dc4ca..971eb64 100644 --- a/samples/deferred/deferredPbrRenderer.cs +++ b/samples/deferred/deferredPbrRenderer.cs @@ -10,7 +10,8 @@ namespace deferred { SwapChain swapChain; public PresentQueue presentQueue; - public static VkSampleCountFlags NUM_SAMPLES = VkSampleCountFlags.SampleCount4; + public static int MAX_MATERIAL_COUNT = 8; + public static VkSampleCountFlags NUM_SAMPLES = VkSampleCountFlags.SampleCount1; public static VkFormat HDR_FORMAT = VkFormat.R32g32b32a32Sfloat; public static VkFormat MRT_FORMAT = VkFormat.R32g32b32a32Sfloat; @@ -29,6 +30,8 @@ namespace deferred { shadowMap } + public static bool EnableTextureArray = false; + public DebugView currentDebugView = DebugView.none; public int lightNumDebug = 0; public int debugMip = 0; @@ -57,11 +60,11 @@ namespace deferred { }; public Light[] lights = { new Light { - position = new Vector4(2.5f,3.5f,2,0f), + position = new Vector4(2.5f,5.5f,2,0f), color = new Vector4(1,0.8f,0.8f,1) }, new Light { - position = new Vector4(-2.5f,2.5f,2,0f), + position = new Vector4(-2.5f,5.5f,2,0f), color = new Vector4(0.8f,0.8f,1,1) } }; @@ -106,8 +109,8 @@ namespace deferred { descriptorPool = new DescriptorPool (dev, 3, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 3), new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 5), - new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 6) - ); + new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 5) + ); uboMatrices = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices, true); uboLights = new HostBuffer<Light> (dev, VkBufferUsageFlags.UniformBuffer, lights, true); @@ -119,12 +122,11 @@ namespace deferred { init (nearPlane, farPlane); } - void init (float nearPlane, float farPlane) { - + void init_renderpass () { renderPass = new RenderPass (dev, NUM_SAMPLES); renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.PresentSrcKHR, VkSampleCountFlags.SampleCount1);//swapchain image - renderPass.AddAttachment (dev.GetSuitableDepthFormat(), VkImageLayout.DepthStencilAttachmentOptimal, NUM_SAMPLES); + renderPass.AddAttachment (dev.GetSuitableDepthFormat (), VkImageLayout.DepthStencilAttachmentOptimal, NUM_SAMPLES); renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff0 (color + roughness) and final color before resolve renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff1 (emit + metal) renderPass.AddAttachment (MRT_FORMAT, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff2 (normals + AO) @@ -139,7 +141,7 @@ namespace deferred { renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); - SubPass[] subpass = { new SubPass (), new SubPass (), new SubPass(), new SubPass() }; + SubPass[] subpass = { new SubPass (), new SubPass (), new SubPass (), new SubPass () }; //skybox subpass[SP_SKYBOX].AddColorReference (6, VkImageLayout.ColorAttachmentOptimal); //models @@ -156,17 +158,17 @@ namespace deferred { new VkAttachmentReference (3, VkImageLayout.ShaderReadOnlyOptimal), new VkAttachmentReference (4, VkImageLayout.ShaderReadOnlyOptimal), new VkAttachmentReference (5, VkImageLayout.ShaderReadOnlyOptimal)); - //tone mapping + //tone mapping subpass[SP_TONE_MAPPING].AddColorReference ((NUM_SAMPLES == VkSampleCountFlags.SampleCount1) ? 0u : 2u, VkImageLayout.ColorAttachmentOptimal); subpass[SP_TONE_MAPPING].AddInputReference (new VkAttachmentReference (6, VkImageLayout.ShaderReadOnlyOptimal)); - if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1) + if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1) subpass[SP_TONE_MAPPING].AddResolveReference (0, VkImageLayout.ColorAttachmentOptimal); - + renderPass.AddSubpass (subpass); renderPass.AddDependency (Vk.SubpassExternal, SP_SKYBOX, - VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, - VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); + VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, + VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); renderPass.AddDependency (SP_SKYBOX, SP_MODELS, VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader, VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead); @@ -177,9 +179,12 @@ namespace deferred { VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader, VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead); renderPass.AddDependency (SP_TONE_MAPPING, Vk.SubpassExternal, - VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, - VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, + VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + } + void init (float nearPlane, float farPlane) { + init_renderpass (); descLayoutMain = new DescriptorSetLayout (dev, new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer),//matrices and params @@ -192,13 +197,17 @@ namespace deferred { descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (6, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)); #endif - descLayoutTextures = new DescriptorSetLayout (dev, - new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), - new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), - new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), - new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), - new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler) - ); + if (EnableTextureArray) { + descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (7, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));//texture array + } else { + descLayoutTextures = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler) + ); + } descLayoutGBuff = new DescriptorSetLayout (dev, new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),//color + roughness @@ -215,7 +224,11 @@ namespace deferred { cfg.multisampleState.minSampleShading = 0.5f; } cfg.Cache = pipelineCache; - cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutTextures, descLayoutGBuff); + if (EnableTextureArray) + cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutGBuff); + else + cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutGBuff, descLayoutTextures); + cfg.Layout.AddPushConstants ( new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()), new VkPushConstantRange (VkShaderStageFlags.Fragment, sizeof (int), 64) @@ -232,10 +245,14 @@ namespace deferred { using (SpecializationInfo constants = new SpecializationInfo ( new SpecializationConstant<float> (0, nearPlane), - new SpecializationConstant<float> (1, farPlane))) { + new SpecializationConstant<float> (1, farPlane), + new SpecializationConstant<float> (2, MAX_MATERIAL_COUNT))) { cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/GBuffPbr.vert.spv"); - cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/GBuffPbr.frag.spv", constants); + if (EnableTextureArray) + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/GBuffPbrTexArray.frag.spv", constants); + else + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/GBuffPbr.frag.spv", constants); gBuffPipeline = new GraphicPipeline (cfg); } @@ -291,16 +308,26 @@ namespace deferred { public void LoadModel (Queue transferQ, string path) { dev.WaitIdle (); model?.Dispose (); - model = new PbrModel (transferQ, path, - descLayoutTextures, - AttachmentType.Color, - AttachmentType.PhysicalProps, - AttachmentType.Normal, - AttachmentType.AmbientOcclusion, - AttachmentType.Emissive); - DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5]); - uboUpdate.Write (dev, model.materialUBO.Descriptor); + if (EnableTextureArray) { + model = new PbrModelTexArray (transferQ, path); + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5], descLayoutMain.Bindings[7]); + uboUpdate.Write (dev, model.materialUBO.Descriptor, (model as PbrModelTexArray).texArray.Descriptor); + + } else { + model = new PbrModelSeparatedTextures (transferQ, path, + descLayoutTextures, + AttachmentType.Color, + AttachmentType.PhysicalProps, + AttachmentType.Normal, + AttachmentType.AmbientOcclusion, + AttachmentType.Emissive); + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5]); + uboUpdate.Write (dev, model.materialUBO.Descriptor); + } + modelAABB = model.DefaultScene.AABB; } @@ -327,7 +354,7 @@ namespace deferred { } renderPass.BeginSubPass (cmd); - cmd.BindDescriptorSet (composePipeline.Layout, dsGBuff, 2); + cmd.BindDescriptorSet (composePipeline.Layout, dsGBuff, 1); if (currentDebugView == DebugView.none) composePipeline.Bind (cmd); @@ -451,7 +478,7 @@ namespace deferred { debugPipeline.Dispose (); descLayoutMain.Dispose (); - descLayoutTextures.Dispose (); + descLayoutTextures?.Dispose (); descLayoutGBuff.Dispose (); uboMatrices.Dispose (); diff --git a/samples/deferred/main-crow.cs b/samples/deferred/main-crow.cs index 2a64e32..f3c06b4 100644 --- a/samples/deferred/main-crow.cs +++ b/samples/deferred/main-crow.cs @@ -1,21 +1,26 @@ using System; using System.Numerics; -using System.Runtime.InteropServices; using Glfw; using VK; using CVKL; -using System.Threading; using System.Collections.Generic; using System.Linq; namespace deferred { class Program : Crow.CrowWin { static void Main (string[] args) { + Instance.DebugUtils = true; + Instance.Validation = true; + //Instance.RenderDocCapture = true; + DeferredPbrRenderer.EnableTextureArray = true; + PbrModelTexArray.TEXTURE_DIM = 512; + using (Program vke = new Program ()) { vke.Run (); } } + #region crow ui public Crow.Command CMDViewScenes, CMDViewEditor, CMDViewDebug, CMDViewMaterials; void init_crow_commands () { CMDViewScenes = new Crow.Command (new Action (() => loadWindow ("#deferred.main.crow", this))) { Caption = "Lighting", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true }; @@ -24,11 +29,6 @@ namespace deferred { CMDViewMaterials = new Crow.Command (new Action (() => loadWindow ("#deferred.materials.crow", this))) { Caption = "Materials", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true }; } - void onApplyMaterialChanges (object sender, Crow.MouseButtonEventArgs e) { - Crow.ListBox lb = ((sender as Crow.Widget).Parent as Crow.Group).Children[0] as Crow.ListBox; - renderer.model.materialUBO.Update (renderer.model.materials); - } - public DeferredPbrRenderer.DebugView CurrentDebugView { get { return renderer.currentDebugView; } set { @@ -73,8 +73,7 @@ namespace deferred { } public List<DeferredPbrRenderer.Light> Lights => renderer.lights.ToList (); public List<Model.Scene> Scenes => renderer.model.Scenes; - public PbrModel.PbrMaterial[] Materials => renderer.model.materials; - + #endregion protected override void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures features) { base.configureEnabledFeatures (available_features, ref features); @@ -82,9 +81,17 @@ namespace deferred { features.samplerAnisotropy = available_features.samplerAnisotropy; features.sampleRateShading = available_features.sampleRateShading; features.geometryShader = available_features.geometryShader; + features.pipelineStatisticsQuery = true; - if (available_features.textureCompressionBC) { + if (available_features.textureCompressionETC2) { + features.textureCompressionETC2 = true; + Image.DefaultTextureFormat = VkFormat.Etc2R8g8b8a8UnormBlock; + }else if (available_features.textureCompressionBC) { + //features.textureCompressionBC = true; + //Image.DefaultTextureFormat = VkFormat.Bc3UnormBlock; } + + } protected override void createQueues () { @@ -100,6 +107,7 @@ namespace deferred { "../../../samples/data/textures/uffizi_cube.ktx", }; string[] modelPathes = { + "/mnt/devel/gts/vkChess.net/data/models/chess.glb", "../../../samples/data/models/DamagedHelmet/glTF/DamagedHelmet.gltf", "../../../samples/data/models/shadow.glb", "../../../samples/data/models/Hubble.glb", @@ -112,8 +120,22 @@ namespace deferred { Queue transferQ; DeferredPbrRenderer renderer; + PipelineStatisticsQueryPool statPool; + TimestampQueryPool timestampQPool; + ulong[] results; + + DebugReport dbgRepport; Program () : base(true) { + + if (Instance.DebugUtils) + dbgRepport = new DebugReport (instance, + VkDebugReportFlagsEXT.ErrorEXT + | VkDebugReportFlagsEXT.DebugEXT + | VkDebugReportFlagsEXT.WarningEXT + | VkDebugReportFlagsEXT.PerformanceWarningEXT + ); + camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f); camera.SetPosition (0, 0, 2); @@ -121,16 +143,24 @@ namespace deferred { renderer.LoadModel (transferQ, modelPathes[curModelIndex]); camera.Model = Matrix4x4.CreateScale (1f / Math.Max (Math.Max (renderer.modelAABB.Width, renderer.modelAABB.Height), renderer.modelAABB.Depth)); + statPool = new PipelineStatisticsQueryPool (dev, + VkQueryPipelineStatisticFlags.InputAssemblyVertices | + VkQueryPipelineStatisticFlags.InputAssemblyPrimitives | + VkQueryPipelineStatisticFlags.ClippingInvocations | + VkQueryPipelineStatisticFlags.ClippingPrimitives | + VkQueryPipelineStatisticFlags.FragmentShaderInvocations); + + timestampQPool = new TimestampQueryPool (dev); + init_crow_commands (); crow.Load ("#deferred.menu.crow").DataSource = this; - //crow.Load ("#deferred.testImage.crow").DataSource = this; - - //crow.LoadIMLFragment (@"<Image Width='32' Height='32' Margin='2' HorizontalAlignment='Left' VerticalAlignment='Top' Path='/mnt/devel/gts/vkvg/build/data/tiger.svg' Background='Grey' MouseEnter='{Background=Blue}' MouseLeave='{Background=White}'/>"); } protected override void recordDraw (CommandBuffer cmd, int imageIndex) { + statPool.Begin (cmd); renderer.buildCommandBuffers (cmd, imageIndex); + statPool.End (cmd); } public override void UpdateView () { @@ -161,6 +191,8 @@ namespace deferred { NotifyValueChanged ("fps", fps); frameCount = 0; } + + results = statPool.GetResults (); } protected override void OnResize () { renderer.Resize (); @@ -168,7 +200,6 @@ namespace deferred { } #region Mouse and keyboard - protected override void onMouseMove (double xPos, double yPos) { if (crow.ProcessMouseMove ((int)xPos, (int)yPos)) return; @@ -345,8 +376,12 @@ namespace deferred { protected override void Dispose (bool disposing) { if (disposing) { - if (!isDisposed) + if (!isDisposed) { renderer.Dispose (); + statPool.Dispose (); + timestampQPool.Dispose (); + dbgRepport?.Dispose (); + } } base.Dispose (disposing); diff --git a/samples/deferred/main.cs b/samples/deferred/main.cs index 975f5d0..40f96cb 100644 --- a/samples/deferred/main.cs +++ b/samples/deferred/main.cs @@ -5,9 +5,16 @@ using Glfw; using VK; namespace deferred { - class Program : VkWindow { + class Deferred : VkWindow { static void Main (string[] args) { - using (Program vke = new Program ()) { + + Instance.Validation = true; + //Instance.DebugUtils = true; + //Instance.RenderDocCapture = true; + DeferredPbrRenderer.EnableTextureArray = true; + PbrModelTexArray.TEXTURE_DIM = 512; + + using (Deferred vke = new Deferred ()) { vke.Run (); } } @@ -34,6 +41,7 @@ namespace deferred { "../../../samples/data/textures/uffizi_cube.ktx", }; string[] modelPathes = { + "/mnt/devel/gts/vkChess.net/data/models/chess.glb", "../../../samples/data/models/DamagedHelmet/glTF/DamagedHelmet.gltf", "../../../samples/data/models/shadow.glb", "../../../samples/data/models/Hubble.glb", @@ -47,11 +55,22 @@ namespace deferred { Queue transferQ; DeferredPbrRenderer renderer; - Program () : base(true) { + DebugReport dbgRepport; + + Deferred () : base(true) { + + if (Instance.DebugUtils) + dbgRepport = new DebugReport (instance, + VkDebugReportFlagsEXT.ErrorEXT + | VkDebugReportFlagsEXT.DebugEXT + | VkDebugReportFlagsEXT.WarningEXT + | VkDebugReportFlagsEXT.PerformanceWarningEXT + ); + camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f); camera.SetPosition (0, 0, 2); - renderer = new DeferredPbrRenderer (dev, swapChain, presentQueue, cubemapPathes[0], camera.NearPlane, camera.FarPlane); + renderer = new DeferredPbrRenderer (dev, swapChain, presentQueue, cubemapPathes[2], camera.NearPlane, camera.FarPlane); renderer.LoadModel (transferQ, modelPathes[curModelIndex]); camera.Model = Matrix4x4.CreateScale (1f / Math.Max (Math.Max (renderer.modelAABB.Width, renderer.modelAABB.Height), renderer.modelAABB.Depth)); @@ -255,8 +274,10 @@ namespace deferred { protected override void Dispose (bool disposing) { if (disposing) { - if (!isDisposed) + if (!isDisposed) { renderer.Dispose (); + dbgRepport?.Dispose (); + } } base.Dispose (disposing); } diff --git a/samples/deferred/shaders/GBuffPbr.frag b/samples/deferred/shaders/GBuffPbr.frag index 20dcf13..ca398e6 100644 --- a/samples/deferred/shaders/GBuffPbr.frag +++ b/samples/deferred/shaders/GBuffPbr.frag @@ -7,6 +7,7 @@ layout (constant_id = 0) const float NEAR_PLANE = 0.1f; layout (constant_id = 1) const float FAR_PLANE = 256.0f; +layout (constant_id = 2) const int MAT_COUNT = 1; struct Material { vec4 baseColorFactor; @@ -41,28 +42,17 @@ layout (location = 1) in vec3 inNormal; layout (location = 2) in vec2 inUV0; layout (location = 3) in vec2 inUV1; -layout (set = 0, binding = 0) uniform UBO { - mat4 projection; - mat4 model; - mat4 view; - vec4 camPos; -} ubo; layout (set = 0, binding = 5) uniform UBOMaterials { - Material materials[16]; + Material materials[MAT_COUNT]; }; -layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance; -layout (set = 0, binding = 2) uniform samplerCube prefilteredMap; -layout (set = 0, binding = 3) uniform sampler2D samplerBRDFLUT; - // Material bindings - -layout (set = 1, binding = 0) uniform sampler2D colorMap; -layout (set = 1, binding = 1) uniform sampler2D physicalDescriptorMap; -layout (set = 1, binding = 2) uniform sampler2D normalMap; -layout (set = 1, binding = 3) uniform sampler2D aoMap; -layout (set = 1, binding = 4) uniform sampler2D emissiveMap; +layout (set = 2, binding = 0) uniform sampler2D colorMap; +layout (set = 2, binding = 1) uniform sampler2D physicalDescriptorMap; +layout (set = 2, binding = 2) uniform sampler2D normalMap; +layout (set = 2, binding = 3) uniform sampler2D aoMap; +layout (set = 2, binding = 4) uniform sampler2D emissiveMap; layout (push_constant) uniform PushCsts { diff --git a/samples/deferred/shaders/GBuffPbrTexArray.frag b/samples/deferred/shaders/GBuffPbrTexArray.frag new file mode 100644 index 0000000..dee3471 --- /dev/null +++ b/samples/deferred/shaders/GBuffPbrTexArray.frag @@ -0,0 +1,211 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +#define MANUAL_SRGB 0 +#define DEBUG 0 + +layout (constant_id = 0) const float NEAR_PLANE = 0.1f; +layout (constant_id = 1) const float FAR_PLANE = 256.0f; +layout (constant_id = 2) const int MAT_COUNT = 1; + +struct Material { + vec4 baseColorFactor; + vec4 emissiveFactor; + vec4 diffuseFactor; + vec4 specularFactor; + + float workflow; + uint tex0; + uint tex1; + int baseColorTex; + + int physicalDescTex; + int normalTex; + int occlusionTex; + int emissiveTex; + + float metallicFactor; + float roughnessFactor; + float alphaMask; + float alphaMaskCutoff; +}; +const float M_PI = 3.141592653589793; +const float c_MinRoughness = 0.04; + +const float PBR_WORKFLOW_METALLIC_ROUGHNESS = 1.0; +const float PBR_WORKFLOW_SPECULAR_GLOSINESS = 2.0f; + +const uint MAP_COLOR = 0x1; +const uint MAP_NORMAL = 0x2; +const uint MAP_AO = 0x4; +const uint MAP_METAL = 0x8; +const uint MAP_ROUGHNESS = 0x10; +const uint MAP_METALROUGHNESS = 0x20; +const uint MAP_EMISSIVE = 0x40; + +layout (location = 0) in vec3 inWorldPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inUV0; +layout (location = 3) in vec2 inUV1; + +layout (set = 0, binding = 5) uniform UBOMaterials { + Material materials[MAT_COUNT]; +}; +layout (set = 0, binding = 7) uniform sampler2DArray texArray; + +layout (push_constant) uniform PushCsts { + layout(offset = 64) + int materialIdx; +}; + + +layout (location = 0) out vec4 outColorRough; +layout (location = 1) out vec4 outEmitMetal; +layout (location = 2) out vec4 outN_AO; +layout (location = 3) out vec4 outPos; + +vec4 SRGBtoLINEAR(vec4 srgbIn) +{ + #ifdef MANUAL_SRGB + #ifdef SRGB_FAST_APPROXIMATION + vec3 linOut = pow(srgbIn.xyz,vec3(2.2)); + #else //SRGB_FAST_APPROXIMATION + vec3 bLess = step(vec3(0.04045),srgbIn.xyz); + vec3 linOut = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess ); + #endif //SRGB_FAST_APPROXIMATION + return vec4(linOut,srgbIn.w);; + #else //MANUAL_SRGB + return srgbIn; + #endif //MANUAL_SRGB +} + +// Find the normal for this fragment, pulling either from a predefined normal map +// or from the interpolated mesh normal and tangent attributes. +vec3 getNormal() +{ + vec3 tangentNormal; + // Perturb normal, see http://www.thetenthplanet.de/archives/1180 + if ((materials[materialIdx].tex0 & MAP_NORMAL) == MAP_NORMAL) + tangentNormal = texture(texArray, vec3(inUV0, materials[materialIdx].normalTex)).xyz * 2.0 - 1.0; + else if ((materials[materialIdx].tex1 & MAP_NORMAL) == MAP_NORMAL) + tangentNormal = texture(texArray, vec3(inUV1, materials[materialIdx].normalTex)).xyz * 2.0 - 1.0; + else + return normalize(inNormal); + + vec3 q1 = dFdx(inWorldPos); + vec3 q2 = dFdy(inWorldPos); + vec2 st1 = dFdx(inUV0); + vec2 st2 = dFdy(inUV0); + + vec3 N = normalize(inNormal); + vec3 T = normalize(q1 * st2.t - q2 * st1.t); + vec3 B = -normalize(cross(N, T)); + mat3 TBN = mat3(T, B, N); + + return normalize(TBN * tangentNormal); +} + +// Gets metallic factor from specular glossiness workflow inputs +float convertMetallic(vec3 diffuse, vec3 specular, float maxSpecular) { + float perceivedDiffuse = sqrt(0.299 * diffuse.r * diffuse.r + 0.587 * diffuse.g * diffuse.g + 0.114 * diffuse.b * diffuse.b); + float perceivedSpecular = sqrt(0.299 * specular.r * specular.r + 0.587 * specular.g * specular.g + 0.114 * specular.b * specular.b); + if (perceivedSpecular < c_MinRoughness) { + return 0.0; + } + float a = c_MinRoughness; + float b = perceivedDiffuse * (1.0 - maxSpecular) / (1.0 - c_MinRoughness) + perceivedSpecular - 2.0 * c_MinRoughness; + float c = c_MinRoughness - perceivedSpecular; + float D = max(b * b - 4.0 * a * c, 0.0); + return clamp((-b + sqrt(D)) / (2.0 * a), 0.0, 1.0); +} + +float linearDepth(float depth) +{ + float z = depth * 2.0f - 1.0f; + return (2.0f * NEAR_PLANE * FAR_PLANE) / (FAR_PLANE + NEAR_PLANE - z * (FAR_PLANE - NEAR_PLANE)); +} + +void main() +{ + float perceptualRoughness; + float metallic; + vec4 baseColor; + vec3 emissive = vec3(0); + + baseColor = materials[materialIdx].baseColorFactor; + + if (materials[materialIdx].workflow == PBR_WORKFLOW_METALLIC_ROUGHNESS) { + perceptualRoughness = materials[materialIdx].roughnessFactor; + metallic = materials[materialIdx].metallicFactor; + // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. + // This layout intentionally reserves the 'r' channel for (optional) occlusion map data + if ((materials[materialIdx].tex0 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS){ + perceptualRoughness *= texture(texArray, vec3(inUV0, materials[materialIdx].physicalDescTex)).g; + metallic *= texture(texArray, vec3(inUV0, materials[materialIdx].physicalDescTex)).b; + }else if ((materials[materialIdx].tex1 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS){ + perceptualRoughness *= texture(texArray, vec3(inUV1, materials[materialIdx].physicalDescTex)).g; + metallic *= texture(texArray, vec3(inUV1, materials[materialIdx].physicalDescTex)).b; + } + perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); + metallic = clamp(metallic, 0.0, 1.0); + + // The albedo may be defined from a base texture or a flat color + if ((materials[materialIdx].tex0 & MAP_COLOR) == MAP_COLOR) + baseColor *= SRGBtoLINEAR(texture(texArray, vec3(inUV0, materials[materialIdx].baseColorTex))); + else if ((materials[materialIdx].tex1 & MAP_COLOR) == MAP_COLOR) + baseColor *= SRGBtoLINEAR(texture(texArray, vec3(inUV1, materials[materialIdx].baseColorTex))); + } + + if (materials[materialIdx].alphaMask == 1.0f) { + if (baseColor.a < materials[materialIdx].alphaMaskCutoff) + discard; + } + + if (materials[materialIdx].workflow == PBR_WORKFLOW_SPECULAR_GLOSINESS) { + // Values from specular glossiness workflow are converted to metallic roughness + if ((materials[materialIdx].tex0 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS) + perceptualRoughness = 1.0 - texture(texArray, vec3(inUV0, materials[materialIdx].physicalDescTex)).a; + else if ((materials[materialIdx].tex1 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS) + perceptualRoughness = 1.0 - texture(texArray, vec3(inUV1, materials[materialIdx].physicalDescTex)).a; + else + perceptualRoughness = 0.0; + + const float epsilon = 1e-6; + + vec4 diffuse = SRGBtoLINEAR(texture(texArray, vec3(inUV0, materials[materialIdx].baseColorTex))); + vec3 specular = SRGBtoLINEAR(texture(texArray, vec3(inUV0, materials[materialIdx].physicalDescTex))).rgb; + + float maxSpecular = max(max(specular.r, specular.g), specular.b); + + // Convert metallic value from specular glossiness inputs + metallic = convertMetallic(diffuse.rgb, specular, maxSpecular); + + vec3 baseColorDiffusePart = diffuse.rgb * ((1.0 - maxSpecular) / (1 - c_MinRoughness) / max(1 - metallic, epsilon)) * materials[materialIdx].diffuseFactor.rgb; + vec3 baseColorSpecularPart = specular - (vec3(c_MinRoughness) * (1 - metallic) * (1 / max(metallic, epsilon))) * materials[materialIdx].specularFactor.rgb; + baseColor = vec4(mix(baseColorDiffusePart, baseColorSpecularPart, metallic * metallic), diffuse.a); + + } + + const float u_OcclusionStrength = 1.0f; + const float u_EmissiveFactor = 1.0f; + float ao = 1.0f; + + if ((materials[materialIdx].tex0 & MAP_EMISSIVE) == MAP_EMISSIVE) + emissive = SRGBtoLINEAR(texture(texArray, vec3(inUV0, materials[materialIdx].emissiveTex))).rgb * u_EmissiveFactor; + else if ((materials[materialIdx].tex1 & MAP_EMISSIVE) == MAP_EMISSIVE) + emissive = SRGBtoLINEAR(texture(texArray, vec3(inUV1, materials[materialIdx].emissiveTex))).rgb * u_EmissiveFactor; + + if ((materials[materialIdx].tex0 & MAP_AO) == MAP_AO) + ao = texture(texArray, vec3(inUV0, materials[materialIdx].occlusionTex)).r; + else if ((materials[materialIdx].tex1 & MAP_AO) == MAP_AO) + ao = texture(texArray, vec3(inUV1, materials[materialIdx].occlusionTex)).r; + + vec3 n = getNormal(); + vec3 p = inWorldPos; + + outColorRough = vec4 (baseColor.rgb, perceptualRoughness); + outEmitMetal = vec4 (emissive, metallic); + outN_AO = vec4 (n, ao); + outPos = vec4 (p, linearDepth(gl_FragCoord.z)); +}
\ No newline at end of file diff --git a/samples/deferred/shaders/compose.frag b/samples/deferred/shaders/compose.frag index 4b5c205..81312bd 100644 --- a/samples/deferred/shaders/compose.frag +++ b/samples/deferred/shaders/compose.frag @@ -28,10 +28,10 @@ layout (set = 0, binding = 4) uniform UBOLights { const float M_PI = 3.141592653589793; const float c_MinRoughness = 0.04; -layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInputMS samplerColorRough; -layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInputMS samplerEmitMetal; -layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInputMS samplerN_AO; -layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInputMS samplerPos; +layout (input_attachment_index = 0, set = 1, binding = 0) uniform subpassInputMS samplerColorRough; +layout (input_attachment_index = 1, set = 1, binding = 1) uniform subpassInputMS samplerEmitMetal; +layout (input_attachment_index = 2, set = 1, binding = 2) uniform subpassInputMS samplerN_AO; +layout (input_attachment_index = 3, set = 1, binding = 3) uniform subpassInputMS samplerPos; layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance; layout (set = 0, binding = 2) uniform samplerCube prefilteredMap; diff --git a/samples/deferred/shaders/compose_with_shadows.frag b/samples/deferred/shaders/compose_with_shadows.frag index e65aaaf..d8ad270 100644 --- a/samples/deferred/shaders/compose_with_shadows.frag +++ b/samples/deferred/shaders/compose_with_shadows.frag @@ -27,12 +27,12 @@ layout (set = 0, binding = 4) uniform UBOLights { const float M_PI = 3.141592653589793; const float c_MinRoughness = 0.04; -#define SHADOW_FACTOR 0.55 +#define SHADOW_FACTOR 0.15 -layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInputMS samplerColorRough; -layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInputMS samplerEmitMetal; -layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInputMS samplerN_AO; -layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInputMS samplerPos; +layout (input_attachment_index = 0, set = 1, binding = 0) uniform subpassInputMS samplerColorRough; +layout (input_attachment_index = 1, set = 1, binding = 1) uniform subpassInputMS samplerEmitMetal; +layout (input_attachment_index = 2, set = 1, binding = 2) uniform subpassInputMS samplerN_AO; +layout (input_attachment_index = 3, set = 1, binding = 3) uniform subpassInputMS samplerPos; layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance; layout (set = 0, binding = 2) uniform samplerCube prefilteredMap; diff --git a/samples/deferred/shaders/show_gbuff.frag b/samples/deferred/shaders/show_gbuff.frag index a494688..7859e36 100644 --- a/samples/deferred/shaders/show_gbuff.frag +++ b/samples/deferred/shaders/show_gbuff.frag @@ -2,15 +2,15 @@ #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInputMS samplerColorRough; -layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInputMS samplerEmitMetal; -layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInputMS samplerN_AO; -layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInputMS samplerPos; +layout (input_attachment_index = 0, set = 1, binding = 0) uniform subpassInputMS samplerColorRough; +layout (input_attachment_index = 1, set = 1, binding = 1) uniform subpassInputMS samplerEmitMetal; +layout (input_attachment_index = 2, set = 1, binding = 2) uniform subpassInputMS samplerN_AO; +layout (input_attachment_index = 3, set = 1, binding = 3) uniform subpassInputMS samplerPos; layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance; layout (set = 0, binding = 2) uniform samplerCube prefilteredMap; layout (set = 0, binding = 3) uniform sampler2D samplerBRDFLUT; -layout (set = 0, binding = 7) uniform sampler2DArray samplerShadowMap; +layout (set = 0, binding = 6) uniform sampler2DArray samplerShadowMap; layout (push_constant) uniform PushCsts { layout(offset = 64) diff --git a/samples/deferred/shaders/tone_mapping.frag b/samples/deferred/shaders/tone_mapping.frag index 9c4dd43..187d672 100644 --- a/samples/deferred/shaders/tone_mapping.frag +++ b/samples/deferred/shaders/tone_mapping.frag @@ -11,7 +11,7 @@ layout (set = 0, binding = 0) uniform UBO { float gamma; } ubo; -layout (input_attachment_index = 0, set = 2, binding = 4) uniform subpassInputMS samplerHDR; +layout (input_attachment_index = 0, set = 1, binding = 4) uniform subpassInputMS samplerHDR; layout (location = 0) in vec2 inUV; layout (location = 0) out vec4 outColor; diff --git a/samples/deferred/shadowMapRenderer.cs b/samples/deferred/shadowMapRenderer.cs index e34b60f..2f5a24e 100644 --- a/samples/deferred/shadowMapRenderer.cs +++ b/samples/deferred/shadowMapRenderer.cs @@ -147,7 +147,6 @@ namespace deferred { public void Dispose () { shadowPipeline?.Dispose (); fbShadowMap?.Dispose (); - shadowPass?.Dispose (); shadowMap?.Dispose (); descriptorPool?.Dispose (); } diff --git a/samples/pbrSashaWillem/SachaWillemPbr.csproj b/samples/pbrSashaWillem/SachaWillemPbr.csproj index 9deadf5..1e1cb59 100644 --- a/samples/pbrSashaWillem/SachaWillemPbr.csproj +++ b/samples/pbrSashaWillem/SachaWillemPbr.csproj @@ -24,6 +24,7 @@ <ItemGroup> <PackageReference Include="Vulkan" Version="0.1.2.8-beta" /> + <PackageReference Include="vkvg.net" Version="0.2.2-beta" /> </ItemGroup> <ItemGroup> @@ -38,13 +38,13 @@ Global {96A2E0B8-91AE-4EB9-A435-185D01E24067}.Release|Any CPU.Build.0 = Release|Any CPU {96A2E0B8-91AE-4EB9-A435-185D01E24067}.temp|Any CPU.ActiveCfg = Debug|Any CPU {96A2E0B8-91AE-4EB9-A435-185D01E24067}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {96A2E0B8-91AE-4EB9-A435-185D01E24067}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU + {96A2E0B8-91AE-4EB9-A435-185D01E24067}.Debug|Any CPU.Build.0 = Debug|Any CPU {96A2A7896-91AE-4EB9-A435-185D01E24067}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {96A2A7896-91AE-4EB9-A435-185D01E24067}.Release|Any CPU.ActiveCfg = Release|Any CPU {96A2A7896-91AE-4EB9-A435-185D01E24067}.Release|Any CPU.Build.0 = Release|Any CPU {96A2A7896-91AE-4EB9-A435-185D01E24067}.temp|Any CPU.ActiveCfg = Debug|Any CPU {96A2A7896-91AE-4EB9-A435-185D01E24067}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {96A2A7896-91AE-4EB9-A435-185D01E24067}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU + {96A2A7896-91AE-4EB9-A435-185D01E24067}.Debug|Any CPU.Build.0 = Debug|Any CPU {87AC7BE1-143E-4FF4-91F8-981B1CAAF1DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {87AC7BE1-143E-4FF4-91F8-981B1CAAF1DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {87AC7BE1-143E-4FF4-91F8-981B1CAAF1DD}.Release|Any CPU.Build.0 = Release|Any CPU @@ -52,7 +52,6 @@ Global {87AC7BE1-143E-4FF4-91F8-981B1CAAF1DD}.temp|Any CPU.ActiveCfg = Debug|Any CPU {87AC7BE1-143E-4FF4-91F8-981B1CAAF1DD}.temp|Any CPU.Build.0 = Debug|Any CPU {87AC7BE1-143E-4FF4-91F8-981B1CAAF1DD}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {87AC7BE1-143E-4FF4-91F8-981B1CAAF1DD}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU {F41EA96F-A9F7-4E85-B2EE-5757C5FAD00D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F41EA96F-A9F7-4E85-B2EE-5757C5FAD00D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F41EA96F-A9F7-4E85-B2EE-5757C5FAD00D}.Release|Any CPU.Build.0 = Release|Any CPU @@ -60,26 +59,23 @@ Global {F41EA96F-A9F7-4E85-B2EE-5757C5FAD00D}.temp|Any CPU.ActiveCfg = Debug|Any CPU {F41EA96F-A9F7-4E85-B2EE-5757C5FAD00D}.temp|Any CPU.Build.0 = Debug|Any CPU {F41EA96F-A9F7-4E85-B2EE-5757C5FAD00D}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {F41EA96F-A9F7-4E85-B2EE-5757C5FAD00D}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU {1F18E74F-BCC9-481C-8FDF-89D81CBB30BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1F18E74F-BCC9-481C-8FDF-89D81CBB30BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {1F18E74F-BCC9-481C-8FDF-89D81CBB30BE}.Release|Any CPU.Build.0 = Release|Any CPU {1F18E74F-BCC9-481C-8FDF-89D81CBB30BE}.temp|Any CPU.ActiveCfg = Debug|Any CPU {1F18E74F-BCC9-481C-8FDF-89D81CBB30BE}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {1F18E74F-BCC9-481C-8FDF-89D81CBB30BE}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU + {1F18E74F-BCC9-481C-8FDF-89D81CBB30BE}.Debug|Any CPU.Build.0 = Debug|Any CPU {1F05E74F-AEE8-481C-8FDF-456654CC30BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1F05E74F-AEE8-481C-8FDF-456654CC30BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {1F05E74F-AEE8-481C-8FDF-456654CC30BE}.Release|Any CPU.Build.0 = Release|Any CPU {1F05E74F-AEE8-481C-8FDF-456654CC30BE}.temp|Any CPU.ActiveCfg = Debug|Any CPU {1F05E74F-AEE8-481C-8FDF-456654CC30BE}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {1F05E74F-AEE8-481C-8FDF-456654CC30BE}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU {1603D809-D9C4-4EE5-B921-B053CE22E068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1603D809-D9C4-4EE5-B921-B053CE22E068}.Debug|Any CPU.Build.0 = Debug|Any CPU {1603D809-D9C4-4EE5-B921-B053CE22E068}.Release|Any CPU.ActiveCfg = Release|Any CPU {1603D809-D9C4-4EE5-B921-B053CE22E068}.Release|Any CPU.Build.0 = Release|Any CPU {1603D809-D9C4-4EE5-B921-B053CE22E068}.temp|Any CPU.ActiveCfg = Debug|Any CPU {1603D809-D9C4-4EE5-B921-B053CE22E068}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {1603D809-D9C4-4EE5-B921-B053CE22E068}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU {9E12DFE6-7DC7-4BF2-8077-42DDC69FD0A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9E12DFE6-7DC7-4BF2-8077-42DDC69FD0A1}.Debug|Any CPU.Build.0 = Debug|Any CPU {9E12DFE6-7DC7-4BF2-8077-42DDC69FD0A1}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -92,7 +88,7 @@ Global {001F5D64-871B-47A4-A823-78C7CE3785AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {001F5D64-871B-47A4-A823-78C7CE3785AA}.temp|Any CPU.ActiveCfg = Debug|Any CPU {001F5D64-871B-47A4-A823-78C7CE3785AA}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {001F5D64-871B-47A4-A823-78C7CE3785AA}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU + {001F5D64-871B-47A4-A823-78C7CE3785AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {BFF1BEEC-2E93-4963-AD3C-2A8C9BA05C36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BFF1BEEC-2E93-4963-AD3C-2A8C9BA05C36}.Debug|Any CPU.Build.0 = Debug|Any CPU {BFF1BEEC-2E93-4963-AD3C-2A8C9BA05C36}.temp|Any CPU.ActiveCfg = Debug|Any CPU @@ -101,7 +97,7 @@ Global {05515E15-D3C3-4A8C-A940-9467D9D77823}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {05515E15-D3C3-4A8C-A940-9467D9D77823}.temp|Any CPU.ActiveCfg = Debug|Any CPU {05515E15-D3C3-4A8C-A940-9467D9D77823}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU - {05515E15-D3C3-4A8C-A940-9467D9D77823}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU + {05515E15-D3C3-4A8C-A940-9467D9D77823}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {96A2E0B8-91AE-4EB9-A435-185D01E24067} = {A2A2849A-0032-4AA8-BC0E-82C69D7DE354} diff --git a/vke/CVKL.csproj b/vke/CVKL.csproj index af5170d..02be0d8 100644 --- a/vke/CVKL.csproj +++ b/vke/CVKL.csproj @@ -4,7 +4,7 @@ <TargetFrameworks>net471;netstandard2.0</TargetFrameworks> <Copyright></Copyright> - <AssemblyVersion>0.1.3.1</AssemblyVersion> + <AssemblyVersion>0.1.3.2</AssemblyVersion> <Description>C# vulkan library with IDispose model and references counting</Description> <Company></Company> <Product>CVKL</Product> diff --git a/vke/src/Image.cs b/vke/src/Image.cs index 96015cb..9b0e5e6 100644 --- a/vke/src/Image.cs +++ b/vke/src/Image.cs @@ -36,6 +36,8 @@ namespace CVKL { /// such imported image will not be disposed with the sampler and the view. /// </summary> public class Image : Resource { + public static VkFormat DefaultTextureFormat = VkFormat.R8g8b8a8Unorm; + internal VkImage handle; VkImageCreateInfo info = VkImageCreateInfo.New(); @@ -102,16 +104,21 @@ namespace CVKL { } #endregion + public static uint ComputeMipLevels(uint size) => (uint)Math.Floor (Math.Log (size)) + 1; + #region bitmap loading /// <summary> /// Load image from data pointed by IntPtr pointer containing full image file (jpg, png,...) /// </summary> public static Image Load (Device dev, Queue staggingQ, CommandPool staggingCmdPool, - IntPtr bitmap, ulong bitmapByteCount, VkFormat format = VkFormat.R8g8b8a8Unorm, + IntPtr bitmap, ulong bitmapByteCount, 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) { + VkImageUsageFlags usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst) { + + if (format == VkFormat.Undefined) + format = DefaultTextureFormat; int width, height, channels; IntPtr imgPtr = Stb.Load (bitmap, (int)bitmapByteCount, out width, out height, out channels, 4); @@ -135,44 +142,10 @@ namespace CVKL { return img; } /// <summary> - /// Load image from data pointed by IntPtr pointer containing full image file (jpg, png,...) - /// </summary> - public static Image Load (Device dev, - IntPtr bitmap, ulong bitmapByteCount, VkImageUsageFlags usage = VkImageUsageFlags.TransferSrc, - VkFormat format = VkFormat.R8g8b8a8Unorm, - VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, - VkImageTiling tiling = VkImageTiling.Linear, bool generateMipmaps = false, - VkImageType imageType = VkImageType.Image2D) { - - int width, height, channels; - IntPtr imgPtr = Stb.Load (bitmap, (int)bitmapByteCount, out width, out height, out channels, 4); - - if (imgPtr == IntPtr.Zero) - throw new Exception ($"STBI image loading error."); - - uint mipLevels = generateMipmaps ? (uint)Math.Floor (Math.Log (Math.Max (width, height))) + 1 : 1; - - if (generateMipmaps) - usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst); - - long size = width * height * 4; - Image img = new Image (dev, format, usage, memoryProps, (uint)width, (uint)height, imageType, VkSampleCountFlags.SampleCount1, tiling, mipLevels); - - img.Map (); - unsafe { - System.Buffer.MemoryCopy (imgPtr.ToPointer (), img.MappedData.ToPointer (), size, size); - } - img.Unmap (); - - Stb.FreeImage (imgPtr); - - return img; - } - /// <summary> /// Load image from byte array containing full image file (jpg, png,...) /// </summary> public static Image Load (Device dev, Queue staggingQ, CommandPool staggingCmdPool, - byte[] bitmap, VkFormat format = VkFormat.R8g8b8a8Unorm, + byte[] bitmap, VkFormat format = VkFormat.Undefined, VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.DeviceLocal, VkImageTiling tiling = VkImageTiling.Optimal, bool generateMipmaps = true, VkImageType imageType = VkImageType.Image2D, @@ -181,75 +154,23 @@ namespace CVKL { Image img = Load (dev, staggingQ, staggingCmdPool, bitmap.Pin (), (ulong)bitmap.Length, format, memoryProps, tiling, generateMipmaps, imageType, usage); bitmap.Unpin (); - - //int width, height, channels; - //IntPtr imgPtr = Stb.Load (, bitmap.Length, out width, out height, out channels, 4); - - //if (imgPtr == IntPtr.Zero) - // throw new Exception ($"STBI image loading error."); - - //uint mipLevels = generateMipmaps ? (uint)Math.Floor (Math.Log (Math.Max (width, height))) + 1 : 1; - - //if (tiling == VkImageTiling.Optimal) - // usage |= VkImageUsageFlags.TransferDst; - //if (generateMipmaps) - // usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst); - - //Image img = new Image (dev, format, usage, memoryProps, (uint)width, (uint)height, imageType, VkSampleCountFlags.SampleCount1, tiling, mipLevels); - - //img.load (staggingQ, staggingCmdPool, imgPtr, generateMipmaps); - - //Stb.FreeImage (imgPtr); - return img; } /// <summary> - /// load bitmap from pointer - /// </summary> - void load (Queue staggingQ, CommandPool staggingCmdPool, IntPtr bitmap, bool generateMipmaps = true) - { - long size = info.extent.width * info.extent.height * 4 * info.extent.depth; - - if (MemoryFlags.HasFlag (VkMemoryPropertyFlags.HostVisible)) { - Map (); - unsafe { - System.Buffer.MemoryCopy (bitmap.ToPointer (), MappedData.ToPointer (), size, size); - } - Unmap (); - - if (generateMipmaps) - BuildMipmaps (staggingQ, staggingCmdPool); - } else { - using (HostBuffer stagging = new HostBuffer (Dev, VkBufferUsageFlags.TransferSrc, (UInt64)size, bitmap)) { - - CommandBuffer cmd = staggingCmdPool.AllocateCommandBuffer (); - - cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit); - - stagging.CopyTo (cmd, this); - if (generateMipmaps) - BuildMipmaps (cmd); - - cmd.End (); - staggingQ.Submit (cmd); - staggingQ.WaitIdle (); - cmd.Free (); - } - } - } - - /// <summary> /// Load bitmap into Image with stagging and mipmap generation if necessary /// and usage. /// </summary> public static Image Load (Device dev, Queue staggingQ, CommandPool staggingCmdPool, - string path, VkFormat format = VkFormat.R8g8b8a8Unorm, + 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) { + if (format == VkFormat.Undefined) + format = DefaultTextureFormat; + int width, height, channels; IntPtr imgPtr = Stb.Load (path, out width, out height, out channels, 4); if (imgPtr == IntPtr.Zero) @@ -272,15 +193,18 @@ namespace CVKL { } /// <summary> - /// create host visible linear image without command + /// create host visible linear image without command from path /// </summary> public static Image Load (Device dev, - string path, VkFormat format = VkFormat.R8g8b8a8Unorm, bool reserveSpaceForMipmaps = true, + string path, VkFormat format = VkFormat.Undefined, bool reserveSpaceForMipmaps = true, VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, VkImageTiling tiling = VkImageTiling.Linear, VkImageType imageType = VkImageType.Image2D, VkImageUsageFlags usage = VkImageUsageFlags.Sampled) { + if (format == VkFormat.Undefined) + format = DefaultTextureFormat; + int width, height, channels; IntPtr imgPtr = Stb.Load (path, out width, out height, out channels, 4); if (imgPtr == IntPtr.Zero) @@ -301,9 +225,96 @@ namespace CVKL { return img; } -#endregion + /// <summary> + /// create host visible linear image without command from byte array + /// </summary> + public static Image Load (Device dev, + byte[] bitmap, VkImageUsageFlags usage = VkImageUsageFlags.TransferSrc, + VkFormat format = VkFormat.Undefined, + VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, + VkImageTiling tiling = VkImageTiling.Linear, bool generateMipmaps = false, + VkImageType imageType = VkImageType.Image2D) { + + Image img = Load (dev, bitmap.Pin (), (ulong)bitmap.Length, usage, format, memoryProps, tiling, generateMipmaps, + imageType); + bitmap.Unpin (); + return img; + } + /// <summary> + /// create host visible linear image without command from data pointed by IntPtr pointer containing full image file (jpg, png,...) + /// </summary> + public static Image Load (Device dev, + IntPtr bitmap, ulong bitmapByteCount, VkImageUsageFlags usage = VkImageUsageFlags.TransferSrc, + VkFormat format = VkFormat.Undefined, + VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, + VkImageTiling tiling = VkImageTiling.Linear, bool generateMipmaps = false, + VkImageType imageType = VkImageType.Image2D) { + + if (format == VkFormat.Undefined) + format = DefaultTextureFormat; + + int width, height, channels; + IntPtr imgPtr = Stb.Load (bitmap, (int)bitmapByteCount, out width, out height, out channels, 4); + + if (imgPtr == IntPtr.Zero) + throw new Exception ($"STBI image loading error."); + + uint mipLevels = generateMipmaps ? (uint)Math.Floor (Math.Log (Math.Max (width, height))) + 1 : 1; + + if (generateMipmaps) + usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst); + + long size = width * height * 4; + Image img = new Image (dev, format, usage, memoryProps, (uint)width, (uint)height, imageType, VkSampleCountFlags.SampleCount1, tiling, mipLevels); + + img.Map (); + unsafe { + System.Buffer.MemoryCopy (imgPtr.ToPointer (), img.MappedData.ToPointer (), size, size); + } + img.Unmap (); + + Stb.FreeImage (imgPtr); + + return img; + } + + /// <summary> + /// load bitmap from pointer + /// </summary> + void load (Queue staggingQ, CommandPool staggingCmdPool, IntPtr bitmap, bool generateMipmaps = true) { + long size = info.extent.width * info.extent.height * 4 * info.extent.depth; + + if (MemoryFlags.HasFlag (VkMemoryPropertyFlags.HostVisible)) { + Map (); + unsafe { + System.Buffer.MemoryCopy (bitmap.ToPointer (), MappedData.ToPointer (), size, size); + } + Unmap (); + + if (generateMipmaps) + BuildMipmaps (staggingQ, staggingCmdPool); + } else { + using (HostBuffer stagging = new HostBuffer (Dev, VkBufferUsageFlags.TransferSrc, (UInt64)size, bitmap)) { + + CommandBuffer cmd = staggingCmdPool.AllocateCommandBuffer (); + + cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit); + + stagging.CopyTo (cmd, this); + if (generateMipmaps) + BuildMipmaps (cmd); + + cmd.End (); + staggingQ.Submit (cmd); + staggingQ.WaitIdle (); + cmd.Free (); + } + } + } + + #endregion - internal override void updateMemoryRequirements () { + internal override void updateMemoryRequirements () { vkGetImageMemoryRequirements (Dev.VkDev, handle, out memReqs); } internal override void bindMemory () { diff --git a/vke/src/Instance.cs b/vke/src/Instance.cs index 589b88b..423d3c0 100644 --- a/vke/src/Instance.cs +++ b/vke/src/Instance.cs @@ -31,6 +31,10 @@ using static VK.Vk; namespace CVKL { public class Instance : IDisposable { + public static bool Validation; + public static bool DebugUtils; + public static bool RenderDocCapture; + VkInstance inst; static class Strings { @@ -80,15 +84,16 @@ namespace CVKL { throw new PlatformNotSupportedException (); } -#if DEBUG - instanceExtensions.Add (Strings.VK_EXT_DEBUG_REPORT_EXTENSION_NAME); - instanceExtensions.Add (Strings.VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - enabledLayerNames.Add (Strings.LayerMonitor); - enabledLayerNames.Add (Strings.LayerValidation); -#if RENDERDOC - enabledLayerNames.Add (Strings.RenderdocCaptureLayerName); -#endif -#endif + if (Validation) + enabledLayerNames.Add (Strings.LayerValidation); + if (RenderDocCapture) + enabledLayerNames.Add (Strings.RenderdocCaptureLayerName); + + if (DebugUtils) { + instanceExtensions.Add (Strings.VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + instanceExtensions.Add (Strings.VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + } + VkApplicationInfo appInfo = new VkApplicationInfo () { sType = VkStructureType.ApplicationInfo, apiVersion = new Vulkan.Version (1, 0, 0), diff --git a/vke/src/MarshaledObject.cs b/vke/src/MarshaledObject.cs new file mode 100644 index 0000000..6d3beb7 --- /dev/null +++ b/vke/src/MarshaledObject.cs @@ -0,0 +1,64 @@ +// +// MarshaledObject.cs +// +// Author: +// Jean-Philippe Bruyère <jp_bruyere@hotmail.com> +// +// Copyright (c) 2019 jp +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Runtime.InteropServices; + +namespace CVKL { + public class MarshaledObject<T> : IDisposable where T : struct { + + GCHandle handle; + + public IntPtr Pointer { + get { + if (!handle.IsAllocated) + throw new InvalidOperationException ("Unalocated MarshaledObject"); + return handle.AddrOfPinnedObject (); + } + } + + public MarshaledObject (T mobj) { + handle = GCHandle.Alloc (mobj, GCHandleType.Pinned); + } + + void freeHandle () { + if (!disposed) + handle.Free (); + } + + #region IDisposable Support + private bool disposed; + + ~MarshaledObject() { + freeHandle (); + } + + public void Dispose () { + freeHandle (); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/vke/src/Model.cs b/vke/src/Model.cs index ed440a9..cc3a3dc 100644 --- a/vke/src/Model.cs +++ b/vke/src/Model.cs @@ -24,20 +24,13 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; -using System.Diagnostics; +using System.Collections.Generic; using System.Numerics; -using System.Runtime.InteropServices; -using glTFLoader; -using GL = glTFLoader.Schema; - using VK; -using System.Collections.Generic; -using System.IO; namespace CVKL { - using static VK.Utils; public struct BoundingBox { public Vector3 min; public Vector3 max; @@ -141,18 +134,34 @@ namespace CVKL { public class Scene { public string Name; public Node Root; - public List<Node> GetNodes () => Root.Children; + public List<Node> GetNodes () => Root?.Children; + public Node FindNode(string name) => Root == null ? null : Root.FindNode (name); - public BoundingBox AABB => Root.GetAABB (Matrix4x4.Identity); + public BoundingBox AABB => Root.GetAABB (Matrix4x4.Identity); } public class Node { + public string Name; public Node Parent; public List<Node> Children; public Matrix4x4 localMatrix; public Mesh Mesh; - public Matrix4x4 Matrix { + public Node FindNode(string name) + { + if (Name == name) + return this; + if (Children == null) + return null; + foreach (Node child in Children) { + Node n = child.FindNode(name); + if (n != null) + return n; + } + return null; + } + + public Matrix4x4 Matrix { get { return Parent == null ? localMatrix : Parent.Matrix * localMatrix; } } @@ -180,8 +189,17 @@ namespace CVKL { public List<Mesh> Meshes; public List<Scene> Scenes; + public Node FindNode(string name) { + foreach (Scene scene in Scenes) + { + Node n = scene.FindNode(name); + if (n != null) + return n; + } + return null; + } - public Dimensions dimensions = new Dimensions (new Vector3 (float.MaxValue), new Vector3 (float.MinValue)); + public Dimensions dimensions = new Dimensions (new Vector3 (float.MaxValue), new Vector3 (float.MinValue)); //public struct MaterialStruct { // public UInt32 baseColorTexture; // public UInt32 metallicRoughnessTexture; @@ -198,11 +216,11 @@ namespace CVKL { public enum Workflow { PhysicalyBaseRendering = 1, SpecularGlossinnes }; public string Name; public Workflow workflow; - public UInt32 baseColorTexture; - public UInt32 metallicRoughnessTexture; - public UInt32 normalTexture; - public UInt32 occlusionTexture; - public UInt32 emissiveTexture; + public Int32 baseColorTexture; + public Int32 metallicRoughnessTexture; + public Int32 normalTexture; + public Int32 occlusionTexture; + public Int32 emissiveTexture; public Vector4 baseColorFactor; public Vector4 emissiveFactor; @@ -224,15 +242,16 @@ namespace CVKL { //} //extension; - public Material (UInt32 _baseColorTexture = 0, UInt32 _metallicRoughnessTexture = 0, - UInt32 _normalTexture = 0, UInt32 _occlusionTexture = 0) + public Material (Int32 _baseColorTexture = -1, Int32 _metallicRoughnessTexture = -1, + Int32 _normalTexture = -1, Int32 _occlusionTexture = -1) { workflow = Workflow.PhysicalyBaseRendering; baseColorTexture = _baseColorTexture; metallicRoughnessTexture = _metallicRoughnessTexture; normalTexture = _normalTexture; occlusionTexture = _occlusionTexture; - emissiveTexture = 0; + emissiveTexture = -1; + alphaMode = AlphaMode.Opaque; alphaCutoff = 1f; metallicFactor = 1f; diff --git a/vke/src/PbrModel.cs b/vke/src/PbrModel.cs index bcd5c9c..761001a 100644 --- a/vke/src/PbrModel.cs +++ b/vke/src/PbrModel.cs @@ -34,9 +34,8 @@ using System.Collections.Generic; namespace CVKL { using static VK.Utils; - //TODO:stride in buffer views? - public class PbrModel : Model { + public abstract class PbrModel : Model { public struct Vertex { [VertexAttribute (VertexAttributeType.Position, VkFormat.R32g32b32Sfloat)] public Vector3 pos; @@ -50,33 +49,11 @@ namespace CVKL { return pos.ToString () + ";" + normal.ToString () + ";" + uv0.ToString () + ";" + uv1.ToString (); } }; - /// <summary> - /// Pbr data structure suitable for push constant or ubo, containing - /// availablility of attached textures and the coef of pbr inputs - /// </summary> - public struct PbrMaterial { - public Vector4 baseColorFactor; - public Vector4 emissiveFactor; - public Vector4 diffuseFactor; - public Vector4 specularFactor; - public float workflow; - public AttachmentType TexCoord0; - public AttachmentType TexCoord1; - public float metallicFactor; - public float roughnessFactor; - public float alphaMask; - public float alphaMaskCutoff; - int pad0;//see std420 - } - - Image[] textures; - public PbrMaterial[] materials; - DescriptorSet[] descriptorSets; - DescriptorPool descriptorPool; + protected DescriptorPool descriptorPool; public GPUBuffer vbo; public GPUBuffer ibo; - public HostBuffer<PbrMaterial> materialUBO; + public HostBuffer materialUBO; public PbrModel (Queue transferQ, string path) { dev = transferQ.Dev; @@ -101,148 +78,34 @@ namespace CVKL { } } } - public PbrModel (Queue transferQ, string path, DescriptorSetLayout layout, params AttachmentType[] attachments) { - dev = transferQ.Dev; - using (CommandPool cmdPool = new CommandPool (dev, transferQ.index)) { - using (glTFLoader ctx = new glTFLoader (path, transferQ, cmdPool)) { - ulong vertexCount, indexCount; - - ctx.GetVertexCount (out vertexCount, out indexCount, out IndexBufferType); - ulong vertSize = vertexCount * (ulong)Marshal.SizeOf<Vertex> (); - ulong idxSize = indexCount * (IndexBufferType == VkIndexType.Uint16 ? 2ul : 4ul); - ulong size = vertSize + idxSize; - - vbo = new GPUBuffer (dev, VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, vertSize); - ibo = new GPUBuffer (dev, VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, idxSize); - - vbo.SetName ("vbo gltf"); - ibo.SetName ("ibo gltf"); - - Meshes = new List<Mesh> (ctx.LoadMeshes<Vertex> (IndexBufferType, vbo, 0, ibo, 0)); - textures = ctx.LoadImages (); - - loadMaterials (ctx, layout, attachments); - - materialUBO = new HostBuffer<PbrMaterial> (dev, VkBufferUsageFlags.UniformBuffer, materials); - - Scenes = new List<Scene> (ctx.LoadScenes (out defaultSceneIndex)); - } - } - } - - void loadMaterials (glTFLoader ctx, DescriptorSetLayout layout, params AttachmentType[] attachments) { - Model.Material[] mats = ctx.LoadMaterial (); - materials = new PbrMaterial[mats.Length]; - descriptorSets = new DescriptorSet[mats.Length]; - - if (attachments.Length == 0) - throw new InvalidOperationException ("At least one attachment is required for Model.WriteMaterialDescriptor"); - - descriptorPool = new DescriptorPool (dev, (uint)materials.Length, - new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, (uint)(attachments.Length * materials.Length)) - ); - descriptorPool.SetName ("descPool gltfTextures"); - - for (int i = 0; i < mats.Length; i++) { - materials[i] = new PbrMaterial { - workflow = (float)mats[i].workflow, - baseColorFactor = mats[i].baseColorFactor, - emissiveFactor = mats[i].emissiveFactor, - metallicFactor = mats[i].metallicFactor, - roughnessFactor = mats[i].roughnessFactor, - TexCoord0 = mats[i].availableAttachments, - TexCoord1 = mats[i].availableAttachments1, - alphaMask = 0f, - alphaMaskCutoff = 0.0f, - diffuseFactor = new Vector4 (0), - specularFactor = new Vector4 (0) - }; - - //materials[i].metallicFactor = 0.1f; - //materials[i].roughnessFactor = 0.9f; - descriptorSets[i] = descriptorPool.Allocate (layout); - descriptorSets[i].Handle.SetDebugMarkerName (dev, "descSet " + mats[i].Name); - - VkDescriptorSetLayoutBinding dslb = - new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler); - - using (DescriptorSetWrites2 uboUpdate = new DescriptorSetWrites2 (dev)) { - for (uint a = 0; a < attachments.Length; a++) { - dslb.binding = a; - switch (attachments[a]) { - case AttachmentType.None: - break; - case AttachmentType.Color: - if (mats[i].availableAttachments.HasFlag (AttachmentType.Color)) - uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].baseColorTexture].Descriptor); - break; - case AttachmentType.Normal: - if (mats[i].availableAttachments.HasFlag (AttachmentType.Normal)) - uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].normalTexture].Descriptor); - break; - case AttachmentType.AmbientOcclusion: - if (mats[i].availableAttachments.HasFlag (AttachmentType.AmbientOcclusion)) - uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].occlusionTexture].Descriptor); - break; - case AttachmentType.PhysicalProps: - if (mats[i].availableAttachments.HasFlag (AttachmentType.PhysicalProps)) - uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].metallicRoughnessTexture].Descriptor); - break; - case AttachmentType.Metal: - break; - case AttachmentType.Roughness: - break; - case AttachmentType.Emissive: - if (mats[i].availableAttachments.HasFlag (AttachmentType.Emissive)) - uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].emissiveTexture].Descriptor); - break; - } - } - uboUpdate.Update (); - } - } - } + protected PbrModel() { } /// <summary> bind vertex and index buffers </summary> - public void Bind (CommandBuffer cmd) { + public virtual void Bind (CommandBuffer cmd) { cmd.BindVertexBuffer (vbo); cmd.BindIndexBuffer (ibo, IndexBufferType); } //TODO:destset for binding must be variable //TODO: ADD REFAULT MAT IF NO MAT DEFINED - public void RenderNode (CommandBuffer cmd, PipelineLayout pipelineLayout, Node node, Matrix4x4 currentTransform, bool shadowPass = false) { - Matrix4x4 localMat = node.localMatrix * currentTransform; - VkShaderStageFlags matStage = shadowPass ? VkShaderStageFlags.Geometry : VkShaderStageFlags.Vertex; - cmd.PushConstant (pipelineLayout, matStage, localMat); - - if (node.Mesh != null) { - foreach (Primitive p in node.Mesh.Primitives) { - if (!shadowPass) { - cmd.PushConstant (pipelineLayout, VkShaderStageFlags.Fragment, (int)p.material, (uint)Marshal.SizeOf<Matrix4x4> ()); - if (descriptorSets[p.material] != null) - cmd.BindDescriptorSet (pipelineLayout, descriptorSets[p.material], 1); - } - cmd.DrawIndexed (p.indexCount, 1, p.indexBase, p.vertexBase, 0); - } - } - if (node.Children == null) - return; - foreach (Node child in node.Children) - RenderNode (cmd, pipelineLayout, child, localMat, shadowPass); - } + public abstract void RenderNode (CommandBuffer cmd, PipelineLayout pipelineLayout, Node node, Matrix4x4 currentTransform, bool shadowPass = false); public void DrawAll (CommandBuffer cmd, PipelineLayout pipelineLayout, bool shadowPass = false) { foreach (Scene sc in Scenes) { - foreach (Node node in sc.Root.Children) { - RenderNode (cmd, pipelineLayout, node, sc.Root.localMatrix, shadowPass); - } + foreach (Node node in sc.Root.Children) + RenderNode (cmd, pipelineLayout, node, sc.Root.localMatrix, shadowPass); } } + public void Draw(CommandBuffer cmd, PipelineLayout pipelineLayout, Scene scene, bool shadowPass = false) + { + if (scene.Root == null) + return; + RenderNode(cmd, pipelineLayout, scene.Root, Matrix4x4.Identity, shadowPass); + } #region IDisposable Support - private bool isDisposed = false; // Pour détecter les appels redondants + protected bool isDisposed; protected virtual void Dispose (bool disposing) { if (!isDisposed) { @@ -251,9 +114,6 @@ namespace CVKL { vbo?.Dispose (); materialUBO?.Dispose (); descriptorPool?.Dispose (); - foreach (Image txt in textures) { - txt.Dispose (); - } } else Debug.WriteLine ("model was not disposed"); isDisposed = true; diff --git a/vke/src/PbrModelSeparateTextures.cs b/vke/src/PbrModelSeparateTextures.cs new file mode 100644 index 0000000..387f20a --- /dev/null +++ b/vke/src/PbrModelSeparateTextures.cs @@ -0,0 +1,198 @@ +// +// PbrModel.cs +// +// Author: +// Jean-Philippe Bruyère <jp_bruyere@hotmail.com> +// +// Copyright (c) 2019 jp +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.InteropServices; + +using VK; +using System.Collections.Generic; + +namespace CVKL { + using static VK.Utils; + + /// <summary> + /// Indexed pbr model whith one descriptorSet per material with separate textures attachments + /// </summary> + public class PbrModelSeparatedTextures : PbrModel { + /// <summary> + /// Pbr data structure suitable for push constant or ubo, containing + /// availablility of attached textures and the coef of pbr inputs + /// </summary> + public struct Material { + public Vector4 baseColorFactor; + public Vector4 emissiveFactor; + public Vector4 diffuseFactor; + public Vector4 specularFactor; + public float workflow; + public AttachmentType TexCoord0; + public AttachmentType TexCoord1; + public float metallicFactor; + public float roughnessFactor; + public float alphaMask; + public float alphaMaskCutoff; + int pad0;//see std420 + } + + Image[] textures; + public Material[] materials; + DescriptorSet[] descriptorSets; + + + public PbrModelSeparatedTextures (Queue transferQ, string path, DescriptorSetLayout layout, params AttachmentType[] attachments) { + dev = transferQ.Dev; + using (CommandPool cmdPool = new CommandPool (dev, transferQ.index)) { + using (glTFLoader ctx = new glTFLoader (path, transferQ, cmdPool)) { + ulong vertexCount, indexCount; + + ctx.GetVertexCount (out vertexCount, out indexCount, out IndexBufferType); + ulong vertSize = vertexCount * (ulong)Marshal.SizeOf<Vertex> (); + ulong idxSize = indexCount * (IndexBufferType == VkIndexType.Uint16 ? 2ul : 4ul); + ulong size = vertSize + idxSize; + + vbo = new GPUBuffer (dev, VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, vertSize); + ibo = new GPUBuffer (dev, VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, idxSize); + + vbo.SetName ("vbo gltf"); + ibo.SetName ("ibo gltf"); + + Meshes = new List<Mesh> (ctx.LoadMeshes<Vertex> (IndexBufferType, vbo, 0, ibo, 0)); + + textures = ctx.LoadImages (); + + loadMaterials (ctx, layout, attachments); + + materialUBO = new HostBuffer<Material> (dev, VkBufferUsageFlags.UniformBuffer, materials); + + Scenes = new List<Scene> (ctx.LoadScenes (out defaultSceneIndex)); + } + } + } + + void loadMaterials (glTFLoader ctx, DescriptorSetLayout layout, params AttachmentType[] attachments) { + Model.Material[] mats = ctx.LoadMaterial (); + materials = new Material[mats.Length]; + descriptorSets = new DescriptorSet[mats.Length]; + + if (attachments.Length == 0) + throw new InvalidOperationException ("At least one attachment is required for Model.WriteMaterialDescriptor"); + + descriptorPool = new DescriptorPool (dev, (uint)materials.Length, + new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, (uint)(attachments.Length * materials.Length)) + ); + descriptorPool.SetName ("descPool gltfTextures"); + + for (int i = 0; i < mats.Length; i++) { + materials[i] = new Material { + workflow = (float)mats[i].workflow, + baseColorFactor = mats[i].baseColorFactor, + emissiveFactor = mats[i].emissiveFactor, + metallicFactor = mats[i].metallicFactor, + roughnessFactor = mats[i].roughnessFactor, + TexCoord0 = mats[i].availableAttachments, + TexCoord1 = mats[i].availableAttachments1, + alphaMask = 0f, + alphaMaskCutoff = 0.0f, + diffuseFactor = new Vector4 (0), + specularFactor = new Vector4 (0) + }; + + descriptorSets[i] = descriptorPool.Allocate (layout); + descriptorSets[i].Handle.SetDebugMarkerName (dev, "descSet " + mats[i].Name); + + VkDescriptorSetLayoutBinding dslb = + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler); + + using (DescriptorSetWrites2 uboUpdate = new DescriptorSetWrites2 (dev)) { + for (uint a = 0; a < attachments.Length; a++) { + dslb.binding = a; + switch (attachments[a]) { + case AttachmentType.None: + break; + case AttachmentType.Color: + if (mats[i].availableAttachments.HasFlag (AttachmentType.Color)) + uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].baseColorTexture].Descriptor); + break; + case AttachmentType.Normal: + if (mats[i].availableAttachments.HasFlag (AttachmentType.Normal)) + uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].normalTexture].Descriptor); + break; + case AttachmentType.AmbientOcclusion: + if (mats[i].availableAttachments.HasFlag (AttachmentType.AmbientOcclusion)) + uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].occlusionTexture].Descriptor); + break; + case AttachmentType.PhysicalProps: + if (mats[i].availableAttachments.HasFlag (AttachmentType.PhysicalProps)) + uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].metallicRoughnessTexture].Descriptor); + break; + case AttachmentType.Metal: + break; + case AttachmentType.Roughness: + break; + case AttachmentType.Emissive: + if (mats[i].availableAttachments.HasFlag (AttachmentType.Emissive)) + uboUpdate.AddWriteInfo (descriptorSets[i], dslb, textures[(int)mats[i].emissiveTexture].Descriptor); + break; + } + } + uboUpdate.Update (); + } + } + } + + public override void RenderNode (CommandBuffer cmd, PipelineLayout pipelineLayout, Node node, Matrix4x4 currentTransform, bool shadowPass = false) { + Matrix4x4 localMat = node.localMatrix * currentTransform; + VkShaderStageFlags matStage = shadowPass ? VkShaderStageFlags.Geometry : VkShaderStageFlags.Vertex; + cmd.PushConstant (pipelineLayout, matStage, localMat); + + if (node.Mesh != null) { + foreach (Primitive p in node.Mesh.Primitives) { + if (!shadowPass) { + cmd.PushConstant (pipelineLayout, VkShaderStageFlags.Fragment, (int)p.material, (uint)Marshal.SizeOf<Matrix4x4> ()); + if (descriptorSets[p.material] != null) + cmd.BindDescriptorSet (pipelineLayout, descriptorSets[p.material], 2); + } + cmd.DrawIndexed (p.indexCount, 1, p.indexBase, p.vertexBase, 0); + } + } + if (node.Children == null) + return; + foreach (Node child in node.Children) + RenderNode (cmd, pipelineLayout, child, localMat, shadowPass); + } + + protected override void Dispose (bool disposing) { + if (!isDisposed) { + if (disposing) { + foreach (Image txt in textures) + txt.Dispose (); + } else + Debug.WriteLine ("model was not disposed"); + } + base.Dispose (disposing); + } + } +} diff --git a/vke/src/PbrModelTexArray.cs b/vke/src/PbrModelTexArray.cs new file mode 100644 index 0000000..47b6b74 --- /dev/null +++ b/vke/src/PbrModelTexArray.cs @@ -0,0 +1,168 @@ +// +// PbrModel.cs +// +// Author: +// Jean-Philippe Bruyère <jp_bruyere@hotmail.com> +// +// Copyright (c) 2019 jp +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.InteropServices; + +using VK; +using System.Collections.Generic; + +namespace CVKL { + using static VK.Utils; + + /// <summary> + /// Indexed pbr model whith one descriptorSet per material with separate textures attachments + /// </summary> + public class PbrModelTexArray : PbrModel { + public static uint TEXTURE_DIM = 512; + /// <summary> + /// Pbr data structure suitable for push constant or ubo, containing + /// availablility of attached textures and the coef of pbr inputs + /// </summary> + public struct Material { + public Vector4 baseColorFactor; + public Vector4 emissiveFactor; + public Vector4 diffuseFactor; + public Vector4 specularFactor; + + public float workflow; + public AttachmentType TexCoord0; + public AttachmentType TexCoord1; + public int baseColorTextureSet; + + public int physicalDescriptorTextureSet; + public int normalTextureSet; + public int occlusionTextureSet; + public int emissiveTextureSet; + + public float metallicFactor; + public float roughnessFactor; + public float alphaMask; + public float alphaMaskCutoff; + } + + public Image texArray; + public Material[] materials; + + public PbrModelTexArray (Queue transferQ, string path) { + dev = transferQ.Dev; + using (CommandPool cmdPool = new CommandPool (dev, transferQ.index)) { + using (glTFLoader ctx = new glTFLoader (path, transferQ, cmdPool)) { + ulong vertexCount, indexCount; + + ctx.GetVertexCount (out vertexCount, out indexCount, out IndexBufferType); + ulong vertSize = vertexCount * (ulong)Marshal.SizeOf<Vertex> (); + ulong idxSize = indexCount * (IndexBufferType == VkIndexType.Uint16 ? 2ul : 4ul); + ulong size = vertSize + idxSize; + + vbo = new GPUBuffer (dev, VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, vertSize); + ibo = new GPUBuffer (dev, VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, idxSize); + + vbo.SetName ("vbo gltf"); + ibo.SetName ("ibo gltf"); + + Meshes = new List<Mesh> (ctx.LoadMeshes<Vertex> (IndexBufferType, vbo, 0, ibo, 0)); + + texArray = new Image (dev, Image.DefaultTextureFormat, VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst | VkImageUsageFlags.TransferSrc, + VkMemoryPropertyFlags.DeviceLocal, TEXTURE_DIM, TEXTURE_DIM, VkImageType.Image2D, + VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal, Image.ComputeMipLevels(TEXTURE_DIM), ctx.ImageCount); + + ctx.BuildTexArray (ref texArray, 0); + + texArray.CreateView (VkImageViewType.ImageView2DArray, VkImageAspectFlags.Color, texArray.CreateInfo.arrayLayers); + texArray.CreateSampler (); + texArray.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + texArray.SetName ("model texArray"); + + loadMaterials (ctx); + + materialUBO = new HostBuffer<Material> (dev, VkBufferUsageFlags.UniformBuffer, materials); + + Scenes = new List<Scene> (ctx.LoadScenes (out defaultSceneIndex)); + } + } + } + + void loadMaterials (glTFLoader ctx) { + Model.Material[] mats = ctx.LoadMaterial (); + materials = new Material[mats.Length]; + + for (int i = 0; i < mats.Length; i++) { + materials[i] = new Material { + workflow = (float)mats[i].workflow, + baseColorFactor = mats[i].baseColorFactor, + emissiveFactor = mats[i].emissiveFactor, + metallicFactor = mats[i].metallicFactor, + roughnessFactor = mats[i].roughnessFactor, + + baseColorTextureSet = mats[i].baseColorTexture, + physicalDescriptorTextureSet = mats[i].metallicRoughnessTexture, + normalTextureSet = mats[i].normalTexture, + occlusionTextureSet = mats[i].occlusionTexture, + emissiveTextureSet = mats[i].emissiveTexture, + + TexCoord0 = mats[i].availableAttachments, + TexCoord1 = mats[i].availableAttachments1, + + alphaMask = 0f, + alphaMaskCutoff = 0.0f, + diffuseFactor = new Vector4 (0), + specularFactor = new Vector4 (0) + }; + } + } + + public override void RenderNode (CommandBuffer cmd, PipelineLayout pipelineLayout, Node node, Matrix4x4 currentTransform, bool shadowPass = false) { + Matrix4x4 localMat = node.localMatrix * currentTransform; + VkShaderStageFlags matStage = shadowPass ? VkShaderStageFlags.Geometry : VkShaderStageFlags.Vertex; + cmd.PushConstant (pipelineLayout, matStage, localMat); + + if (node.Mesh != null) { + foreach (Primitive p in node.Mesh.Primitives) { + if (!shadowPass) { + cmd.PushConstant (pipelineLayout, VkShaderStageFlags.Fragment, (int)p.material, (uint)Marshal.SizeOf<Matrix4x4> ()); + } + cmd.DrawIndexed (p.indexCount, 1, p.indexBase, p.vertexBase, 0); + } + } + if (node.Children == null) + return; + foreach (Node child in node.Children) + RenderNode (cmd, pipelineLayout, child, localMat, shadowPass); + } + + protected override void Dispose (bool disposing) { + if (!isDisposed) { + if (disposing) { + texArray?.Dispose (); + } else + Debug.WriteLine ("model was not disposed"); + } + base.Dispose (disposing); + } + } +} diff --git a/vke/src/SubPass.cs b/vke/src/SubPass.cs index 016641b..e0998e8 100644 --- a/vke/src/SubPass.cs +++ b/vke/src/SubPass.cs @@ -1,5 +1,5 @@ // -// AttachmentReference.cs +// SubPass.cs // // Author: // Jean-Philippe Bruyère <jp_bruyere@hotmail.com> @@ -23,91 +23,10 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -using System; using System.Collections.Generic; -using System.Runtime.InteropServices; using VK; namespace CVKL { - //public class NativeList2<T> : IDisposable where T : struct { - // const int sizeStep = 4; - // int eltSize; - // int capacity; - // int count; - // IntPtr handle; - - // public IntPtr Pointer => handle; - - // public NativeList2 (T[] array) { - // eltSize = Marshal.SizeOf<T> (); - // capacity = count = array.Length; - // GCHandle hnd = GCHandle.Alloc (array, GCHandleType.Pinned); - // handle = GCHandle.ToIntPtr (hnd); - // } - - // public void Add (T elem) { - // if (count == capacity) { - // } - // } - - // void resize (int newSize) { - - // } - - // #region IDisposable Support - // private bool disposedValue; - // protected virtual void Dispose (bool disposing) { - // if (!disposedValue) { - // if (disposing) { - // } - // handle.Free (); - // disposedValue = true; - // } - // } - // public void Dispose () { - // Dispose (true); - // GC.SuppressFinalize(this); - // } - // ~NativeList2 () { Dispose (false); } - // #endregion - //} - - - public class MarshaledObject<T> : IDisposable where T : struct { - - GCHandle handle; - - public IntPtr Pointer { - get { - if (!handle.IsAllocated) - throw new InvalidOperationException ("Unalocated MarshaledObject"); - return handle.AddrOfPinnedObject (); - } - } - - public MarshaledObject (T mobj) { - handle = GCHandle.Alloc (mobj, GCHandleType.Pinned); - } - - void freeHandle () { - if (!disposed) - handle.Free (); - } - - #region IDisposable Support - private bool disposed; - - ~MarshaledObject() { - freeHandle (); - } - - public void Dispose () { - freeHandle (); - GC.SuppressFinalize(this); - } - #endregion - } - public class SubPass { List<VkAttachmentReference> colorRefs = new List<VkAttachmentReference>(); List<VkAttachmentReference> inputRefs = new List<VkAttachmentReference>(); @@ -122,7 +41,6 @@ namespace CVKL { AddColorReference (i, layouts[i]); } - public void AddColorReference (uint attachment, VkImageLayout layout = VkImageLayout.DepthStencilAttachmentOptimal) { AddColorReference (new VkAttachmentReference { attachment = attachment, layout = layout }); } diff --git a/vke/src/SwapChain.cs b/vke/src/SwapChain.cs index ad25abd..5473c93 100644 --- a/vke/src/SwapChain.cs +++ b/vke/src/SwapChain.cs @@ -28,32 +28,33 @@ using VK; using static VK.Vk; namespace CVKL { - public class SwapChain { - Device dev; - PresentQueue presentQueue; + public class SwapChain : Activable { internal VkSwapchainKHR handle; - public VkSemaphore presentComplete; + internal uint currentImageIndex; + VkSwapchainCreateInfoKHR createInfos; + PresentQueue presentQueue; + public VkSemaphore presentComplete; public Image[] images; - internal uint currentImageIndex; + protected override VkDebugMarkerObjectNameInfoEXT DebugMarkerInfo + => new VkDebugMarkerObjectNameInfoEXT (VkDebugReportObjectTypeEXT.SwapchainKhrEXT, handle.Handle); - VkSwapchainCreateInfoKHR createInfos; - public uint ImageCount => (uint)images?.Length; + 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) { - presentQueue = _presentableQueue; - dev = presentQueue.dev; + 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); + VkSurfaceFormatKHR[] formats = Dev.phy.GetSurfaceFormats (presentQueue.Surface); for (int i = 0; i < formats.Length; i++) { if (formats[i].format == format) { createInfos.imageFormat = format; @@ -64,7 +65,7 @@ namespace CVKL { if (createInfos.imageFormat == VkFormat.Undefined) throw new Exception ("Invalid format for swapchain: " + format); - VkPresentModeKHR[] presentModes = dev.phy.GetSurfacePresentModes (presentQueue.Surface); + VkPresentModeKHR[] presentModes = Dev.phy.GetSurfacePresentModes (presentQueue.Surface); for (int i = 0; i < presentModes.Length; i++) { if (presentModes[i] == presentMode) { createInfos.presentMode = presentMode; @@ -81,18 +82,23 @@ namespace CVKL { createInfos.imageSharingMode = VkSharingMode.Exclusive; createInfos.compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR; createInfos.presentMode = presentMode; - createInfos.clipped = 1; - - presentComplete = dev.CreateSemaphore (); - presentComplete.SetDebugMarkerName (dev, "Semaphore PresentComplete"); - - Create (); + createInfos.clipped = 1; } + public override void Activate () { + if (state != ActivableState.Activated) { + presentComplete = Dev.CreateSemaphore (); + presentComplete.SetDebugMarkerName (Dev, "Semaphore PresentComplete"); + } + base.Activate (); + } - public void Create () { - dev.WaitIdle (); + public void Create () { + if (state != ActivableState.Activated) + Activate (); - VkSurfaceCapabilitiesKHR capabilities = dev.phy.GetSurfaceCapabilities (presentQueue.Surface); + Dev.WaitIdle (); + + VkSurfaceCapabilitiesKHR capabilities = Dev.phy.GetSurfaceCapabilities (presentQueue.Surface); createInfos.minImageCount = capabilities.minImageCount; createInfos.preTransform = capabilities.currentTransform; @@ -111,23 +117,23 @@ namespace CVKL { } else createInfos.imageExtent = capabilities.currentExtent; - VkSwapchainKHR newSwapChain = dev.CreateSwapChain (createInfos); + VkSwapchainKHR newSwapChain = Dev.CreateSwapChain (createInfos); if (handle.Handle != 0) _destroy (); handle = newSwapChain; - VkImage[] tmp = dev.GetSwapChainImages (handle); + 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] = new Image (Dev, tmp[i], ColorFormat, ImageUsage, Width, Height); images[i].CreateView (); images[i].SetName ("SwapChain Img" + i); - images[i].Descriptor.imageView.SetDebugMarkerName (dev, "SwapChain Img" + i + " view"); + images[i].Descriptor.imageView.SetDebugMarkerName (Dev, "SwapChain Img" + i + " view"); } } public int GetNextImage () { - VkResult res = vkAcquireNextImageKHR (dev.VkDev, handle, UInt64.MaxValue, presentComplete, VkFence.Null, out currentImageIndex); + VkResult res = vkAcquireNextImageKHR (Dev.VkDev, handle, UInt64.MaxValue, presentComplete, VkFence.Null, out currentImageIndex); if (res == VkResult.ErrorOutOfDateKHR || res == VkResult.SuboptimalKHR) { Create (); return -1; @@ -140,13 +146,28 @@ namespace CVKL { for (int i = 0; i < ImageCount; i++) images[i].Dispose (); - dev.DestroySwapChain (handle); + Dev.DestroySwapChain (handle); } - public void Destroy () { - _destroy (); + public override string ToString () { + return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString ("x")}]"); + } - dev.DestroySemaphore (presentComplete); - } - } + #region IDisposable Support + protected override void Dispose (bool disposing) { + if (state == ActivableState.Activated) { + if (disposing) { + } else + System.Diagnostics.Debug.WriteLine ("VKE Swapchain disposed by finalizer"); + + Dev.DestroySemaphore (presentComplete); + _destroy (); + + } else if (disposing) + System.Diagnostics.Debug.WriteLine ("Calling dispose on unactive Swapchain"); + + base.Dispose (disposing); + } + #endregion + } } diff --git a/vke/src/VkWindow.cs b/vke/src/VkWindow.cs index 6928e73..15d4697 100644 --- a/vke/src/VkWindow.cs +++ b/vke/src/VkWindow.cs @@ -35,24 +35,20 @@ namespace CVKL { /// Base class to build vulkan application. /// Provide default swapchain with its command pool and buffers per image and the main present queue /// </summary> - public abstract class VkWindow : IDisposable { + public abstract class VkWindow : IDisposable { static VkWindow currentWindow; IntPtr hWin; -#if DEBUG - DebugReport dbgRepport; -#endif - - protected VkSurfaceKHR hSurf; - protected Instance instance; - protected PhysicalDevice phy; - protected Device dev; - protected PresentQueue presentQueue; - protected SwapChain swapChain; - protected CommandPool cmdPool; - protected CommandBuffer[] cmds; - protected VkSemaphore[] drawComplete; + protected VkSurfaceKHR hSurf; + protected Instance instance; + protected PhysicalDevice phy; + protected Device dev; + protected PresentQueue presentQueue; + protected SwapChain swapChain; + protected CommandPool cmdPool; + protected CommandBuffer[] cmds; + protected VkSemaphore[] drawComplete; protected uint fps; protected bool updateViewRequested = true, rebuildBuffers = false; @@ -64,7 +60,7 @@ namespace CVKL { /// </summary> protected Camera camera = new Camera (Utils.DegreesToRadians (45f), 1f); - uint width, height; + uint width, height; bool[] buttons = new bool[10]; public Modifier KeyModifiers = 0; @@ -76,132 +72,122 @@ namespace CVKL { /// </summary> public virtual string[] EnabledExtensions { get { - return new string[] {Ext.D.VK_KHR_swapchain}; - } + return new string[] { Ext.D.VK_KHR_swapchain }; + } } /// <summary> /// Frequency in millisecond of the call to the Update method /// </summary> public long UpdateFrequency = 200; - public uint Width => width; - public uint Height => height; + public uint Width => width; + public uint Height => height; - public VkWindow (bool debugMarkers = false, string name = "VkWindow", uint _width = 1024, uint _height=768, bool vSync = false) - { - currentWindow = this; + public VkWindow (bool debugMarkers = false, string name = "VkWindow", uint _width = 1024, uint _height = 768, bool vSync = false) { + currentWindow = this; - width = _width; - height = _height; + width = _width; + height = _height; - Glfw3.Init (); + Glfw3.Init (); - Glfw3.WindowHint (WindowAttribute.ClientApi, 0); - Glfw3.WindowHint (WindowAttribute.Resizable, 1); + Glfw3.WindowHint (WindowAttribute.ClientApi, 0); + Glfw3.WindowHint (WindowAttribute.Resizable, 1); hWin = Glfw3.CreateWindow ((int)width, (int)height, name, MonitorHandle.Zero, IntPtr.Zero); - Glfw3.SetKeyCallback (hWin, HandleKeyDelegate); - Glfw3.SetMouseButtonPosCallback (hWin, HandleMouseButtonDelegate); - Glfw3.SetCursorPosCallback (hWin, HandleCursorPosDelegate); - Glfw3.SetWindowSizeCallback (hWin, HandleWindowSizeDelegate); + Glfw3.SetKeyCallback (hWin, HandleKeyDelegate); + Glfw3.SetMouseButtonPosCallback (hWin, HandleMouseButtonDelegate); + Glfw3.SetCursorPosCallback (hWin, HandleCursorPosDelegate); + Glfw3.SetWindowSizeCallback (hWin, HandleWindowSizeDelegate); Glfw3.SetScrollCallback (hWin, HandleScrollDelegate); Glfw3.SetCharCallback (hWin, HandleCharDelegate); - initVulkan (vSync, debugMarkers); + initVulkan (vSync, debugMarkers); } void initVulkan (bool vSync, bool debugMarkers) { - instance = new Instance (); - -#if DEBUG - dbgRepport = new DebugReport (instance, - VkDebugReportFlagsEXT.ErrorEXT - | VkDebugReportFlagsEXT.DebugEXT - | VkDebugReportFlagsEXT.WarningEXT - | VkDebugReportFlagsEXT.PerformanceWarningEXT - //| VkDebugReportFlagsEXT.InformationEXT - ); -#endif + instance = new Instance (); hSurf = instance.CreateSurface (hWin); - phy = instance.GetAvailablePhysicalDevice ().Where (p => p.HasSwapChainSupport).FirstOrDefault (); + phy = instance.GetAvailablePhysicalDevice ().Where (p => p.HasSwapChainSupport).FirstOrDefault (); - VkPhysicalDeviceFeatures enabledFeatures = default(VkPhysicalDeviceFeatures); - configureEnabledFeatures (phy.Features, ref enabledFeatures); + VkPhysicalDeviceFeatures enabledFeatures = default (VkPhysicalDeviceFeatures); + configureEnabledFeatures (phy.Features, ref enabledFeatures); if (debugMarkers) debugMarkers = phy.GetDeviceExtensionSupported (Ext.D.VK_EXT_debug_marker); //First create the c# device class dev = new Device (phy, debugMarkers); - //create queue class - createQueues (); + //create queue class + createQueues (); - //activate the device to have effective queues created accordingly to what's available - dev.Activate (enabledFeatures, EnabledExtensions); + //activate the device to have effective queues created accordingly to what's available + dev.Activate (enabledFeatures, EnabledExtensions); - swapChain = new SwapChain (presentQueue as PresentQueue, width, height, VkFormat.B8g8r8a8Srgb, - vSync ? VkPresentModeKHR.FifoKHR : VkPresentModeKHR.MailboxKHR ); + swapChain = new SwapChain (presentQueue as PresentQueue, width, height, VkFormat.B8g8r8a8Srgb, + vSync ? VkPresentModeKHR.FifoKHR : VkPresentModeKHR.MailboxKHR); + swapChain.Create (); - cmdPool = new CommandPool(dev, presentQueue.qFamIndex); + cmdPool = new CommandPool (dev, presentQueue.qFamIndex); - cmds = new CommandBuffer[swapChain.ImageCount]; - drawComplete = new VkSemaphore[swapChain.ImageCount]; + cmds = new CommandBuffer[swapChain.ImageCount]; + drawComplete = new VkSemaphore[swapChain.ImageCount]; - for (int i = 0; i < swapChain.ImageCount; i++) - drawComplete[i] = dev.CreateSemaphore (); + for (int i = 0; i < swapChain.ImageCount; i++) + drawComplete[i] = dev.CreateSemaphore (); cmdPool.SetName ("main CmdPool"); for (int i = 0; i < swapChain.ImageCount; i++) drawComplete[i].SetDebugMarkerName (dev, "Semaphore DrawComplete" + i); - } + } /// <summary> /// override this method to modify enabled features before device creation /// </summary> /// <param name="enabled_features">Features.</param> protected virtual void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures enabled_features) { - } + } /// <summary> /// override this method to create additional queue. Dedicated queue of the requested type will be selected first, created queues may excess /// available physical queues. /// </summary> - protected virtual void createQueues () { - presentQueue = new PresentQueue (dev, VkQueueFlags.Graphics, hSurf); - } + protected virtual void createQueues () { + presentQueue = new PresentQueue (dev, VkQueueFlags.Graphics, hSurf); + } /// <summary> /// Main render method called each frame. get next swapchain image, process resize if needed, submit and present to the presentQueue. /// Wait QueueIdle after presenting. /// </summary> - protected virtual void render () { - int idx = swapChain.GetNextImage(); - if (idx < 0) { - OnResize (); - return; - } + protected virtual void render () { + int idx = swapChain.GetNextImage (); + if (idx < 0) { + OnResize (); + return; + } - presentQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx]); - presentQueue.Present (swapChain, drawComplete[idx]); + presentQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx]); + presentQueue.Present (swapChain, drawComplete[idx]); - presentQueue.WaitIdle (); - } + presentQueue.WaitIdle (); + } - protected virtual void onScroll (double xOffset, double yOffset) {} - protected virtual void onMouseMove (double xPos, double yPos) { + protected virtual void onScroll (double xOffset, double yOffset) { } + protected virtual void onMouseMove (double xPos, double yPos) { double diffX = lastMouseX - xPos; double diffY = lastMouseY - yPos; if (MouseButton[0]) { - camera.Rotate ((float)-diffX,(float)-diffY); + camera.Rotate ((float)-diffX, (float)-diffY); } else if (MouseButton[1]) { - camera.Move (0,0,(float)diffY); + camera.Move (0, 0, (float)diffY); } updateViewRequested = true; - } - protected virtual void onMouseButtonDown (Glfw.MouseButton button) { } - protected virtual void onMouseButtonUp (Glfw.MouseButton button) { } - protected virtual void onKeyDown (Key key, int scanCode, Modifier modifiers) { + } + protected virtual void onMouseButtonDown (Glfw.MouseButton button) { } + protected virtual void onMouseButtonUp (Glfw.MouseButton button) { } + protected virtual void onKeyDown (Key key, int scanCode, Modifier modifiers) { switch (key) { case Key.F4: if (modifiers == Modifier.Alt) @@ -241,21 +227,21 @@ namespace CVKL { protected virtual void onChar (CodePoint cp) { } #region events delegates - static void HandleWindowSizeDelegate (IntPtr window, int width, int height) {} - static void HandleCursorPosDelegate (IntPtr window, double xPosition, double yPosition) { - currentWindow.onMouseMove (xPosition, yPosition); + static void HandleWindowSizeDelegate (IntPtr window, int width, int height) { } + static void HandleCursorPosDelegate (IntPtr window, double xPosition, double yPosition) { + currentWindow.onMouseMove (xPosition, yPosition); currentWindow.lastMouseX = xPosition; currentWindow.lastMouseY = yPosition; - } - static void HandleMouseButtonDelegate (IntPtr window, Glfw.MouseButton button, InputAction action, Modifier mods) { - if (action == InputAction.Press) { - currentWindow.buttons[(int)button] = true; - currentWindow.onMouseButtonDown (button); - } else { - currentWindow.buttons[(int)button] = false; - currentWindow.onMouseButtonUp (button); - } - } + } + static void HandleMouseButtonDelegate (IntPtr window, Glfw.MouseButton button, InputAction action, Modifier mods) { + if (action == InputAction.Press) { + currentWindow.buttons[(int)button] = true; + currentWindow.onMouseButtonDown (button); + } else { + currentWindow.buttons[(int)button] = false; + currentWindow.onMouseButtonUp (button); + } + } static void HandleScrollDelegate (IntPtr window, double xOffset, double yOffset) { currentWindow.onScroll (xOffset, yOffset); } @@ -263,10 +249,10 @@ namespace CVKL { currentWindow.KeyModifiers = modifiers; if (action == InputAction.Press || action == InputAction.Repeat) { currentWindow.onKeyDown (key, scanCode, modifiers); - } else { + } else { currentWindow.onKeyUp (key, scanCode, modifiers); } - } + } static void HandleCharDelegate (IntPtr window, CodePoint codepoint) { currentWindow.onChar (codepoint); } @@ -276,46 +262,46 @@ namespace CVKL { /// main window loop, exits on GLFW3 exit event /// </summary> public virtual void Run () { - OnResize (); - UpdateView (); + OnResize (); + UpdateView (); - frameChrono = Stopwatch.StartNew (); + frameChrono = Stopwatch.StartNew (); long totTime = 0; - while (!Glfw3.WindowShouldClose (hWin)) { - render (); + while (!Glfw3.WindowShouldClose (hWin)) { + render (); - if(updateViewRequested) - UpdateView (); + if (updateViewRequested) + UpdateView (); - frameCount++; + frameCount++; - if (frameChrono.ElapsedMilliseconds > UpdateFrequency) { + if (frameChrono.ElapsedMilliseconds > UpdateFrequency) { Update (); frameChrono.Stop (); totTime += frameChrono.ElapsedMilliseconds; - fps = (uint)((double)frameCount / (double)totTime * 1000.0); - //Glfw3.SetWindowTitle (hWin, "FPS: " + fps.ToString ()); + fps = (uint)((double)frameCount / (double)totTime * 1000.0); + Glfw3.SetWindowTitle (hWin, "FPS: " + fps.ToString ()); if (totTime > 2000) { frameCount = 0; totTime = 0; } frameChrono.Restart (); - } - Glfw3.PollEvents (); - } - } - public virtual void UpdateView () {} + } + Glfw3.PollEvents (); + } + } + public virtual void UpdateView () { } /// <summary> /// custom update method called at UpdateFrequency /// </summary> - public virtual void Update () {} + public virtual void Update () { } /// <summary> /// called when swapchain has been resized, override this method to resize your framebuffers coupled to the swapchain /// </summary> - protected virtual void OnResize () {} + protected virtual void OnResize () { } #region IDisposable Support @@ -330,7 +316,7 @@ namespace CVKL { cmds[i].Free (); } - swapChain.Destroy (); + swapChain.Dispose (); vkDestroySurfaceKHR (instance.Handle, hSurf, IntPtr.Zero); @@ -338,9 +324,6 @@ namespace CVKL { if (disposing) { dev.Dispose (); -#if DEBUG - dbgRepport.Dispose (); -#endif instance.Dispose (); } else Debug.WriteLine ("a VkWindow has not been correctly disposed"); diff --git a/vke/src/glTFLoader.cs b/vke/src/glTFLoader.cs index cf18110..d21ff61 100644 --- a/vke/src/glTFLoader.cs +++ b/vke/src/glTFLoader.cs @@ -109,6 +109,9 @@ namespace CVKL { } } + public uint ImageCount => gltf.Images == null ? 0 : (uint)gltf.Images.Length; + + //TODO: some buffer data are reused between primitives, and I duplicate the datas //buffers must be constructed without duplications public Mesh[] LoadMeshes<TVertex> (VkIndexType indexType, Buffer vbo, ulong vboOffset, Buffer ibo, ulong iboOffset) { @@ -361,7 +364,8 @@ namespace CVKL { Node node = new Node { localMatrix = localTransform, - Parent = parentNode + Parent = parentNode, + Name = gltfNode.Name }; parentNode.Children.Add (node); @@ -380,69 +384,90 @@ namespace CVKL { ///// </summary> ///// <returns>The images.</returns> ///// <param name="textureSize">Texture size.</param> - //public Image LoadImages (uint textureSize) { - // Image imgs = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst, VkMemoryPropertyFlags.DeviceLocal, textureSize, textureSize, - // VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal); + public void BuildTexArray (ref Image texArray, uint firstImg = 0) { + int texDim = (int)texArray.CreateInfo.extent.width; - // CommandBuffer cmd = cmdPool.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); + CommandBuffer cmd = cmdPool.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); + texArray.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, + VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.Transfer); + cmd.End (); + transferQ.Submit (cmd); + transferQ.WaitIdle (); + cmd.Free (); - // foreach (GL.Image img in gltf.Images) { - // Image vkimg = null; + VkImageBlit imageBlit = new VkImageBlit { + srcSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1, 0), + dstOffsets_1 = new VkOffset3D (texDim, texDim, 1) + }; - // string imgName = img.Name; + for (int l = 0; l < gltf.Images.Length; l++) { + GL.Image img = gltf.Images[l]; + Image vkimg = null; - // if (img.BufferView != null) {//load image from gltf buffer view - // GL.BufferView bv = gltf.BufferViews[(int)img.BufferView]; - // EnsureBufferIsLoaded (bv.Buffer); - // vkimg = Image.Load (dev, bufferHandles[bv.Buffer].AddrOfPinnedObject () + bv.ByteOffset, (ulong)bv.ByteLength); - // } else if (img.Uri.StartsWith ("data:", StringComparison.Ordinal)) {//load base64 encoded image - // Debug.WriteLine ("loading embedded image {0} : {1}", img.Name, img.MimeType); - // 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)); - // imgName += ";" + img.Uri; - // } + if (img.BufferView != null) {//load image from gltf buffer view + GL.BufferView bv = gltf.BufferViews[(int)img.BufferView]; + EnsureBufferIsLoaded (bv.Buffer); + vkimg = Image.Load (dev, bufferHandles[bv.Buffer].AddrOfPinnedObject () + bv.ByteOffset, (ulong)bv.ByteLength); + } else if (img.Uri.StartsWith ("data:", StringComparison.Ordinal)) {//load base64 encoded image + Debug.WriteLine ("loading embedded image {0} : {1}", img.Name, img.MimeType); + vkimg = Image.Load (dev, 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, Path.Combine (baseDirectory, img.Uri)); + } + imageBlit.srcOffsets_1 = new VkOffset3D ((int)vkimg.CreateInfo.extent.width, (int)vkimg.CreateInfo.extent.height, 1); + imageBlit.dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1, 0, (uint)l + firstImg); - // VkImageSubresourceRange mipSubRange = new VkImageSubresourceRange (VkImageAspectFlags.Color, 0, 1, 0, info.arrayLayers); + cmd = cmdPool.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); - // SetLayout (cmd, VkImageLayout.Undefined, VkImageLayout.TransferSrcOptimal, mipSubRange, - // VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); + vkimg.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferSrcOptimal, + VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); - // for (int i = 1; i < info.mipLevels; i++) { - // VkImageBlit imageBlit = new VkImageBlit { - // 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) - // }; + Vk.vkCmdBlitImage (cmd.Handle, vkimg.handle, VkImageLayout.TransferSrcOptimal, + texArray.handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, VkFilter.Linear); - // mipSubRange.baseMipLevel = (uint)i; + cmd.End (); + transferQ.Submit (cmd); + transferQ.WaitIdle (); + cmd.Free (); - // SetLayout (cmd, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, mipSubRange, - // VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); - // vkCmdBlitImage (cmd.Handle, handle, VkImageLayout.TransferSrcOptimal, handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, VkFilter.Linear); - // SetLayout (cmd, VkImageLayout.TransferDstOptimal, VkImageLayout.TransferSrcOptimal, mipSubRange, - // VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); - // } - // SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.TransferSrcOptimal, VkImageLayout.ShaderReadOnlyOptimal, - // VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader); + vkimg.Dispose (); + } + uint imgCount = (uint)gltf.Images.Length; - // vkimg.CreateView (); - // vkimg.CreateSampler (); - // vkimg.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + VkImageSubresourceRange mipSubRange = new VkImageSubresourceRange (VkImageAspectFlags.Color, 0, 1, firstImg, imgCount); - // vkimg.SetName (imgName); - // vkimg.Descriptor.imageView.SetDebugMarkerName (dev, "imgView " + imgName); - // vkimg.Descriptor.sampler.SetDebugMarkerName (dev, "sampler " + imgName); + cmd = cmdPool.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); + texArray.SetLayout (cmd, VkImageLayout.Undefined, VkImageLayout.TransferSrcOptimal, mipSubRange, + VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); + + for (int i = 1; i < texArray.CreateInfo.mipLevels; i++) { + imageBlit = new VkImageBlit { + srcSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, imgCount, (uint)i - 1, firstImg), + srcOffsets_1 = new VkOffset3D ((int)texDim >> (i - 1), (int)texDim >> (i - 1), 1), + dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, imgCount, (uint)i, firstImg), + dstOffsets_1 = new VkOffset3D ((int)texDim >> i, (int)texDim >> i, 1) + }; + mipSubRange.baseMipLevel = (uint)i; + + texArray.SetLayout (cmd, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, mipSubRange, + VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); + Vk.vkCmdBlitImage (cmd.Handle, texArray.handle, VkImageLayout.TransferSrcOptimal, + texArray.handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, VkFilter.Linear); + texArray.SetLayout (cmd, VkImageLayout.TransferDstOptimal, VkImageLayout.TransferSrcOptimal, mipSubRange, + VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); + } - // textures.Add (vkimg); - // } + texArray.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.TransferSrcOptimal, VkImageLayout.ShaderReadOnlyOptimal, + VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader); - // return imgs; - //} + cmd.End (); + transferQ.Submit (cmd); + transferQ.WaitIdle (); + cmd.Free (); + } public Image[] LoadImages () { if (gltf.Images == null) @@ -498,21 +523,21 @@ namespace CVKL { FromFloatArray (ref pbr.emissiveFactor, mat.EmissiveFactor); if (mat.EmissiveTexture != null) { - pbr.emissiveTexture = (uint)mat.EmissiveTexture.Index; + pbr.emissiveTexture = mat.EmissiveTexture.Index; if (mat.EmissiveTexture.TexCoord == 1) pbr.availableAttachments1 |= AttachmentType.Emissive; else pbr.availableAttachments |= AttachmentType.Emissive; } if (mat.NormalTexture != null) { - pbr.normalTexture = (uint)mat.NormalTexture.Index; + pbr.normalTexture = mat.NormalTexture.Index; if (mat.NormalTexture.TexCoord == 1) pbr.availableAttachments1 |= AttachmentType.Normal; else pbr.availableAttachments |= AttachmentType.Normal; } if (mat.OcclusionTexture != null) { - pbr.occlusionTexture = (uint)mat.OcclusionTexture.Index; + pbr.occlusionTexture = mat.OcclusionTexture.Index; if (mat.OcclusionTexture.TexCoord == 1) pbr.availableAttachments1 |= AttachmentType.AmbientOcclusion; else @@ -521,7 +546,7 @@ namespace CVKL { if (mat.PbrMetallicRoughness != null) { if (mat.PbrMetallicRoughness.BaseColorTexture != null) { - pbr.baseColorTexture = (uint)mat.PbrMetallicRoughness.BaseColorTexture.Index; + pbr.baseColorTexture = mat.PbrMetallicRoughness.BaseColorTexture.Index; if (mat.PbrMetallicRoughness.BaseColorTexture.TexCoord == 1) pbr.availableAttachments1 |= AttachmentType.Color; else @@ -531,7 +556,7 @@ namespace CVKL { FromFloatArray (ref pbr.baseColorFactor, mat.PbrMetallicRoughness.BaseColorFactor); if (mat.PbrMetallicRoughness.MetallicRoughnessTexture != null) { - pbr.metallicRoughnessTexture = (uint)mat.PbrMetallicRoughness.MetallicRoughnessTexture.Index; + pbr.metallicRoughnessTexture = mat.PbrMetallicRoughness.MetallicRoughnessTexture.Index; if (mat.PbrMetallicRoughness.MetallicRoughnessTexture.TexCoord == 1) pbr.availableAttachments1 |= AttachmentType.PhysicalProps; else |