]> O.S.I.I.S - jp/vke.net.git/commitdiff
wip devel
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Tue, 19 May 2020 09:19:19 +0000 (11:19 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Tue, 19 May 2020 09:19:19 +0000 (11:19 +0200)
60 files changed:
Directory.Build.props
addons/CrowWindow/CrowWindow.csproj [new file with mode: 0644]
addons/CrowWindow/FSQPipeline.cs [new file with mode: 0644]
addons/CrowWindow/VkCrowWindow.cs [new file with mode: 0644]
addons/CrowWindow/shaders/simpletexture.frag [new file with mode: 0644]
addons/gltfLoader/gltfLoader.csproj
samples/Directory.Build.props
samples/Model/EditableShaderInfo.cs [new file with mode: 0644]
samples/Model/Model.csproj
samples/Model/main.cs
samples/Model/shaders/model.frag
samples/Model/shaders/model.vert
samples/Model/ui/main.crow [new file with mode: 0755]
samples/TexturedCube/TexturedCube.csproj
samples/crowWin/FSQPipeline.cs
samples/crowWin/VkCrowWindow.cs
samples/crowWin/shaders/simpletexture.frag
samples/deferred/main.cs
samples/glow/DebuDrawPipeline.cs [new file with mode: 0644]
samples/glow/DeferredPbrRenderer.cs [new file with mode: 0644]
samples/glow/EnvironmentPipeline.cs [new file with mode: 0644]
samples/glow/glow.csproj [new file with mode: 0644]
samples/glow/main-crow.cs [new file with mode: 0644]
samples/glow/main.cs [new file with mode: 0644]
samples/glow/mainShadow.cs [new file with mode: 0644]
samples/glow/mainWithDebugDrawer.cs [new file with mode: 0644]
samples/glow/modelWithVkvgStats.cs [new file with mode: 0644]
samples/glow/shaders/GBuffPbr.frag [new file with mode: 0644]
samples/glow/shaders/GBuffPbr.vert [new file with mode: 0644]
samples/glow/shaders/GBuffPbrCommon.inc [new file with mode: 0644]
samples/glow/shaders/GBuffPbrTexArray.frag [new file with mode: 0644]
samples/glow/shaders/bloom.comp [new file with mode: 0644]
samples/glow/shaders/bloom.frag [new file with mode: 0644]
samples/glow/shaders/compose.frag [new file with mode: 0644]
samples/glow/shaders/compose_with_shadows.frag [new file with mode: 0644]
samples/glow/shaders/debug.frag [new file with mode: 0644]
samples/glow/shaders/debug.vert [new file with mode: 0644]
samples/glow/shaders/emissive.frag [new file with mode: 0644]
samples/glow/shaders/shadow.geom [new file with mode: 0644]
samples/glow/shaders/shadow.vert [new file with mode: 0644]
samples/glow/shaders/show_gbuff.frag [new file with mode: 0644]
samples/glow/shaders/simpletexture.frag [new file with mode: 0644]
samples/glow/shaders/tone_mapping.frag [new file with mode: 0644]
samples/glow/shadowMapRenderer.cs [new file with mode: 0644]
samples/glow/ui/debug.crow [new file with mode: 0644]
samples/glow/ui/deferred.style [new file with mode: 0644]
samples/glow/ui/main.crow [new file with mode: 0644]
samples/glow/ui/materials.crow [new file with mode: 0644]
samples/glow/ui/menu.crow [new file with mode: 0644]
samples/glow/ui/sceneItem.crow [new file with mode: 0644]
samples/glow/ui/scenes.crow [new file with mode: 0644]
samples/glow/ui/testImage.crow [new file with mode: 0644]
vke.net.sln
vke/src/ExtensionMethods.cs
vke/src/ShaderInfo.cs
vke/src/Utils.cs
vke/src/base/ComputePipeline.cs
vke/src/base/GraphicPipeline.cs
vke/src/base/Resource.cs
vke/vke.csproj

index e4fbc00aba2329358a8ef295b7d191bd47a81222..b6f81a71fb348b5762ddbe095f4b3414af3c0d92 100644 (file)
@@ -4,7 +4,7 @@
                <RestoreAdditionalProjectSources Condition="Exists('$(SolutionDir)build\$(Configuration)\')">$(SolutionDir)build\$(Configuration)\</RestoreAdditionalProjectSources>
                <SpirVTasksReleaseVersion>0.1.44</SpirVTasksReleaseVersion>
                <SpirVTasksPackageVersion>$(SpirVTasksReleaseVersion)-beta</SpirVTasksPackageVersion>
-               <VkeReleaseVersion>0.1.18</VkeReleaseVersion>
+               <VkeReleaseVersion>0.1.20</VkeReleaseVersion>
                <VkePackageVersion>$(VkeReleaseVersion)-beta</VkePackageVersion>
                
                <LangVersion>7.2</LangVersion>
diff --git a/addons/CrowWindow/CrowWindow.csproj b/addons/CrowWindow/CrowWindow.csproj
new file mode 100644 (file)
index 0000000..58bbead
--- /dev/null
@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  
+  <PropertyGroup>
+    <AssemblyName>CrowWindow</AssemblyName>
+    <PackageId>vke.CrowWindow</PackageId>
+    <AssemblyVersion>$(VkeReleaseVersion)</AssemblyVersion>
+    <Description>vke.net addon to creaet a vulkan window with crow gui support.</Description>
+    <PackageTags>vulkan gui ui c# vke.net</PackageTags>    
+    <PackageVersion>$(AssemblyVersion)</PackageVersion>
+    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
+    <PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
+    <PackageProjectUrl>https://github.com/jpbruyere/vke.net/blob/master/README.md</PackageProjectUrl>
+    <License>MIT</License>
+    <PackageReleaseNotes></PackageReleaseNotes>
+    <SynchReleaseVersion>false</SynchReleaseVersion>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>    
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Crow" Version="0.9.2-beta" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Remove="main.cs" />
+  </ItemGroup>
+</Project>
diff --git a/addons/CrowWindow/FSQPipeline.cs b/addons/CrowWindow/FSQPipeline.cs
new file mode 100644 (file)
index 0000000..19cc423
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (c) 2019  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Numerics;
+using vke;
+using Vulkan;
+
+namespace vke {
+
+       public class FSQPipeline : GraphicPipeline {
+               public static string FragPath = "#CrowWindow.simpletexture.frag.spv";
+               public FSQPipeline (RenderPass renderPass, PipelineLayout pipelineLayout, int attachment = 0, PipelineCache pipelineCache = null)
+               : base (renderPass, pipelineCache, "FSQ pipeline") {
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, this.RenderPass.Samples, false);
+                       cfg.RenderPass = RenderPass;
+                       cfg.Layout = pipelineLayout;
+                       cfg.AddShader (Dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv");
+                       cfg.AddShader (Dev, VkShaderStageFlags.Fragment, FragPath);
+                       cfg.multisampleState.rasterizationSamples = Samples;
+
+                       cfg.blendAttachments[attachment] = new VkPipelineColorBlendAttachmentState (true);
+
+                       layout = cfg.Layout;
+
+                       init (cfg);
+
+                       cfg.DisposeShaders ();
+               }
+
+               public virtual void RecordDraw (CommandBuffer cmd) {
+                       Bind (cmd);
+                       cmd.Draw (3, 1, 0, 0);
+               }
+
+               protected override void Dispose (bool disposing) {
+                       base.Dispose (disposing);
+               }
+       }
+
+}
diff --git a/addons/CrowWindow/VkCrowWindow.cs b/addons/CrowWindow/VkCrowWindow.cs
new file mode 100644 (file)
index 0000000..636ddf2
--- /dev/null
@@ -0,0 +1,255 @@
+// Copyright (c) 2019  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using Glfw;
+using Vulkan;
+using Crow;
+using System.Threading;
+
+namespace vke {
+       /// <summary>
+       /// Vulkan context with Crow enabled window.
+       /// Crow vector drawing is handled with Cairo Image on an Host mapped vulkan image.
+       /// This is an easy way to have GUI in my samples with low GPU cost. Most of the ui
+       /// is cached on cpu memory images.
+       /// </summary>
+       public class CrowWindow : VkWindow, IValueChange {
+               #region IValueChange implementation
+               public event EventHandler<ValueChangeEventArgs> ValueChanged;
+               public virtual void NotifyValueChanged (string MemberName, object _value)
+               {
+                       ValueChanged?.Invoke (this, new ValueChangeEventArgs (MemberName, _value));
+               }
+               #endregion
+
+               public bool MouseIsInInterface =>
+                       iFace.HoverWidget != null;
+
+               protected FSQPipeline fsqPl;
+               DescriptorPool dsPool;
+               protected DescriptorSet descSet;
+               CommandPool cmdPoolCrow;
+               PrimaryCommandBuffer cmdUpdateCrow;
+               Image crowImage;
+               HostBuffer crowBuffer;
+               Interface iFace;
+               protected RenderPass renderPass;
+
+               volatile bool running;
+
+
+               VkDescriptorSetLayoutBinding dslBinding = new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler);
+
+               protected override void initVulkan () {
+                       base.initVulkan ();
+
+                       iFace = new Interface ((int)Width, (int)Height, WindowHandle);
+                       iFace.Init ();
+
+                       CreateRenderPass ();
+
+                       fsqPl = new FSQPipeline (renderPass,
+                               new PipelineLayout (dev, new DescriptorSetLayout (dev, dslBinding)));
+
+                       cmdPoolCrow = new CommandPool (presentQueue, VkCommandPoolCreateFlags.ResetCommandBuffer);
+                       cmdUpdateCrow = cmdPoolCrow.AllocateCommandBuffer ();
+
+                       dsPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler));
+                       descSet = dsPool.Allocate (fsqPl.Layout.DescriptorSetLayouts[0]);
+
+                       Thread ui = new Thread (crowThread);
+                       ui.IsBackground = true;
+                       ui.Start ();
+               }
+               protected virtual void CreateRenderPass () {
+                       renderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), VkSampleCountFlags.SampleCount1);
+               }
+
+
+               protected override void onMouseMove (double xPos, double yPos)
+               {
+                       if (iFace.OnMouseMove ((int)xPos, (int)yPos))
+                               return;
+                       base.onMouseMove (xPos, yPos);
+               }
+               protected override void onMouseButtonDown (MouseButton button) {
+                       if (iFace.OnMouseButtonDown (button))
+                               return;
+                       base.onMouseButtonDown (button);
+               }
+               protected override void onMouseButtonUp (MouseButton button)
+               {
+                       if (iFace.OnMouseButtonUp (button))
+                               return;
+                       base.onMouseButtonUp (button);
+               }
+               protected override void onScroll (double xOffset, double yOffset) {
+                       if (iFace.OnMouseWheelChanged ((float)yOffset))
+                               return;
+                       base.onScroll (xOffset, yOffset);
+               }
+               protected override void onChar (CodePoint cp) {
+                       if (iFace.OnKeyPress (cp.ToChar()))
+                               return;
+                       base.onChar (cp);
+               }
+               protected override void onKeyUp (Key key, int scanCode, Modifier modifiers) {
+                       if (iFace.OnKeyUp (key))
+                               return;
+                       base.onKeyUp (key, scanCode, modifiers);
+               }
+               protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
+                       if (iFace.OnKeyDown (key))
+                               return;
+                       base.onKeyDown (key, scanCode, modifiers);
+               }
+
+               protected override void render () {
+
+                       int idx = swapChain.GetNextImage ();
+                       if (idx < 0) {
+                               OnResize ();
+                               return;
+                       }
+
+                       if (cmds[idx] == null)
+                               return;
+
+                       drawFence.Wait ();
+                       drawFence.Reset ();
+
+                       if (Monitor.IsEntered (iFace.UpdateMutex))
+                               Monitor.Exit (iFace.UpdateMutex);
+
+                       presentQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx], drawFence);
+                       presentQueue.Present (swapChain, drawComplete[idx]);
+               }
+
+               public override void Update () {
+                       if (iFace.IsDirty) {
+                               drawFence.Wait ();
+                               drawFence.Reset ();
+                               Monitor.Enter (iFace.UpdateMutex);
+                               presentQueue.Submit (cmdUpdateCrow, default, default, drawFence);
+                               iFace.IsDirty = false;
+                       }
+
+                       NotifyValueChanged ("fps", fps);
+               }
+
+               protected override void OnResize ()
+               {
+                       base.OnResize ();
+                       dev.WaitIdle ();
+                       initCrowSurface ();
+                       iFace.ProcessResize (new Rectangle (0, 0, (int)Width, (int)Height));
+               }
+
+               protected virtual void recordUICmd (CommandBuffer cmd) {
+                       fsqPl.BindDescriptorSet (cmd, descSet, 0);
+                       fsqPl.RecordDraw (cmd);
+               }
+
+               void crowThread () {
+                       while (iFace.surf == null) {
+                               Thread.Sleep (10);
+                       }
+                       running = true;
+                       while (running) {
+                               iFace.Update ();
+                               Thread.Sleep (10);
+                       }
+               }
+               void initCrowSurface () {
+                       lock (iFace.UpdateMutex) {
+                               iFace.surf?.Dispose ();
+                               crowImage?.Dispose ();
+                               crowBuffer?.Dispose ();
+
+                               crowBuffer = new HostBuffer (dev, VkBufferUsageFlags.TransferSrc | VkBufferUsageFlags.TransferDst, Width * Height * 4, true);
+
+                               crowImage = new Image (dev, VkFormat.B8g8r8a8Unorm, VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst,
+                                       VkMemoryPropertyFlags.DeviceLocal, Width, Height, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Linear);
+                               crowImage.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color);
+                               crowImage.CreateSampler (VkFilter.Nearest, VkFilter.Nearest, VkSamplerMipmapMode.Nearest, VkSamplerAddressMode.ClampToBorder);
+                               crowImage.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+
+                               DescriptorSetWrites dsw = new DescriptorSetWrites (descSet, dslBinding);
+                               dsw.Write (dev, crowImage.Descriptor);
+
+                               iFace.surf = new Crow.Cairo.ImageSurface (crowBuffer.MappedData, Crow.Cairo.Format.ARGB32,
+                                       (int)Width, (int)Height, (int)Width * 4);
+
+                               PrimaryCommandBuffer cmd = cmdPoolCrow.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit);
+                               crowImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.Preinitialized, VkImageLayout.ShaderReadOnlyOptimal);
+                               presentQueue.EndSubmitAndWait (cmd, true);
+
+                               recordUpdateCrowCmd ();
+                       }
+               }
+
+               /// <summary>
+               /// command buffer must have been reseted
+               /// </summary>
+               void recordUpdateCrowCmd () {
+                       cmdPoolCrow.Reset ();
+                       cmdUpdateCrow.Start ();
+                       crowImage.SetLayout (cmdUpdateCrow, VkImageAspectFlags.Color,
+                               VkImageLayout.ShaderReadOnlyOptimal, VkImageLayout.TransferDstOptimal,
+                               VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.Transfer);
+
+                       crowBuffer.CopyTo (cmdUpdateCrow, crowImage, VkImageLayout.ShaderReadOnlyOptimal);
+
+                       crowImage.SetLayout (cmdUpdateCrow, VkImageAspectFlags.Color,
+                               VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal,
+                               VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader);
+                       cmdUpdateCrow.End ();
+               }
+
+
+               protected void loadWindow (string path, object dataSource = null) {
+                       try {
+                               Widget w = iFace.FindByName (path);
+                               if (w != null) {
+                                       iFace.PutOnTop (w);
+                                       return;
+                               }
+                               w = iFace.Load (path);
+                               w.Name = path;
+                               w.DataSource = dataSource;
+
+                       } catch (Exception ex) {
+                               System.Diagnostics.Debug.WriteLine (ex.Message);
+                       }
+               }
+               protected void loadIMLFragment (string imlFragment, object dataSource = null) {
+                       try {
+                               iFace.LoadIMLFragment (imlFragment).DataSource = dataSource;
+                       } catch (Exception ex) {
+                               System.Diagnostics.Debug.WriteLine (ex.Message);
+                       }
+               }
+               protected void closeWindow (string path) {
+                       Widget g = iFace.FindByName (path);
+                       if (g != null)
+                               iFace.DeleteWidget (g);
+               }
+
+
+               protected override void Dispose (bool disposing) {
+                       dev.WaitIdle ();
+
+                       running = false;
+                       fsqPl.Dispose ();
+                       dsPool.Dispose ();
+                       cmdPoolCrow.Dispose ();
+                       crowImage?.Dispose ();
+                       crowBuffer?.Dispose ();
+                       iFace.Dispose ();
+
+                       base.Dispose (disposing);
+               }
+
+       }
+}
diff --git a/addons/CrowWindow/shaders/simpletexture.frag b/addons/CrowWindow/shaders/simpletexture.frag
new file mode 100644 (file)
index 0000000..95cab5f
--- /dev/null
@@ -0,0 +1,14 @@
+#version 450
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (set = 0, binding = 0) uniform sampler2D samplerColor;
+
+layout (location = 0) in       vec2 inUV;
+layout (location = 0) out      vec4 outFragColor;
+
+void main()
+{
+       outFragColor = texture(samplerColor, inUV);
+}
index b7940e5ebfae1855f85c34ac9a1cc4dbe91bbcbe..64da4326f9cf600dc175f71a84299ae022298191 100644 (file)
@@ -4,8 +4,8 @@
     <AssemblyName>vke.gltfLoader</AssemblyName>
     <PackageId>vke.gltfLoader</PackageId>
     <AssemblyVersion>$(VkeReleaseVersion)</AssemblyVersion>
-    <Description>vke.net gltf addons</Description>
-    <PackageTags>C# vulkan CVKL gltf</PackageTags>    
+    <Description>vke.net glTF addons</Description>
+    <PackageTags>vulkan C# gltf</PackageTags>    
     <PackageVersion>$(AssemblyVersion)</PackageVersion>
     <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
     <PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
index 899a632a7e1b4a2d07d77a953ae2b2fbc6767410..93eff46b4e55f88ed13ceeb0a361ace6513de777 100644 (file)
@@ -21,7 +21,7 @@
        </PropertyGroup>
     
        <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">    
-               <DefineConstants>TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;_WITH_VKVG</DefineConstants>    
+               <DefineConstants>TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;_WITH_SHADOWS;_WITH_VKVG</DefineConstants>    
        </PropertyGroup>
        <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
                <DefineConstants>NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;_WITH_VKVG</DefineConstants>    
diff --git a/samples/Model/EditableShaderInfo.cs b/samples/Model/EditableShaderInfo.cs
new file mode 100644 (file)
index 0000000..3f60ca9
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.IO;
+using Crow;
+using vke;
+using Vulkan;
+
+namespace Model {
+       public class EditableShaderInfo : ShaderInfo, IValueChange {
+               #region IValueChange implementation
+               public event EventHandler<ValueChangeEventArgs> ValueChanged;
+               public virtual void NotifyValueChanged (string MemberName, object _value) {
+                       ValueChanged?.Invoke (this, new ValueChangeEventArgs (MemberName, _value));
+               }
+               #endregion
+
+               public event EventHandler ModuleChanged;
+
+               string path;
+               string origSource;
+               string source;
+
+               public string Source {
+                       get => source;
+                       set {
+                               if (source == value)
+                                       return;
+                               source = value;
+
+                               NotifyValueChanged (nameof (IsDirty), IsDirty);
+                               NotifyValueChanged (nameof(Source), source);
+
+                               Compile ();
+                       }
+               }
+
+               string error;
+
+               public bool IsDirty => source != origSource;
+               public bool HasError => !string.IsNullOrEmpty (error);
+
+               public string Error {
+                       get => error;
+                       set {
+                               if (error == value)
+                                       return;
+                               error = value;
+                               NotifyValueChanged (nameof (Error), error);
+                               NotifyValueChanged ("HasError", HasError);
+                       }
+               }
+
+               public EditableShaderInfo (Device dev, string shaderPath, VkShaderStageFlags stageFlags, SpecializationInfo specializationInfo = null, string entryPoint = "main") :
+                       base (stageFlags, default, specializationInfo, entryPoint) {
+                       this.dev = dev;
+                       path = shaderPath;
+                       reloadFromDisk ();
+               }
+
+               void reloadFromDisk () {
+                       using (StreamReader sr = new StreamReader (path)) {
+                               origSource = sr.ReadToEnd ();
+                       }
+                       Source = origSource;
+               }
+
+               public bool Compile () {
+                       using (shaderc.Compiler comp = new shaderc.Compiler ()) {
+                               using (shaderc.Result res = comp.Compile (source, path, Utils.ShaderStageToShaderKind (Stage))) {
+                                       if (res.Status == shaderc.Status.Success) {
+                                               dev.DestroyShaderModule (info.module);
+                                               info.module = dev.CreateShaderModule (res.CodePointer, (UIntPtr)res.CodeLength);
+                                               Error = null;
+                                               ModuleChanged.Raise (this, null);
+                                               return true;
+                                       }
+                                       Error = res.ErrorMessage;
+                               }
+                       }
+                       return false;
+               }
+       }
+}
index 701a289505290c2f0cc2c587171c5d960965fc2b..cdf00049f7831f626bf7b011cc500ec1a81b4fb4 100644 (file)
@@ -2,6 +2,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
        <ItemGroup>
                <ProjectReference Include="..\..\addons\gltfLoader\gltfLoader.csproj" />
+               <ProjectReference Include="..\..\addons\CrowWindow\CrowWindow.csproj" />
        </ItemGroup>
        <ItemGroup>
                <GLSLShader Remove="shaders\**\*.frag;shaders\**\*.vert;shaders\**\*.comp;shaders\**\*.geom" />
index 7799f2c2eedd8ab8a0e96bd37f06921e4be9fcb9..67194563a75218c240d7d0a93b80df42490b1d0a 100644 (file)
@@ -2,14 +2,16 @@
 //
 // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Numerics;
 using System.Runtime.InteropServices;
 using vke;
 using vke.glTF;
 using Vulkan;
 
-namespace ModelSample {
-       class Program : VkWindow {
+namespace Model{
+       class Program : CrowWindow {
                static void Main (string[] args) {
 #if DEBUG
                        Instance.VALIDATION = true;
@@ -37,7 +39,7 @@ namespace ModelSample {
 
                FrameBuffers frameBuffers;
 
-               GraphicPipeline pipeline;
+               GraphicPipeline modelPipeline;
 
                VkSampleCountFlags NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
 
@@ -45,7 +47,11 @@ namespace ModelSample {
 
                DebugDrawPipeline dbgPipeline;
 
+               public List<ShaderInfo> Shaders {
+                       get => modelPlCfg?.Shaders;
+               }
 
+               GraphicPipelineConfig modelPlCfg;
 
                protected override void initVulkan () {
                        base.initVulkan ();
@@ -56,6 +62,7 @@ namespace ModelSample {
 
                        cmds = cmdPool.AllocateCommandBuffer(swapChain.ImageCount);
                        cmdDebug = cmdPool.AllocateSecondaryCommandBuffer ();
+                       cmdUI = cmdPool.AllocateSecondaryCommandBuffer ();
 
                        descriptorPool = new DescriptorPool (dev, 2,
                                new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer),
@@ -69,28 +76,30 @@ namespace ModelSample {
                                new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),
                                new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)
                        );
-                               
-                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, NUM_SAMPLES);
-                       cfg.rasterizationState.cullMode = VkCullModeFlags.Back;
+
+                       modelPlCfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, NUM_SAMPLES);
+
+                       modelPlCfg.rasterizationState.cullMode = VkCullModeFlags.Back;
                        if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1) {
-                               cfg.multisampleState.sampleShadingEnable = true;
-                               cfg.multisampleState.minSampleShading = 0.5f;
+                               modelPlCfg.multisampleState.sampleShadingEnable = true;
+                               modelPlCfg.multisampleState.minSampleShading = 0.5f;
                        }
 
-                       cfg.Layout = new PipelineLayout (dev, new VkPushConstantRange(VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()), descLayoutMatrix, descLayoutTextures);
-                       cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), cfg.Samples);
-                       cfg.AddVertexBinding<Model.Vertex> (0);
-                       cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat);
+                       modelPlCfg.Layout = new PipelineLayout (dev, new VkPushConstantRange(VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()), descLayoutMatrix, descLayoutTextures);
+                       modelPlCfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), modelPlCfg.Samples);
+                       modelPlCfg.AddVertexBinding<SimpleModel.Vertex> (0);
+                       modelPlCfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat);
 
-                       using (shaderc.Compiler comp = new shaderc.Compiler()) {
 
-                               cfg.AddShaders (comp.CreateShaderInfo (dev, "shaders/model.vert", shaderc.ShaderKind.VertexShader));
-                               cfg.AddShaders (comp.CreateShaderInfo (dev, "shaders/model.frag", shaderc.ShaderKind.FragmentShader));
-                       }
+                       modelPlCfg.AddShaders (new EditableShaderInfo (dev, "shaders/model.vert", VkShaderStageFlags.Vertex));
+                       modelPlCfg.AddShaders (new EditableShaderInfo (dev, "shaders/model.frag", VkShaderStageFlags.Fragment));
 
-                       pipeline = new GraphicPipeline (cfg);
+                       foreach (EditableShaderInfo esi in modelPlCfg.Shaders.OfType<EditableShaderInfo> ()) {
+                               esi.Compile ();
+                               esi.ModuleChanged += (sender, e) => rebuildModelPipeline = true;
+                       }
 
-                       cfg.DisposeShaders ();
+                       buildModelPipeline ();
 
                        helmet = new SimpleModel (presentQueue, Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf");
 
@@ -105,12 +114,12 @@ namespace ModelSample {
                        DescriptorSetWrites texturesUpdate = new DescriptorSetWrites (dsTextures, descLayoutTextures);
                        texturesUpdate.Write (dev,
                                helmet.textures[0].Descriptor,
-                               helmet.textures[1].Descriptor,
-                               helmet.textures[2].Descriptor);
+                               helmet.textures[4].Descriptor,
+                               helmet.textures[3].Descriptor);
 
                        uboMats.Map ();//permanent map
 
-                       dbgPipeline = new DebugDrawPipeline (pipeline.RenderPass);
+                       dbgPipeline = new DebugDrawPipeline (modelPipeline.RenderPass);
                        dbgPipeline.AddLine (Vector3.Zero, Vector3.UnitX, 1, 0, 0);
                        dbgPipeline.AddLine (Vector3.Zero, Vector3.UnitY, 0, 1, 0);
                        dbgPipeline.AddLine (Vector3.Zero, Vector3.UnitZ, 0, 0, 1);
@@ -118,34 +127,44 @@ namespace ModelSample {
 
                        cmdPoolModel = new CommandPool (presentQueue, VkCommandPoolCreateFlags.ResetCommandBuffer);
                        cmdModel = cmdPoolModel.AllocateSecondaryCommandBuffer ();
+
+                       UpdateFrequency = 20;
+
+                       loadWindow ("#ui.main.crow", this);
                }
 
+               void buildModelPipeline () {
+                       dev.WaitIdle ();
+                       GraphicPipeline newPL = new GraphicPipeline (modelPlCfg);
+                       modelPipeline?.Dispose ();
+                       modelPipeline = newPL;
+               }
 
-               bool rebuildCmdBuffers, rebuildCmdModel = true;
+               bool rebuildCmdBuffers, rebuildCmdModel = true, rebuildModelPipeline;
                CommandPool cmdPoolModel;
-               SecondaryCommandBuffer cmdModel, cmdDebug;
+               SecondaryCommandBuffer cmdModel, cmdDebug, cmdUI;
 
                void buildModelCmd () {
                        cmdPoolModel.Reset ();
-                       cmdModel.Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, pipeline.RenderPass, 0);
+                       cmdModel.Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, modelPipeline.RenderPass, 0);
 
                        cmdModel.SetViewport (swapChain.Width, swapChain.Height);
                        cmdModel.SetScissor (swapChain.Width, swapChain.Height);
 
-                       cmdModel.BindDescriptorSet (pipeline.Layout, dsMatrices);
-                       cmdModel.BindDescriptorSet (pipeline.Layout, dsTextures, 1);
+                       cmdModel.BindDescriptorSet (modelPipeline.Layout, dsMatrices);
+                       cmdModel.BindDescriptorSet (modelPipeline.Layout, dsTextures, 1);
 
                        Matrix4x4 matrix = Matrix4x4.Identity;
-                       cmdModel.PushConstant (pipeline.Layout, VkShaderStageFlags.Vertex, matrix);
+                       cmdModel.PushConstant (modelPipeline.Layout, VkShaderStageFlags.Vertex, matrix);
 
-                       cmdModel.BindPipeline (pipeline);
+                       cmdModel.BindPipeline (modelPipeline);
 
-                       helmet.DrawAll (cmdModel, pipeline.Layout);
+                       helmet.DrawAll (cmdModel, modelPipeline.Layout);
                        cmdModel.End ();
                }
 
                void buildDebugCmd () {
-                       cmdDebug.Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, pipeline.RenderPass);
+                       cmdDebug.Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, modelPipeline.RenderPass);
 
                        float d = 0.2f;
                        uint dbgW = (uint)(swapChain.Width * d);
@@ -161,6 +180,15 @@ namespace ModelSample {
                        cmdDebug.End ();
                }
 
+               protected override void recordUICmd (CommandBuffer cmd) {
+                       (cmd as SecondaryCommandBuffer).Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, modelPipeline.RenderPass);
+                       cmd.SetViewport (swapChain.Width, swapChain.Height);
+                       cmd.SetScissor (swapChain.Width, swapChain.Height);
+                       fsqPl.BindDescriptorSet (cmd, descSet, 0);
+                       fsqPl.RecordDraw (cmd);
+                       cmd.End ();
+               }
+
                void buildCommandBuffers () {
                        dev.WaitIdle ();
                        cmdPool.Reset (VkCommandPoolResetFlags.ReleaseResources);
@@ -171,19 +199,21 @@ namespace ModelSample {
                        }
 
                        buildDebugCmd ();
+                       recordUICmd (cmdUI);
 
                        for (int i = 0; i < swapChain.ImageCount; ++i) {
                                FrameBuffer fb = frameBuffers[i];
                                cmds[i].Start ();
 
-                               pipeline.RenderPass.Begin (cmds[i], fb, VkSubpassContents.SecondaryCommandBuffers);
+                               modelPipeline.RenderPass.Begin (cmds[i], fb, VkSubpassContents.SecondaryCommandBuffers);
 
                                if (cmdModel != null)
                                        cmds[i].Execute (cmdModel);
-                                       
+
+                               cmds[i].Execute (cmdUI);
                                cmds[i].Execute (cmdDebug);
 
-                               pipeline.RenderPass.End (cmds[i]);
+                               modelPipeline.RenderPass.End (cmds[i]);
 
                                cmds[i].End ();
                        }
@@ -191,10 +221,16 @@ namespace ModelSample {
 
 
                public override void Update () {
+                       if (rebuildModelPipeline) {
+                               buildModelPipeline ();
+                               rebuildModelPipeline = false;
+                               rebuildCmdModel = rebuildCmdBuffers = true;
+                       }
                        if (rebuildCmdBuffers) {
                                buildCommandBuffers ();
                                rebuildCmdBuffers = false;
                        }
+                       base.Update ();
                }
                public override void UpdateView () {
                        camera.AspectRatio = (float)swapChain.Width / swapChain.Height;
@@ -207,28 +243,31 @@ namespace ModelSample {
                }
 
                protected override void onMouseMove (double xPos, double yPos) {
-                       double diffX = lastMouseX - xPos;
-                       double diffY = lastMouseY - yPos;
-                       if (MouseButton[0]) {
-                               camera.Rotate ((float)-diffY,0, (float)diffX);
-                       } else if (MouseButton[1]) {
-                               camera.SetZoom ((float)diffY);
-                       } else
+                       base.onMouseMove (xPos, yPos);
+                       if (MouseIsInInterface)
                                return;
-                       rebuildCmdBuffers = true;
-                       updateViewRequested = true;
-               }
-
-
 
+                       //double diffX = lastMouseX - xPos;
+                       //double diffY = lastMouseY - yPos;
+                       //if (MouseButton[0]) {
+                       //      camera.Rotate ((float)-diffY,0, (float)diffX);
+                       //} else if (MouseButton[1]) {
+                       //      camera.SetZoom ((float)diffY);
+                       //} else
+                       //      return;
+                       //rebuildCmdBuffers = true;
+                       //updateViewRequested = true;
+               }
 
                protected override void OnResize () {
                        base.OnResize();
 
                        frameBuffers?.Dispose();
-                       frameBuffers = pipeline.RenderPass.CreateFrameBuffers(swapChain);
+                       frameBuffers = modelPipeline.RenderPass.CreateFrameBuffers(swapChain);
 
+                       rebuildCmdModel = true;
                        buildCommandBuffers ();
+                       updateViewRequested = true;
                }
 
                class SimpleModel : PbrModel {
@@ -289,7 +328,7 @@ namespace ModelSample {
                        if (disposing) {
                                if (!isDisposed) {
                                        helmet.Dispose ();
-                                       pipeline.Dispose ();
+                                       modelPipeline.Dispose ();
                                        descLayoutMatrix.Dispose ();
                                        descLayoutTextures.Dispose ();
                                        frameBuffers?.Dispose();
index 7083a06d62a1eb0b41a552bc6f126a6b8f463b24..8e8d5026349ac7bb2c0f73efca66a88dd8053e8f 100644 (file)
@@ -9,19 +9,22 @@ layout (set = 1, binding = 2) uniform sampler2D samplerOcclusion;
 
 layout (location = 0) in vec2 inUV;
 layout (location = 1) in vec3 inN;
-layout (location = 2) in vec3 inV;//ViewDir
+layout (location = 2) in vec3 inV;
 layout (location = 3) in vec3 inL;
+layout (location = 4) in vec3 inP;
 
 layout (location = 0) out vec4 outFragColor;
 
 
 
-// http://www.thetenthplanet.de/archives/1180
-mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv)
+vec3 perturb_normal(vec3 N, vec3 P, vec2 uv)
 {
+    // assume N, the interpolated vertex normal and 
+    // V, the view vector (vertex to eye)
+    vec3 map = texture(samplerNormal, uv).xyz * 2.0 - 1.0;
     // get edge vectors of the pixel triangle
-    vec3 dp1 = dFdx( p );
-    vec3 dp2 = dFdy( p );
+    vec3 dp1 = dFdx( P );
+    vec3 dp2 = dFdy( P );
     vec2 duv1 = dFdx( uv );
     vec2 duv2 = dFdy( uv );
  
@@ -33,52 +36,29 @@ mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv)
  
     // construct a scale-invariant frame 
     float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) );
-    return mat3( T * invmax, B * invmax, N );
-}
-
-vec3 perturb_normal( vec3 N, vec3 V, vec2 texcoord )
-{
-    // assume N, the interpolated vertex normal and 
-    // V, the view vector (vertex to eye)
-    vec3 map = texture(samplerNormal, texcoord).xyz;
-    map = map * 255./127. - 128./127.;
-    mat3 TBN = cotangent_frame(N, -V, texcoord);
+    mat3 TBN = mat3( T * invmax, B * invmax, N );
+         
     return normalize(TBN * map);
 }
 
-
 void main() 
 {
     vec4 color = texture(samplerColor, inUV);
 
     vec3 N = normalize(inN);
-    vec3 L = normalize(inL);
     vec3 V = normalize(inV);
+    vec3 L = normalize(inL);
+    vec3 P = normalize(inP);
+    
+    N = perturb_normal(N, P, inUV); 
+    
     vec3 R = reflect(-L, N);
-    vec3 diffuse = max(dot(N, L), 0.0) * vec3(0.9);
-    vec3 specular = pow(max(dot(R, V), 0.0), 16.0) * vec3(0.75);
-    outFragColor = vec4(diffuse * color.rgb + specular, 1.0);       
-}
-/*void main() 
-{    
-    vec4 diff = texture(samplerColor, inUV);
+    vec3 diff = max(dot(N, L), 0.0) * texture(samplerOcclusion, inUV).rgb;
+    vec3 specular = pow(max(dot(R, V), 0.0), 16.0) * vec3(1.0);
     
-    vec3 n = normalize(inN);
-    vec3 l = normalize(-light);
-    vec3 pn = perturb_normal(n, inV, inUV);    
+    outFragColor = vec4(diff * color.rgb + specular, 1.0);
     
-    float lambert = max(0.0, dot(pn, l));
+    /*float fr = dot(N,V);
+    */
     
-    //diff.rgb *= lambert * texture(samplerOcclusion, inUV).rgb;
-    vec3 spec = vec3(0);
-    vec3 amb = vec3(0.1);
-    if (lambert >= 0.0) {
-       vec3 rd = reflect(l, pn);
-       float s = dot(rd, normalize(inV));
-       spec = vec3(0.9,0.9,0.9)* //light.specular.xyz * material.specular.xyz *
-             pow(max(0.0, s), 10.5); //0.5 = mat shininess
-    }
-    //outFragColor = vec4(1.0);  // 
-    //outFragColor = vec4(diff.rgb , 1.0);  // 
-    outFragColor = vec4(diff.rgb + amb + spec , diff.a);  // 
-}*/
\ No newline at end of file
+}
index 3de34fc8491c53d8d7199c5c64063847b1e8def9..69c1ac3338c9a364fe351d7e4e2cf1eb63ce7a33 100644 (file)
@@ -16,8 +16,9 @@ layout (binding = 0) uniform UBO
 
 layout (location = 0) out vec2 outUV;
 layout (location = 1) out vec3 outN;
-layout (location = 2) out vec3 outV;//ViewDir
+layout (location = 2) out vec3 outV;
 layout (location = 3) out vec3 outL;
+layout (location = 4) out vec3 outP;
 
 out gl_PerVertex 
 {
@@ -41,10 +42,11 @@ void main()
     //outN = normalize(transpose(inverse(mat3(mod))) * inNormal);    
     outN = mat3(mod)* inNormal;    
     
-    //mat4 viewInv = inverse(ubo.viewMatrix);
-    
-    outV = -pos.xyz;//normalize(vec3(viewInv * vec4(0.0, 0.0, 0.0, 1.0) - pos));
+    mat4 vi = inverse(ubo.viewMatrix);
+    vec4 vit = vi[3];
+    outV = vec3(vit[0],vit[1],vit[2]); //normalize(vec3(viewInv * vec4(0.0, 0.0, 0.0, 1.0) - pos));
     outL = lPos - pos.xyz;
+    outP = -pos.xyz;
     
        gl_Position = ubo.projectionMatrix * ubo.viewMatrix * pos;    
 }
diff --git a/samples/Model/ui/main.crow b/samples/Model/ui/main.crow
new file mode 100755 (executable)
index 0000000..6b3a54c
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<Window Width="50%" Height="50%" Background="0.1,0.1,0.1,0.7">
+       <HorizontalStack>
+               <ListBox Name="shaders" Data="{Shaders}" Width="30%" Height="Stretched" Background="Transparent"
+                                                SelectionColoring="true" SelectionBackground="RoyalBlue">
+                       <ItemTemplate>
+                               <VerticalStack Height="Fit" Margin="5">
+                                       <Label Text="{Stage}" Width="Stretched" />
+                               </VerticalStack>
+                       </ItemTemplate>
+               </ListBox>
+               <Splitter/>
+               <VerticalStack DataSource="{../shaders.SelectedItem}">
+                       <!--<TextBox Text="{²Source}" Multiline="True" Height="Stretched" TextAlignment="TopLeft" Background="0.0,0.0,0.0,0.7" Foreground="White"/>
+                       <Scroller Height="Stretched" Background="White">
+                               <Label Height="Fit" Text="{Error}" Visible="{HasError}" Width="Stretched" Background="DarkRed" Foreground="White" Multiline="true"/>
+                       </Scroller>-->
+                       <HorizontalStack>
+                               <Scroller Name="scroller1" Background="White"
+                                               Margin="2" ScrollY="{../scrollbar1.Value}"
+                                               ValueChanged="./_scroller_ValueChanged">
+                                       <TextBox VerticalAlignment="Top"
+                                               Text="{²Source}" Multiline="true" TextAlignment="TopLeft"
+                                               Font="Courriernew 10"/>
+                               </Scroller>
+                               <ScrollBar Name="scrollbar1" Value="{../scroller1.ScrollY}"
+                                       LargeIncrement="{../scroller1.PageHeight}" SmallIncrement="30"
+                                       CursorSize="{../scroller1.ChildHeightRatio}"
+                                       Maximum="{../scroller1.MaxScrollY}" Orientation="Vertical"
+                                       Width="14" />
+                       </HorizontalStack>                      
+               </VerticalStack>
+       </HorizontalStack>
+</Window>
\ No newline at end of file
index a2f41d2955374eb7f67353c0ceb226a434c669e9..e316d2d6895d17239388a8563ec11276fae14246 100644 (file)
@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <ItemGroup>
-    <ProjectReference Include="..\..\addons\VkvgPipeline\VkvgPipeline.csproj" />
+<!--    <ProjectReference Include="..\..\addons\VkvgPipeline\VkvgPipeline.csproj" />-->
   </ItemGroup>
 </Project>
 
index 99c56540cd1a81ff88b06f48ec4d1047e50e53a6..db4cadbca268b42ed4748385d97e8167264cd624 100644 (file)
@@ -9,6 +9,7 @@ using Vulkan;
 namespace vke {
 
        public class FSQPipeline : GraphicPipeline {
+               public static string FragPath = "#shaders.simpletexture.frag.spv";
                public FSQPipeline (RenderPass renderPass, PipelineLayout pipelineLayout, int attachment = 0, PipelineCache pipelineCache = null)
                : base (renderPass, pipelineCache, "FSQ pipeline") {
 
@@ -16,7 +17,7 @@ namespace vke {
                        cfg.RenderPass = RenderPass;
                        cfg.Layout = pipelineLayout;
                        cfg.AddShader (Dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv");
-                       cfg.AddShader (Dev, VkShaderStageFlags.Fragment, "#shaders.simpletexture.frag.spv");
+                       cfg.AddShader (Dev, VkShaderStageFlags.Fragment, FragPath);
                        cfg.multisampleState.rasterizationSamples = Samples;
 
                        cfg.blendAttachments[attachment] = new VkPipelineColorBlendAttachmentState (true);
index 7f71778ebf18f0be42c92b95ec182c368b4de13c..9e05b92f3499945f4d113bddbfeb35a00e0b822b 100644 (file)
@@ -19,7 +19,7 @@ namespace vke {
        /// </summary>
        public class CrowWindow : VkWindow, IValueChange {
                #region IValueChange implementation
-               public event EventHandler<Crow.ValueChangeEventArgs> ValueChanged;
+               public event EventHandler<ValueChangeEventArgs> ValueChanged;
                public virtual void NotifyValueChanged (string MemberName, object _value)
                {
                        ValueChanged?.Invoke (this, new ValueChangeEventArgs (MemberName, _value));
@@ -141,7 +141,7 @@ namespace vke {
                        base.OnResize ();
                        dev.WaitIdle ();
                        initCrowSurface ();
-                       iFace.ProcessResize (new Crow.Rectangle (0, 0, (int)Width, (int)Height));
+                       iFace.ProcessResize (new Rectangle (0, 0, (int)Width, (int)Height));
                }
 
                public void RecordDraw (CommandBuffer cmd) {
index 792e2086356d60dd2890391f8ffa03820bd182ba..95cab5f06454cc184017e9423251938648c765cf 100644 (file)
@@ -6,7 +6,6 @@
 layout (set = 0, binding = 0) uniform sampler2D samplerColor;
 
 layout (location = 0) in       vec2 inUV;
-
 layout (location = 0) out      vec4 outFragColor;
 
 void main()
index 0c08882c5f4a4be4140bbe0d5864e93dc197bbe3..7cbc2e1c45602f747baff6f49ab6d2ad87ee195d 100644 (file)
@@ -18,7 +18,7 @@ namespace deferred {
                static void Main (string[] args) {
 #if DEBUG
                        Instance.VALIDATION = true;
-                       //Instance.RENDER_DOC_CAPTURE = true;
+                       Instance.RENDER_DOC_CAPTURE = true;
 #endif
                        SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb;
                        DeferredPbrRenderer.TEXTURE_ARRAY = true;
@@ -65,6 +65,8 @@ namespace deferred {
                };
                string[] modelPathes = {
                                "/mnt/devel/vkPinball/data/models/pinball.gltf",
+                               "/mnt/devel/tests/FidelityFX-SSSR/sample/media/Chess/scene.gltf",
+                               "/mnt/devel/tests/FidelityFX-SSSR/sample/media/Chess/scene.bin",
                                "/mnt/devel/pinball.net/data/test.glb",
                                Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf",
                                //Utils.DataDirectory + "models/shadow.glb",
diff --git a/samples/glow/DebuDrawPipeline.cs b/samples/glow/DebuDrawPipeline.cs
new file mode 100644 (file)
index 0000000..fef2751
--- /dev/null
@@ -0,0 +1,78 @@
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using VK;
+
+namespace CVKL {
+       public class DebugDrawPipeline : GraphicPipeline {
+               public HostBuffer Vertices;
+               uint vertexCount;
+               uint vboLength = 100 * 6 * sizeof (float);
+
+               public DebugDrawPipeline (Device dev, DescriptorSetLayout dsLayout, VkFormat colorFormat, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1) :
+                       base (new RenderPass (dev, colorFormat), "Debug draw pipeline") {
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.LineList, samples);
+                       cfg.rasterizationState.lineWidth = 1.0f;
+                       cfg.RenderPass = RenderPass;
+                       cfg.Layout = new PipelineLayout(dev, dsLayout);
+                       cfg.Layout.AddPushConstants (
+                               new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> () * 2)                     
+                       );
+                       cfg.AddVertexBinding (0, 6 * sizeof(float));
+                       cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat);
+
+                       cfg.blendAttachments[0] = new VkPipelineColorBlendAttachmentState (true);
+
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/debug.vert.spv");
+                       cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/debug.frag.spv");
+
+                       layout = cfg.Layout;
+
+                       init (cfg);
+
+                       Vertices = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vboLength);
+                       Vertices.Map ();
+               }
+
+               public void AddLine (Vector3 start, Vector3 end, float r, float g, float b) {
+                       float[] data = {
+                               start.X, start.Y, start.Z,
+                               r, g, b,
+                               end.X, end.Y, end.Z,
+                               r, g, b
+                       };
+                       Vertices.Update (data, 12 * sizeof (float), vertexCount * 6 * sizeof (float));
+                       vertexCount+=2;
+               }
+
+               public void RecordDraw (CommandBuffer cmd, Framebuffer fb, Camera camera) {
+                       RenderPass.Begin (cmd, fb);
+                       const int ratio = 8;
+                       cmd.SetViewport (fb.Width/ratio, fb.Height/ratio, (ratio-1) * (int)fb.Width / ratio, (ratio-1) * (int)fb.Height / ratio);
+                       //cmd.SetViewport (200, 200,100,100,-10,10);//, 4 * (int)fb.Width / 5, 4 * (int)fb.Height / 5);
+                       cmd.SetScissor (fb.Width / ratio, fb.Height / ratio, (ratio-1) * (int)fb.Width / ratio, (ratio-1) * (int)fb.Height / ratio);
+                       //cmd.SetScissor (200, 200,100,100);
+
+                       Matrix4x4 ortho = Matrix4x4.CreateOrthographic (4, 4.0f / camera.AspectRatio,-1,1);
+
+                       cmd.PushConstant (layout, VkShaderStageFlags.Vertex, ortho);
+
+                       Bind (cmd);
+
+                       cmd.BindVertexBuffer (Vertices);
+                       cmd.Draw (vertexCount);
+                       RenderPass.End (cmd);
+               }
+
+               protected override void Dispose (bool disposing) {
+                       if (disposing) {
+                               Vertices.Unmap ();
+                               Vertices.Dispose ();
+                       }
+
+                       base.Dispose (disposing);
+               }
+       }
+
+}
diff --git a/samples/glow/DeferredPbrRenderer.cs b/samples/glow/DeferredPbrRenderer.cs
new file mode 100644 (file)
index 0000000..6805a14
--- /dev/null
@@ -0,0 +1,512 @@
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using vke;
+using vke.Environment;
+using vke.glTF;
+using Vulkan;
+
+namespace glow {
+       public class DeferredPbrRenderer : IDisposable {
+               Device dev;
+               Queue gQueue;
+               public static int MAX_MATERIAL_COUNT = 4;
+               public static VkSampleCountFlags NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
+               public static VkFormat HDR_FORMAT = VkFormat.R16g16b16a16Sfloat;
+               public static VkFormat MRT_FORMAT = VkFormat.R32g32b32a32Sfloat;
+               public static bool TEXTURE_ARRAY;
+
+               public enum DebugView {
+                       none,
+                       color,
+                       normal,
+                       pos,
+                       occlusion,
+                       emissive,
+                       metallic,
+                       roughness,
+                       depth,
+                       prefill,
+                       irradiance,
+                       shadowMap
+               }
+               public DebugView currentDebugView = DebugView.none;
+               public int lightNumDebug = 0;
+               public int debugMip = 0;
+               public int debugFace = 0;
+
+               const float lightMoveSpeed = 0.1f;
+               public float exposure = 2.0f;
+               public float gamma = 1.2f;
+
+               public struct Matrices {
+                       public Matrix4x4 projection;
+                       public Matrix4x4 model;
+                       public Matrix4x4 view;
+                       public Vector4 camPos;
+                       public float prefilteredCubeMipLevels;
+                       public float scaleIBLAmbient;
+               }
+               public struct Light {
+                       public Vector4 position;
+                       public Vector4 color;
+                       public Matrix4x4 mvp;
+               }
+
+               public Matrices matrices = new Matrices {
+                       scaleIBLAmbient = 1.0f,
+               };
+               public Light[] lights = {
+                       new Light {
+                               position = new Vector4(1.5f,2.5f,1.5f,0f),
+                               color = new Vector4(1,1.0f,1.0f,1)
+                       },
+                       new Light {
+                               position = new Vector4(-1.5f,2.5f,1.5f,0f),
+                               color = new Vector4(0.8f,0.8f,1,1)
+                       }
+               };
+
+               FrameBuffer frameBuffer;
+               public Image gbColorRough, gbEmitMetal, gbN_AO, gbPos, hdrImgResolved;
+
+               DescriptorPool descriptorPool;
+               DescriptorSetLayout descLayoutMain, descLayoutTextures, descLayoutGBuff;
+               DescriptorSet dsMain, dsGBuff;
+
+               public PipelineCache pipelineCache;
+               Pipeline gBuffPipeline, composePipeline, debugPipeline;
+
+               public HostBuffer uboMatrices { get; private set; }
+               public HostBuffer<Light> uboLights { get; private set; }
+
+               RenderPass renderPass;
+
+               public PbrModel model { get; private set; }
+               public EnvironmentCube envCube;
+               public ShadowMapRenderer shadowMapRenderer;
+
+               public BoundingBox modelAABB;
+
+               public VkSemaphore DrawComplete;
+
+               const int SP_SKYBOX             = 0;
+               const int SP_MODELS             = 1;
+               const int SP_COMPOSE            = 2;
+               //const int SP_TONE_MAPPING     = 3;
+
+               string cubemapPath;
+
+               uint width, height;
+               public uint Width => width;
+               public uint Height => height;
+
+               public DeferredPbrRenderer (Queue gQueue, string cubemapPath, uint width, uint height, float nearPlane, float farPlane) {
+                       this.gQueue = gQueue;
+                       this.dev = gQueue.Dev;
+                       this.cubemapPath = cubemapPath;
+                       this.width = width;
+                       this.height = height;
+
+                       DrawComplete = dev.CreateSemaphore();
+
+                       pipelineCache = new PipelineCache (dev);
+
+                       descriptorPool = new DescriptorPool (dev, 5,
+                               new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 3),
+                               new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 6),
+                               new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 5),
+                               new VkDescriptorPoolSize (VkDescriptorType.StorageImage, 4)
+                       );                              
+
+                       uboMatrices = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices, true);
+                       uboLights = new HostBuffer<Light> (dev, VkBufferUsageFlags.UniformBuffer, lights, true);
+
+#if WITH_SHADOWS
+                       shadowMapRenderer = new ShadowMapRenderer (gQueue, this);
+#endif
+
+                       init (nearPlane, farPlane);
+               }
+
+               void init_renderpass () {
+                       renderPass = new RenderPass (dev, NUM_SAMPLES);
+
+                       renderPass.AddAttachment (HDR_FORMAT, VkImageLayout.ShaderReadOnlyOptimal, NUM_SAMPLES);//final outpout
+                       renderPass.AddAttachment (dev.GetSuitableDepthFormat (), VkImageLayout.DepthStencilAttachmentOptimal, NUM_SAMPLES);
+                       renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, 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)
+                       renderPass.AddAttachment (MRT_FORMAT, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff3 (Pos + depth)
+
+                       renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) });
+                       renderPass.ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) });
+                       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) });
+                       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 ()};
+                       //skybox
+                       subpass[SP_SKYBOX].AddColorReference (0, VkImageLayout.ColorAttachmentOptimal);
+                       //models
+                       subpass[SP_MODELS].AddColorReference (new VkAttachmentReference (2, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (3, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (4, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (5, VkImageLayout.ColorAttachmentOptimal));
+                       subpass[SP_MODELS].SetDepthReference (1, VkImageLayout.DepthStencilAttachmentOptimal);
+                       subpass[SP_MODELS].AddPreservedReference (0);
+
+                       //compose
+                       subpass[SP_COMPOSE].AddColorReference (0, VkImageLayout.ColorAttachmentOptimal);
+                       subpass[SP_COMPOSE].AddInputReference (new VkAttachmentReference (2, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (3, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (4, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (5, VkImageLayout.ShaderReadOnlyOptimal));
+                       //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)
+                       //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);
+                       renderPass.AddDependency (SP_SKYBOX, SP_MODELS,
+                               VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader,
+                               VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead);
+                       renderPass.AddDependency (SP_MODELS, SP_COMPOSE,
+                               VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader,
+                               VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead);
+                       //renderPass.AddDependency (SP_COMPOSE, Vk.SubpassExternal,
+                               //VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.Transfer,
+                               //VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.TransferRead);
+                       //renderPass.AddDependency (SP_COMPOSE, SP_COMPOSE,
+                               //VkPipelineStageFlags.Transfer, VkPipelineStageFlags.ComputeShader,
+                               //VkAccessFlags.TransferWrite, VkAccessFlags.ShaderRead);
+                       //renderPass.AddDependency (Vk.SubpassExternal, SP_TONE_MAPPING,
+                       //      VkPipelineStageFlags.ComputeShader, VkPipelineStageFlags.FragmentShader,
+                       //      VkAccessFlags.ShaderWrite, VkAccessFlags.ShaderRead);
+                       //renderPass.AddDependency (SP_SKYBOX, SP_TONE_MAPPING,
+                               //VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader,
+                               //VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead);
+                       renderPass.AddDependency (SP_COMPOSE, Vk.SubpassExternal,
+                               VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.Transfer,
+                               VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.TransferRead);
+                       //renderPass.AddDependency (SP_TONE_MAPPING, Vk.SubpassExternal,
+                                       //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
+                               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.UniformBuffer),//lights
+                               new VkDescriptorSetLayoutBinding (5, VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer));//materials
+#if WITH_SHADOWS
+                       descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (6, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));
+#endif
+
+                       if (TEXTURE_ARRAY) {
+                               descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (7, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));//texture array
+                               //descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (8, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));//down sampled hdr
+                       } 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
+                               new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),//emit + metal
+                               new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),//normals + AO
+                               new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment));//Pos + depth
+
+
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, NUM_SAMPLES);
+                       cfg.rasterizationState.cullMode = VkCullModeFlags.Back;
+                       if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1) {
+                               cfg.multisampleState.sampleShadingEnable = true;
+                               cfg.multisampleState.minSampleShading = 0.5f;
+                       }
+                       cfg.Cache = pipelineCache;
+                       if (TEXTURE_ARRAY) 
+                               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)
+                       );
+                       cfg.RenderPass = renderPass;
+                       cfg.SubpassIndex = SP_MODELS;
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       //cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+
+                       cfg.AddVertex<PbrModelTexArray.Vertex> ();
+
+                       using (SpecializationInfo constants = new SpecializationInfo (
+                                               new SpecializationConstant<float> (0, nearPlane),
+                                               new SpecializationConstant<float> (1, farPlane),
+                                               new SpecializationConstant<float> (2, MAX_MATERIAL_COUNT))) {
+
+                               cfg.AddShader (dev, VkShaderStageFlags.Vertex, "#shaders.GBuffPbr.vert.spv");
+                               if (TEXTURE_ARRAY) 
+                                       cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.GBuffPbrTexArray.frag.spv", constants);
+                               else
+                                       cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.GBuffPbr.frag.spv", constants);
+
+                               gBuffPipeline = new GraphicPipeline (cfg);
+                       }
+                       cfg.rasterizationState.cullMode = VkCullModeFlags.Front;
+                       //COMPOSE PIPELINE
+                       cfg.blendAttachments.Clear ();
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.ResetShadersAndVerticesInfos ();
+                       cfg.SubpassIndex = SP_COMPOSE;
+                       cfg.Layout = gBuffPipeline.Layout;
+                       cfg.depthStencilState.depthTestEnable = false;
+                       cfg.depthStencilState.depthWriteEnable = false;
+                       using (SpecializationInfo constants = new SpecializationInfo (
+                               new SpecializationConstant<uint> (0, (uint)lights.Length))) {
+                               cfg.AddShader (dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv");
+#if WITH_SHADOWS
+                               cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.compose_with_shadows.frag.spv", constants);
+#else
+                               cfg.AddShader (VkShaderStageFlags.Fragment, "#shaders.compose.frag.spv", constants);
+#endif
+                               composePipeline = new GraphicPipeline (cfg);
+                       }
+                       //DEBUG DRAW use subpass of compose
+                       cfg.Shaders[1].Dispose ();
+                       cfg.Shaders[1] = new ShaderInfo (dev, VkShaderStageFlags.Fragment, "#shaders.show_gbuff.frag.spv");
+                       cfg.SubpassIndex = SP_COMPOSE;
+                       debugPipeline = new GraphicPipeline (cfg);
+                       ////TONE MAPPING
+                       //cfg.shaders[1] = new ShaderInfo (VkShaderStageFlags.Fragment, "#shaders.tone_mapping.frag.spv");
+                       //cfg.SubpassIndex = SP_TONE_MAPPING;
+                       //toneMappingPipeline = new GraphicPipeline (cfg);
+
+                       cfg.DisposeShaders ();
+
+                       dsMain = descriptorPool.Allocate (descLayoutMain);
+                       dsGBuff = descriptorPool.Allocate (descLayoutGBuff);
+
+                       envCube = new EnvironmentCube (cubemapPath, gBuffPipeline.Layout, gQueue, renderPass);
+
+                       matrices.prefilteredCubeMipLevels = envCube.prefilterCube.CreateInfo.mipLevels;
+
+                       DescriptorSetWrites dsMainWrite = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings.GetRange (0, 5).ToArray ());
+                       dsMainWrite.Write (dev, 
+                               uboMatrices.Descriptor,
+                               envCube.irradianceCube.Descriptor,
+                               envCube.prefilterCube.Descriptor,
+                               envCube.lutBrdf.Descriptor,
+                               uboLights.Descriptor);
+
+#if WITH_SHADOWS
+                       dsMainWrite = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[6]);
+                       dsMainWrite.Write (dev, shadowMapRenderer.shadowMap.Descriptor);
+#endif
+               }
+
+
+               public void LoadModel (Queue transferQ, string path) {
+                       dev.WaitIdle ();
+                       model?.Dispose ();
+
+                       if (TEXTURE_ARRAY) {
+                               PbrModelTexArray mod = new PbrModelTexArray (transferQ, path);
+                               if (mod.texArray != null) {
+                                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5], descLayoutMain.Bindings[7]);
+                                       uboUpdate.Write (dev, mod.materialUBO.Descriptor, mod.texArray.Descriptor);
+                               }
+                               model = mod;
+                       } 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;
+               }
+               public void buildCommandBuffers (PrimaryCommandBuffer cmd) {
+
+
+                       renderPass.Begin (cmd, frameBuffer);
+
+                       cmd.SetViewport (frameBuffer.Width, frameBuffer.Height);
+                       cmd.SetScissor (frameBuffer.Width, frameBuffer.Height);
+
+                       cmd.BindDescriptorSet (gBuffPipeline.Layout, dsMain);
+
+                       envCube.RecordDraw (cmd);
+
+                       renderPass.BeginSubPass (cmd);
+
+                       if (model != null) {
+                               gBuffPipeline.Bind (cmd);
+                               model.Bind (cmd);
+                               model.DrawAll (cmd, gBuffPipeline.Layout);
+                       }
+
+                       renderPass.BeginSubPass (cmd);
+
+                       //cmd.BindDescriptorSet (composePipeline.Layout, dsMain);
+                       cmd.BindDescriptorSet (composePipeline.Layout, dsGBuff, 1);
+
+                       if (currentDebugView == DebugView.none)
+                               composePipeline.Bind (cmd);
+                       else {
+                               debugPipeline.Bind (cmd);
+                               uint debugValue = (uint)currentDebugView - 1;
+                               if (currentDebugView == DebugView.shadowMap)
+                                       debugValue += (uint)((lightNumDebug << 8));
+                               else
+                                       debugValue += (uint)((debugFace << 8) + (debugMip << 16));
+                               cmd.PushConstant (debugPipeline.Layout, VkShaderStageFlags.Fragment, debugValue, (uint)Marshal.SizeOf<Matrix4x4> ());
+                       }
+
+                       cmd.Draw (3, 1, 0, 0);
+
+                       //renderPass.BeginSubPass (cmd);
+                       //toneMappingPipeline.Bind (cmd);
+                       //cmd.Draw (3, 1, 0, 0);
+
+                       renderPass.End (cmd);
+               }
+
+               public void MoveLight (Vector4 dir) {
+                       lights[lightNumDebug].position += dir * lightMoveSpeed;
+#if WITH_SHADOWS
+                       shadowMapRenderer.updateShadowMap = true;
+#endif
+               }
+
+               #region update
+               public void UpdateView (Camera camera) {
+                       camera.AspectRatio = (float)width / height;
+
+                       matrices.projection = camera.Projection;
+                       //matrices.projection = Utils.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (60), 1, 0.1f, 16f);
+                       matrices.view = camera.View;
+                       //matrices.view = Matrix4x4.CreateLookAt (lights[0].position.ToVector3 (), Vector3.Zero, Vector3.UnitY);
+                       matrices.model = camera.Model;
+
+                       Matrix4x4.Invert (camera.View, out Matrix4x4 inv);
+                       matrices.camPos = new Vector4 (inv.M41, inv.M42, inv.M43, 0);
+
+                       uboMatrices.Update (matrices, (uint)Marshal.SizeOf<Matrices> ());
+               }
+
+               #endregion
+
+
+               void createGBuff () {
+                       gbColorRough?.Dispose ();
+                       gbEmitMetal?.Dispose ();
+                       gbN_AO?.Dispose ();
+                       gbPos?.Dispose ();
+                       hdrImgResolved?.Dispose ();
+
+
+                       hdrImgResolved = new Image (dev, HDR_FORMAT, VkImageUsageFlags.Sampled | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferSrc, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+                       gbColorRough = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+                       gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+                       gbN_AO = new Image (dev, MRT_FORMAT, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+                       gbPos = new Image (dev, MRT_FORMAT, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+
+
+                       gbColorRough.CreateView (); gbColorRough.CreateSampler ();
+                       gbColorRough.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+                       gbEmitMetal.CreateView (); gbEmitMetal.CreateSampler ();
+                       gbEmitMetal.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+                       gbN_AO.CreateView (); gbN_AO.CreateSampler ();
+                       gbN_AO.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+                       gbPos.CreateView (); gbPos.CreateSampler ();
+                       gbPos.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+                       hdrImgResolved.CreateView (); hdrImgResolved.CreateSampler ();
+                       hdrImgResolved.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+
+                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutGBuff);
+                       uboUpdate.Write (dev, dsGBuff,  gbColorRough.Descriptor,
+                                                                               gbEmitMetal.Descriptor,
+                                                                               gbN_AO.Descriptor,
+                                                                               gbPos.Descriptor);
+
+                       gbColorRough.SetName ("GBuffColorRough");
+                       gbEmitMetal.SetName ("GBuffEmitMetal");
+                       gbN_AO.SetName ("GBuffN");
+                       gbPos.SetName ("GBuffPos");
+                       hdrImgResolved.SetName ("HDRimg resolved");
+               }
+
+               public void Resize (uint width, uint height) {
+                       this.width = width;
+                       this.height = height;
+
+                       frameBuffer?.Dispose ();
+                       createGBuff ();
+
+                       frameBuffer = new FrameBuffer (renderPass, width, height, new Image[] {
+                                       hdrImgResolved, null, gbColorRough, gbEmitMetal, gbN_AO, gbPos});
+               }
+
+               public void Dispose () {
+                       dev.WaitIdle ();
+
+                       frameBuffer?.Dispose ();
+
+                       gbColorRough.Dispose ();
+                       gbEmitMetal.Dispose ();
+                       gbN_AO.Dispose ();
+                       gbPos.Dispose ();
+                       hdrImgResolved.Dispose ();
+
+                       gBuffPipeline.Dispose ();
+                       composePipeline.Dispose ();
+                       //toneMappingPipeline.Dispose ();
+                       debugPipeline?.Dispose ();
+
+                       descLayoutMain.Dispose ();
+                       descLayoutTextures?.Dispose ();
+                       descLayoutGBuff.Dispose ();
+
+                       uboMatrices.Dispose ();
+                       uboLights.Dispose ();
+                       model.Dispose ();
+                       envCube.Dispose ();
+
+#if WITH_SHADOWS
+                       shadowMapRenderer.Dispose ();
+#endif
+
+                       descriptorPool.Dispose ();
+
+                       dev.DestroySemaphore (DrawComplete);
+               }
+       }
+}
diff --git a/samples/glow/EnvironmentPipeline.cs b/samples/glow/EnvironmentPipeline.cs
new file mode 100644 (file)
index 0000000..32f8e6a
--- /dev/null
@@ -0,0 +1,317 @@
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using Vulkan;
+
+namespace vke {
+       public class EnvironmentCube : GraphicPipeline {
+
+               GPUBuffer vboSkybox;
+
+               public Image cubemap { get; private set; }
+               public Image lutBrdf { get; private set; }
+               public Image irradianceCube { get; private set; }
+               public Image prefilterCube { get; set; }
+
+               public EnvironmentCube (string cubemapPath, DescriptorSet dsSkybox, PipelineLayout plLayout, Queue staggingQ, RenderPass renderPass, PipelineCache cache = null)
+               : base (renderPass, cache, "EnvCube pipeline") {
+
+                       using (CommandPool cmdPool = new CommandPool (staggingQ.Dev, staggingQ.index)) {
+
+                               vboSkybox = new GPUBuffer<float> (staggingQ, cmdPool, VkBufferUsageFlags.VertexBuffer, box_vertices);
+
+                               cubemap = KTX.KTX.Load (staggingQ, cmdPool, cubemapPath,
+                                       VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, true);
+                               cubemap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color);
+                               cubemap.CreateSampler (VkSamplerAddressMode.ClampToEdge);
+                               cubemap.SetName ("skybox Texture");
+                               cubemap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+
+                               GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, renderPass.Samples, false);
+                               cfg.RenderPass = renderPass;
+                               cfg.Layout = plLayout;
+                               cfg.AddVertexBinding (0, 3 * sizeof (float));
+                               cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat);
+                               cfg.AddShader (VkShaderStageFlags.Vertex, "#deferred.skybox.vert.spv");
+                               cfg.AddShader (VkShaderStageFlags.Fragment, "#deferred.skybox.frag.spv");
+                               cfg.multisampleState.rasterizationSamples = Samples;
+
+                               layout = cfg.Layout;
+
+                               init (cfg);
+
+                               generateBRDFLUT (staggingQ, cmdPool);
+                               generateCubemaps (staggingQ, cmdPool);
+                       }
+
+               }
+
+               public void RecordDraw (CommandBuffer cmd) {
+                       Bind (cmd);
+                       cmd.BindVertexBuffer (vboSkybox);
+                       cmd.Draw (36);
+               }
+
+               #region skybox
+
+               static float[] box_vertices = {
+                        1.0f, 1.0f,-1.0f,  // +X side
+                        1.0f, 1.0f, 1.0f,
+                        1.0f,-1.0f, 1.0f,
+                        1.0f,-1.0f, 1.0f,
+                        1.0f,-1.0f,-1.0f,
+                        1.0f, 1.0f,-1.0f,
+
+                       -1.0f,-1.0f,-1.0f,      // +X side
+                       -1.0f,-1.0f, 1.0f,
+                       -1.0f, 1.0f, 1.0f,
+                       -1.0f, 1.0f, 1.0f,
+                       -1.0f, 1.0f,-1.0f,
+                       -1.0f,-1.0f,-1.0f,
+
+                       -1.0f, 1.0f,-1.0f,  // +Y side
+                       -1.0f, 1.0f, 1.0f,
+                        1.0f, 1.0f, 1.0f,
+                       -1.0f, 1.0f,-1.0f,
+                        1.0f, 1.0f, 1.0f,
+                        1.0f, 1.0f,-1.0f,
+
+                       -1.0f,-1.0f,-1.0f,  // -Y side
+                        1.0f,-1.0f,-1.0f,
+                        1.0f,-1.0f, 1.0f,
+                       -1.0f,-1.0f,-1.0f,
+                        1.0f,-1.0f, 1.0f,
+                       -1.0f,-1.0f, 1.0f,
+
+                       -1.0f, 1.0f, 1.0f,  // +Z side
+                       -1.0f,-1.0f, 1.0f,
+                        1.0f, 1.0f, 1.0f,
+                       -1.0f,-1.0f, 1.0f,
+                        1.0f,-1.0f, 1.0f,
+                        1.0f, 1.0f, 1.0f,
+
+                       -1.0f,-1.0f,-1.0f,  // -Z side
+                        1.0f, 1.0f,-1.0f,
+                        1.0f,-1.0f,-1.0f,
+                       -1.0f,-1.0f,-1.0f,
+                       -1.0f, 1.0f,-1.0f,
+                        1.0f, 1.0f,-1.0f,
+
+               };
+               #endregion
+
+               void generateBRDFLUT (Queue staggingQ, CommandPool cmdPool) {
+                       const VkFormat format = VkFormat.R16g16Sfloat;
+                       const int dim = 512;
+
+                       lutBrdf = new Image (Dev, format, VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.Sampled,
+                               VkMemoryPropertyFlags.DeviceLocal, dim, dim);
+                       lutBrdf.SetName ("lutBrdf");
+
+                       lutBrdf.CreateView ();
+                       lutBrdf.CreateSampler (VkSamplerAddressMode.ClampToEdge);
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false);
+
+                       cfg.Layout = new PipelineLayout (Dev, new DescriptorSetLayout (Dev));
+                       cfg.RenderPass = new RenderPass (Dev);
+                       cfg.RenderPass.AddAttachment (format, VkImageLayout.ShaderReadOnlyOptimal);
+                       cfg.RenderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0, 0, 0) });
+                       cfg.RenderPass.AddSubpass (new SubPass (VkImageLayout.ColorAttachmentOptimal));
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "#deferred.genbrdflut.vert.spv");
+                       cfg.AddShader (VkShaderStageFlags.Fragment, "#deferred.genbrdflut.frag.spv");
+
+                       using (GraphicPipeline pl = new GraphicPipeline (cfg)) {
+                               using (FrameBuffer fb = new FrameBuffer (cfg.RenderPass, dim, dim, lutBrdf)) {
+                                       CommandBuffer cmd = cmdPool.AllocateCommandBuffer ();
+                                       cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit);
+                                       pl.RenderPass.Begin (cmd, fb);
+                                       cmd.SetViewport (dim, dim);
+                                       cmd.SetScissor (dim, dim);
+                                       pl.Bind (cmd);
+                                       cmd.Draw (3, 1, 0, 0);
+                                       pl.RenderPass.End (cmd);
+                                       cmd.End ();
+
+                                       staggingQ.Submit (cmd);
+                                       staggingQ.WaitIdle ();
+
+                                       cmd.Free ();
+                               }
+                       }
+                       lutBrdf.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+               }
+
+               public enum CBTarget { IRRADIANCE = 0, PREFILTEREDENV = 1 };
+
+               public Image generateCubeMap (Queue staggingQ, CommandPool cmdPool, CBTarget target) {
+                       const float deltaPhi = (2.0f * (float)Math.PI) / 180.0f;
+                       const float deltaTheta = (0.5f * (float)Math.PI) / 64.0f;
+
+                       VkFormat format = VkFormat.R32g32b32a32Sfloat;
+                       uint dim = 64;
+
+                       if (target == CBTarget.PREFILTEREDENV) {
+                               format = VkFormat.R16g16b16a16Sfloat;
+                               dim = 512;
+                       }
+
+                       uint numMips = (uint)Math.Floor (Math.Log (dim, 2)) + 1;
+
+                       Image imgFbOffscreen = new Image (Dev, format, VkImageUsageFlags.TransferSrc | VkImageUsageFlags.ColorAttachment,
+                               VkMemoryPropertyFlags.DeviceLocal, dim, dim);
+                       imgFbOffscreen.SetName ("offscreenfb");
+                       imgFbOffscreen.CreateView ();
+
+                       Image cmap = new Image (Dev, format, VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled,
+                               VkMemoryPropertyFlags.DeviceLocal, dim, dim, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal,
+                               numMips, 6, 1, VkImageCreateFlags.CubeCompatible);
+                       if (target == CBTarget.PREFILTEREDENV)
+                               cmap.SetName ("prefilterenvmap");
+                       else
+                               cmap.SetName ("irradianceCube");
+                       cmap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color, 6, 0);
+                       cmap.CreateSampler (VkSamplerAddressMode.ClampToEdge);
+
+                       DescriptorPool dsPool = new DescriptorPool (Dev, 2, new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler));
+
+                       DescriptorSetLayout dsLayout = new DescriptorSetLayout (Dev,
+                               new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));
+
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false);
+                       cfg.Layout = new PipelineLayout (Dev, dsLayout);
+                       cfg.Layout.AddPushConstants (
+                               new VkPushConstantRange (VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf<Matrix4x4> () + 8));
+
+                       cfg.RenderPass = new RenderPass (Dev);
+                       cfg.RenderPass.AddAttachment (format, VkImageLayout.ColorAttachmentOptimal);
+                       cfg.RenderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0, 0, 0) });
+                       cfg.RenderPass.AddSubpass (new SubPass (VkImageLayout.ColorAttachmentOptimal));
+
+                       cfg.AddVertexBinding (0, 3 * sizeof (float));
+                       cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat);
+
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "#deferred.filtercube.vert.spv");
+                       if (target == CBTarget.PREFILTEREDENV)
+                               cfg.AddShader (VkShaderStageFlags.Fragment, "#deferred.prefilterenvmap.frag.spv");
+                       else
+                               cfg.AddShader (VkShaderStageFlags.Fragment, "#deferred.irradiancecube.frag.spv");
+
+                       Matrix4x4[] matrices = {
+                               // POSITIVE_X
+                               Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)) * Matrix4x4.CreateRotationY(Utils.DegreesToRadians(90)),
+                               // NEGATIVE_X
+                               Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)) * Matrix4x4.CreateRotationY(Utils.DegreesToRadians(-90)),
+                               // POSITIVE_Y
+                               Matrix4x4.CreateRotationX(Utils.DegreesToRadians(-90)),
+                               // NEGATIVE_Y
+                               Matrix4x4.CreateRotationX(Utils.DegreesToRadians(90)),
+                               // POSITIVE_Z
+                               Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)),
+                               // NEGATIVE_Z
+                               Matrix4x4.CreateRotationZ(Utils.DegreesToRadians(180))
+                       };
+
+                       VkImageSubresourceRange subRes = new VkImageSubresourceRange (VkImageAspectFlags.Color, 0, numMips, 0, 6);
+
+                       using (GraphicPipeline pl = new GraphicPipeline (cfg)) {
+
+                               DescriptorSet dset = dsPool.Allocate (dsLayout);
+                               DescriptorSetWrites dsUpdate = new DescriptorSetWrites (dsLayout);
+                               dsUpdate.Write (Dev, dset, cubemap.Descriptor);
+                               Dev.WaitIdle ();
+
+                               using (FrameBuffer fb = new FrameBuffer (pl.RenderPass, dim, dim, imgFbOffscreen)) {
+                                       CommandBuffer cmd = cmdPool.AllocateCommandBuffer ();
+                                       cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit);
+
+                                       cmap.SetLayout (cmd, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, subRes);
+
+                                       float roughness = 0;
+
+                                       cmd.SetScissor (dim, dim);
+                                       cmd.SetViewport ((float)(dim), (float)dim);
+
+                                       for (int m = 0; m < numMips; m++) {
+                                               roughness = (float)m / ((float)numMips - 1f);
+
+                                               for (int f = 0; f < 6; f++) {
+                                                       pl.RenderPass.Begin (cmd, fb);
+
+                                                       pl.Bind (cmd);
+
+                                                       float viewPortSize = (float)Math.Pow (0.5, m) * dim;
+                                                       cmd.SetViewport (viewPortSize, viewPortSize);
+                                                       cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment,
+                                                               matrices[f] * Matrix4x4.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (90), 1f, 0.1f, 512f));
+                                                       if (target == CBTarget.IRRADIANCE) {
+                                                               cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaPhi, (uint)Marshal.SizeOf<Matrix4x4> ());
+                                                               cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaTheta, (uint)Marshal.SizeOf<Matrix4x4> () + 4);
+                                                       } else {
+                                                               cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, roughness, (uint)Marshal.SizeOf<Matrix4x4> ());
+                                                               cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, 64u, (uint)Marshal.SizeOf<Matrix4x4> () + 4);
+                                                       }
+
+                                                       cmd.BindDescriptorSet (pl.Layout, dset);
+                                                       cmd.BindVertexBuffer (vboSkybox);
+                                                       cmd.Draw (36);
+
+                                                       pl.RenderPass.End (cmd);
+
+                                                       imgFbOffscreen.SetLayout (cmd, VkImageAspectFlags.Color,
+                                                               VkImageLayout.ColorAttachmentOptimal, VkImageLayout.TransferSrcOptimal);
+
+                                                       VkImageCopy region = new VkImageCopy ();
+                                                       region.srcSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1);
+                                                       region.dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1, (uint)m, (uint)f);
+                                                       region.extent = new VkExtent3D { width = (uint)viewPortSize, height = (uint)viewPortSize, depth = 1 };
+
+                                                       Vk.vkCmdCopyImage (cmd.Handle,
+                                                               imgFbOffscreen.Handle, VkImageLayout.TransferSrcOptimal,
+                                                               cmap.Handle, VkImageLayout.TransferDstOptimal,
+                                                               1, region.Pin ());
+                                                       region.Unpin ();
+
+                                                       imgFbOffscreen.SetLayout (cmd, VkImageAspectFlags.Color,
+                                                               VkImageLayout.TransferSrcOptimal, VkImageLayout.ColorAttachmentOptimal);
+
+                                               }
+                                       }
+
+                                       cmap.SetLayout (cmd, VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal, subRes);
+
+                                       cmd.End ();
+
+                                       staggingQ.Submit (cmd);
+                                       staggingQ.WaitIdle ();
+
+                                       cmd.Free ();
+                               }
+                       }
+                       cmap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+
+                       dsLayout.Dispose ();
+                       imgFbOffscreen.Dispose ();
+                       dsPool.Dispose ();
+
+                       return cmap;
+               }
+
+               void generateCubemaps (Queue staggingQ, CommandPool cmdPool) {
+                       irradianceCube = generateCubeMap (staggingQ, cmdPool, CBTarget.IRRADIANCE);
+                       prefilterCube = generateCubeMap (staggingQ, cmdPool, CBTarget.PREFILTEREDENV);
+               }
+
+               protected override void Dispose (bool disposing) {
+                       vboSkybox.Dispose ();
+                       cubemap.Dispose ();
+                       lutBrdf.Dispose ();
+                       irradianceCube.Dispose ();
+                       prefilterCube.Dispose ();
+
+                       base.Dispose (disposing);
+               }
+       }
+
+}
diff --git a/samples/glow/glow.csproj b/samples/glow/glow.csproj
new file mode 100644 (file)
index 0000000..2ba698f
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+       <PropertyGroup>
+               <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
+               <!--    <EnableDefaultNoneItems>false</EnableDefaultNoneItems>     -->
+       </PropertyGroup>
+       <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+               <DefineConstants>TRACE;NETSTANDARD;NETSTANDARD2_0;MEMORY_POOLS;WITH_SHADOWS;_WITH_VKVG;DEBUG;NETFRAMEWORK;NET472</DefineConstants>
+       </PropertyGroup>
+       <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugCrow|AnyCPU' ">
+               <DefineConstants>TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;MEMORY_POOLS;WITH_SHADOWS;_WITH_VKVG</DefineConstants>
+       </PropertyGroup>
+       <ItemGroup>
+               <Compile Include="DeferredPbrRenderer.cs;shadowMapRenderer.cs" />
+       </ItemGroup>
+       <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugCrow|AnyCPU' ">
+               <Compile Include="main-crow.cs" />
+       </ItemGroup>
+       <ItemGroup Condition="$(Configuration) != 'DebugCrow' ">
+               <Compile Include="main.cs" />
+       </ItemGroup>
+       <ItemGroup>
+               <ProjectReference Include="..\..\addons\gltfLoader\gltfLoader.csproj" />
+               <ProjectReference Include="..\..\addons\EnvironmentPipeline\EnvironmentPipeline.csproj" />
+       </ItemGroup>
+</Project>
diff --git a/samples/glow/main-crow.cs b/samples/glow/main-crow.cs
new file mode 100644 (file)
index 0000000..90c3243
--- /dev/null
@@ -0,0 +1,405 @@
+using System;
+using System.Numerics;
+using Glfw;
+using Vulkan;
+using vke;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace glow {
+       class Program : Crow.CrowWin {
+               static void Main (string[] args) {
+#if DEBUG
+                       Instance.VALIDATION = true;
+                       Instance.DEBUG_UTILS = true;
+                       Instance.RENDER_DOC_CAPTURE = false;
+#endif
+                       DeferredPbrRenderer.TEXTURE_ARRAY = true;
+                       DeferredPbrRenderer.NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
+                       DeferredPbrRenderer.HDR_FORMAT = VkFormat.R32g32b32a32Sfloat;
+                       DeferredPbrRenderer.MRT_FORMAT = VkFormat.R16g16b16a16Sfloat;
+
+                       PbrModelTexArray.TEXTURE_DIM = 1024;
+
+                       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 };
+                       CMDViewEditor = new Crow.Command (new Action (() => loadWindow ("#deferred.scenes.crow", this))) { Caption = "Scenes", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true };
+                       CMDViewDebug = new Crow.Command (new Action (() => loadWindow ("#deferred.debug.crow", this))) { Caption = "Debug", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true };
+                       CMDViewMaterials = new Crow.Command (new Action (() => loadWindow ("#deferred.materials.crow", this))) { Caption = "Materials", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true };
+               }
+
+               public DeferredPbrRenderer.DebugView CurrentDebugView {
+                       get { return renderer.currentDebugView; }
+                       set {
+                               if (value == renderer.currentDebugView)
+                                       return;
+                               lock(crow.UpdateMutex)
+                                       renderer.currentDebugView = value;
+                               rebuildBuffers = true;
+                               NotifyValueChanged ("CurrentDebugView", renderer.currentDebugView);
+                       }
+               }
+
+               public float Gamma {
+                       get { return renderer.matrices.gamma; }
+                       set {
+                               if (value == renderer.matrices.gamma)
+                                       return;
+                               renderer.matrices.gamma = value;
+                               NotifyValueChanged ("Gamma", value);
+                               updateViewRequested = true;
+                       }
+               }
+               public float Exposure {
+                       get { return renderer.matrices.exposure; }
+                       set {
+                               if (value == renderer.matrices.exposure)
+                                       return;
+                               renderer.matrices.exposure = value;
+                               NotifyValueChanged ("Exposure", value);
+                               updateViewRequested = true;
+                       }
+               }
+               public float LightStrength {
+                       get { return renderer.lights[renderer.lightNumDebug].color.X; }
+                       set {
+                               if (value == renderer.lights[renderer.lightNumDebug].color.X)
+                                       return;
+                               renderer.lights[renderer.lightNumDebug].color = new Vector4(value);
+                               NotifyValueChanged ("LightStrength", value);
+                               renderer.uboLights.Update (renderer.lights);
+                       }
+               }
+               public List<DeferredPbrRenderer.Light> Lights => renderer.lights.ToList ();
+               public List<Model.Scene> Scenes => renderer.model.Scenes;
+               #endregion
+
+               public override string[] EnabledDeviceExtensions => new string[] {
+                       Ext.D.VK_KHR_swapchain,
+                       Ext.D.VK_EXT_debug_marker
+               };
+
+               protected override void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures features) {
+                       base.configureEnabledFeatures (available_features, ref features);
+
+                       features.samplerAnisotropy = available_features.samplerAnisotropy;
+                       features.sampleRateShading = available_features.sampleRateShading;
+                       features.geometryShader = available_features.geometryShader;
+                       features.pipelineStatisticsQuery = true;
+
+                       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 () {
+                       base.createQueues ();
+                       transferQ = new Queue (dev, VkQueueFlags.Transfer);
+               }
+
+               string[] cubemapPathes = {
+                       Utils.DataDirectory + "textures/papermill.ktx",
+                       Utils.DataDirectory + "textures/cubemap_yokohama_bc3_unorm.ktx",
+                       Utils.DataDirectory + "textures/gcanyon_cube.ktx",
+                       Utils.DataDirectory + "textures/pisa_cube.ktx",
+                       Utils.DataDirectory + "textures/uffizi_cube.ktx",
+               };
+               string[] modelPathes = {
+                               //"/mnt/devel/gts/vkChess.net/data/models/chess.glb",
+                               //"/home/jp/gltf/jaguar/scene.gltf",
+                               Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf",
+                               Utils.DataDirectory + "models/shadow.glb",
+                               Utils.DataDirectory + "models/Hubble.glb",
+                               Utils.DataDirectory + "models/MER_static.glb",
+                               Utils.DataDirectory + "models/ISS_stationary.glb",
+                       };
+
+               int curModelIndex = 0;
+               bool reloadModel;
+
+               Queue transferQ;
+               DeferredPbrRenderer renderer;
+               PipelineStatisticsQueryPool statPool;
+               TimestampQueryPool timestampQPool;
+               ulong[] results;
+
+               DebugReport dbgRepport;
+
+               protected override void initVulkan () {
+                       base.initVulkan ();
+
+#if DEBUG
+                       dbgRepport = new DebugReport (instance,
+                                       VkDebugReportFlagsEXT.ErrorEXT
+                                       | VkDebugReportFlagsEXT.DebugEXT
+                                       | VkDebugReportFlagsEXT.WarningEXT
+                                       | VkDebugReportFlagsEXT.PerformanceWarningEXT
+                               );
+#endif
+
+                       camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f);
+                       camera.SetPosition (0, 0, 2);
+
+                       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));
+
+                       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;
+
+               }
+
+               protected override void recordDraw (PrimaryCommandBuffer cmd, int imageIndex) {
+                       statPool.Begin (cmd);
+                       renderer.buildCommandBuffers (cmd, imageIndex);
+                       statPool.End (cmd);
+               }
+
+               public override void UpdateView () {
+                       renderer.UpdateView (camera);
+                       updateViewRequested = false;
+#if WITH_SHADOWS
+                       if (renderer.shadowMapRenderer.updateShadowMap)
+                               renderer.shadowMapRenderer.update_shadow_map (cmdPool);
+#endif
+               }
+
+               int frameCount = 0;
+               public override void Update () {
+                       if (reloadModel) {
+                               renderer.LoadModel (transferQ, modelPathes[curModelIndex]);
+                               reloadModel = false;
+                               camera.Model = Matrix4x4.CreateScale (1f / Math.Max (Math.Max (renderer.modelAABB.Width, renderer.modelAABB.Height), renderer.modelAABB.Depth));
+                               updateViewRequested = true;
+                               rebuildBuffers = true;
+#if WITH_SHADOWS
+                               renderer.shadowMapRenderer.updateShadowMap = true;
+#endif
+                       }
+
+                       base.Update ();
+
+                       if (++frameCount > 20) {
+                               NotifyValueChanged ("fps", fps);
+                               frameCount = 0;
+                       }
+
+                       results = statPool.GetResults ();
+               }
+               protected override void OnResize () {           
+                       renderer.Resize ();
+                       base.OnResize ();
+               }
+
+               #region Mouse and keyboard
+               protected override void onMouseMove (double xPos, double yPos) {
+                       if (crow.ProcessMouseMove ((int)xPos, (int)yPos))
+                               return;
+
+                       double diffX = lastMouseX - xPos;
+                       double diffY = lastMouseY - yPos;
+                       if (MouseButton[0]) {
+                               camera.Rotate ((float)-diffX, (float)-diffY);
+                       } else if (MouseButton[1]) {
+                               camera.SetZoom ((float)diffY);
+                       } else
+                               return;
+
+                       updateViewRequested = true;
+               }
+               protected override void onMouseButtonDown (Glfw.MouseButton button) {
+                       if (crow.ProcessMouseButtonDown ((Crow.MouseButton)button))
+                               return;
+                       base.onMouseButtonDown (button);
+               }
+               protected override void onMouseButtonUp (Glfw.MouseButton button) {
+                       if (crow.ProcessMouseButtonUp ((Crow.MouseButton)button))
+                               return;
+                       base.onMouseButtonUp (button);
+               }
+               protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
+                       if (crow.ProcessKeyDown ((Crow.Key)key))
+                               return;
+                       switch (key) {
+                               case Key.F:
+                                       if (modifiers.HasFlag (Modifier.Shift)) {
+                                               renderer.debugFace--;
+                                               if (renderer.debugFace < 0)
+                                                       renderer.debugFace = 5;
+                                       } else {
+                                               renderer.debugFace++;
+                                               if (renderer.debugFace >= 5)
+                                                       renderer.debugFace = 0;
+                                       }
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.M:
+                                       if (modifiers.HasFlag (Modifier.Shift)) {
+                                               renderer.debugMip--;
+                                               if (renderer.debugMip < 0)
+                                                       renderer.debugMip = (int)renderer.envCube.prefilterCube.CreateInfo.mipLevels - 1;
+                                       } else {
+                                               renderer.debugMip++;
+                                               if (renderer.debugMip >= renderer.envCube.prefilterCube.CreateInfo.mipLevels)
+                                                       renderer.debugMip = 0;
+                                       }
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.L:
+                                       if (modifiers.HasFlag (Modifier.Shift)) {
+                                               renderer.lightNumDebug--;
+                                               if (renderer.lightNumDebug < 0)
+                                                       renderer.lightNumDebug = (int)renderer.lights.Length - 1;
+                                       } else {
+                                               renderer.lightNumDebug++;
+                                               if (renderer.lightNumDebug >= renderer.lights.Length)
+                                                       renderer.lightNumDebug = 0;
+                                       }
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.Keypad0:
+                               case Key.Keypad1:
+                               case Key.Keypad2:
+                               case Key.Keypad3:
+                               case Key.Keypad4:
+                               case Key.Keypad5:
+                               case Key.Keypad6:
+                               case Key.Keypad7:
+                               case Key.Keypad8:
+                               case Key.Keypad9:
+                                       renderer.currentDebugView = (DeferredPbrRenderer.DebugView)(int)key-320;
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.KeypadDivide:
+                                       renderer.currentDebugView = DeferredPbrRenderer.DebugView.irradiance;
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.S:
+                                       if (modifiers.HasFlag (Modifier.Control)) {
+                                               renderer.pipelineCache.Save ();
+                                               Console.WriteLine ($"Pipeline Cache saved.");
+                                       } else {
+                                               renderer.currentDebugView = DeferredPbrRenderer.DebugView.shadowMap;
+                                               rebuildBuffers = true; 
+                                       }
+                                       break;
+                               case Key.Up:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight(-Vector4.UnitZ);
+                                       else
+                                               camera.Move (0, 0, 1);
+                                       break;
+                               case Key.Down:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (Vector4.UnitZ);
+                                       else
+                                               camera.Move (0, 0, -1);
+                                       break;
+                               case Key.Left:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (-Vector4.UnitX);
+                                       else
+                                               camera.Move (1, 0, 0);
+                                       break;
+                               case Key.Right:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (Vector4.UnitX);
+                                       else
+                                               camera.Move (-1, 0, 0);
+                                       break;
+                               case Key.PageUp:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (Vector4.UnitY);
+                                       else
+                                               camera.Move (0, 1, 0);
+                                       break;
+                               case Key.PageDown:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (-Vector4.UnitY);
+                                       else
+                                               camera.Move (0, -1, 0);
+                                       break;
+                               case Key.F2:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.matrices.exposure -= 0.3f;
+                                       else
+                                               renderer.matrices.exposure += 0.3f;
+                                       break;
+                               case Key.F3:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.matrices.gamma -= 0.1f;
+                                       else
+                                               renderer.matrices.gamma += 0.1f;
+                                       break;
+                               case Key.F4:
+                                       if (camera.Type == Camera.CamType.FirstPerson)
+                                               camera.Type = Camera.CamType.LookAt;
+                                       else
+                                               camera.Type = Camera.CamType.FirstPerson;
+                                       Console.WriteLine ($"camera type = {camera.Type}");
+                                       break;
+                               case Key.KeypadAdd:
+                                       curModelIndex++;
+                                       if (curModelIndex >= modelPathes.Length)
+                                               curModelIndex = 0;
+                                       reloadModel = true;
+                                       break;
+                               case Key.KeypadSubtract:
+                                       curModelIndex--;
+                                       if (curModelIndex < 0)
+                                               curModelIndex = modelPathes.Length -1;
+                                       reloadModel = true;
+                                       break;
+                               default:
+                                       base.onKeyDown (key, scanCode, modifiers);
+                                       return;
+                       }
+                       updateViewRequested = true;
+               }
+               protected override void onKeyUp (Key key, int scanCode, Modifier modifiers) {
+                       if (crow.ProcessKeyUp ((Crow.Key)key))
+                               return;
+               }
+               protected override void onChar (CodePoint cp) {
+                       if (crow.ProcessKeyPress (cp.ToChar ()))
+                               return;
+               }
+               #endregion
+
+               protected override void Dispose (bool disposing) {
+                       if (disposing) {
+                               if (!isDisposed) {
+                                       renderer.Dispose ();
+                                       statPool.Dispose ();
+                                       timestampQPool.Dispose ();
+                                       dbgRepport?.Dispose ();
+                               }
+                       }
+
+                       base.Dispose (disposing);
+               }
+       }
+}
diff --git a/samples/glow/main.cs b/samples/glow/main.cs
new file mode 100644 (file)
index 0000000..570067b
--- /dev/null
@@ -0,0 +1,381 @@
+// Copyright (c) 2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using vke;
+using vke.glTF;
+using Glfw;
+using Vulkan;
+
+namespace glow {
+       /// <summary>
+       /// Deferred PBR rendering.
+       /// </summary>
+       class Glow : VkWindow {
+               static void Main (string[] args) {
+#if DEBUG
+                       Instance.VALIDATION = true;
+                       //Instance.RENDER_DOC_CAPTURE = true;
+#endif
+                       SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb;
+                       DeferredPbrRenderer.TEXTURE_ARRAY = true;
+                       DeferredPbrRenderer.NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
+                       DeferredPbrRenderer.HDR_FORMAT = VkFormat.R32g32b32a32Sfloat;
+                       DeferredPbrRenderer.MRT_FORMAT = VkFormat.R32g32b32a32Sfloat;
+
+                       PbrModelTexArray.TEXTURE_DIM = 1024;
+
+                       using (Glow vke = new Glow ()) {
+                               vke.Run ();
+                       }
+               }
+
+               public override string[] EnabledInstanceExtensions => new string[] {
+                       Ext.I.VK_EXT_debug_utils,
+               };
+
+               public override string[] EnabledDeviceExtensions => new string[] {
+                       Ext.D.VK_KHR_swapchain,
+               };
+
+               protected override void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures enabled_features) {
+                       base.configureEnabledFeatures (available_features, ref enabled_features);
+
+                       enabled_features.samplerAnisotropy = available_features.samplerAnisotropy;
+                       enabled_features.sampleRateShading = available_features.sampleRateShading;
+                       enabled_features.geometryShader = available_features.geometryShader;
+
+                       enabled_features.textureCompressionBC = available_features.textureCompressionBC;
+               }
+
+               protected override void createQueues () {
+                       base.createQueues ();
+                       transferQ = new Queue (dev, VkQueueFlags.Transfer);
+                       computeQ = new Queue (dev, VkQueueFlags.Compute);
+               }
+               string[] cubemapPathes = {
+                       Utils.DataDirectory + "textures/papermill.ktx",
+                       Utils.DataDirectory + "textures/cubemap_yokohama_bc3_unorm.ktx",
+                       Utils.DataDirectory + "textures/gcanyon_cube.ktx",
+                       Utils.DataDirectory + "textures/pisa_cube.ktx",
+                       Utils.DataDirectory + "textures/uffizi_cube.ktx",
+               };
+               string[] modelPathes = {
+                               "/mnt/devel/vkPinball/data/models/pinball.gltf",
+                               "/mnt/devel/pinball.net/data/test.glb",
+                               Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf",
+                               //Utils.DataDirectory + "models/shadow.glb",
+                               Utils.DataDirectory + "models/Hubble.glb",
+                               Utils.DataDirectory + "models/MER_static.glb",
+                               Utils.DataDirectory + "models/ISS_stationary.glb",
+                       };
+
+               int curModelIndex = 1;
+               bool reloadModel;
+               bool rebuildBuffers;
+
+               Queue transferQ, computeQ;
+               DeferredPbrRenderer renderer;
+
+
+               GraphicPipeline plToneMap;
+               FrameBuffers frameBuffers;
+               DescriptorPool descriptorPool;
+               DescriptorSet descriptorSet;
+
+               vke.DebugUtils.Messenger dbgmsg;
+
+               protected override void initVulkan () {
+                       base.initVulkan ();
+
+#if DEBUG
+                       dbgmsg = new vke.DebugUtils.Messenger (instance, VkDebugUtilsMessageTypeFlagsEXT.PerformanceEXT | VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT | VkDebugUtilsMessageTypeFlagsEXT.GeneralEXT,
+                               VkDebugUtilsMessageSeverityFlagsEXT.InfoEXT |
+                               VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT |
+                               VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT |
+                               VkDebugUtilsMessageSeverityFlagsEXT.VerboseEXT);
+#endif
+
+                       camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f);
+                       camera.SetPosition (0, 0, -2);
+
+                       //renderer = new DeferredPbrRenderer (presentQueue, cubemapPathes[2], swapChain.Width, swapChain.Height, camera.NearPlane, camera.FarPlane);
+                       renderer = new DeferredPbrRenderer (presentQueue, cubemapPathes[2], swapChain.Width, swapChain.Height, 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));
+
+                       init_final_pl ();
+               }
+
+               void init_final_pl() {
+                       descriptorPool = new DescriptorPool (dev, 3,
+                               new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 2),
+                               new VkDescriptorPoolSize (VkDescriptorType.StorageImage, 4)
+                       );
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, DeferredPbrRenderer.NUM_SAMPLES);
+                       if (DeferredPbrRenderer.NUM_SAMPLES != VkSampleCountFlags.SampleCount1) {
+                               cfg.multisampleState.sampleShadingEnable = true;
+                               cfg.multisampleState.minSampleShading = 0.5f;
+                       }
+                       cfg.Layout = new PipelineLayout (dev,
+                               new VkPushConstantRange (VkShaderStageFlags.Fragment, 2 * sizeof (float)),
+                               new DescriptorSetLayout (dev, 0,
+                                       new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)
+                                       ));
+
+                       cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, DeferredPbrRenderer.NUM_SAMPLES);
+
+                       using (ShaderInfo vs = new ShaderInfo (dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv"))
+                       using (ShaderInfo fs = new ShaderInfo (dev, VkShaderStageFlags.Fragment, "#shaders.tone_mapping.frag.spv"))
+                       {
+                               cfg.AddShaders (vs, fs);
+
+                               plToneMap = new GraphicPipeline (cfg);
+                       }
+
+                       descriptorSet = descriptorPool.Allocate (cfg.Layout.DescriptorSetLayouts[0]);
+               }
+
+               void buildCommandBuffers () {
+                       for (int i = 0; i < swapChain.ImageCount; ++i) {
+                               cmds[i]?.Free ();
+                               cmds[i] = cmdPool.AllocateAndStart ();
+
+                               renderer.buildCommandBuffers (cmds[i]);
+
+                               plToneMap.RenderPass.Begin (cmds[i], frameBuffers[i]);
+
+                               cmds[i].SetViewport (frameBuffers[i].Width, frameBuffers[i].Height);
+                               cmds[i].SetScissor (frameBuffers[i].Width, frameBuffers[i].Height);
+
+                               plToneMap.Bind (cmds[i]);
+                               plToneMap.BindDescriptorSet (cmds[i], descriptorSet);
+
+                               cmds[i].PushConstant (plToneMap.Layout, VkShaderStageFlags.Fragment, 8, new float[] { renderer.exposure, renderer.gamma }, 0);
+
+                               cmds[i].Draw (3, 1, 0, 0);
+
+                               plToneMap.RenderPass.End (cmds[i]);
+
+                               cmds[i].End ();
+                       }
+               }
+
+               public override void UpdateView () {
+                       dev.WaitIdle ();
+
+                       renderer.UpdateView (camera);
+                       updateViewRequested = false;
+#if WITH_SHADOWS
+                       if (renderer.shadowMapRenderer.updateShadowMap)
+                               renderer.shadowMapRenderer.update_shadow_map (cmdPool);
+#endif
+               }
+
+               public override void Update () {
+                       if (reloadModel) {
+                               renderer.LoadModel (transferQ, modelPathes[curModelIndex]);
+                               reloadModel = false;
+                               camera.Model = Matrix4x4.CreateScale (1f / Math.Max (Math.Max (renderer.modelAABB.Width, renderer.modelAABB.Height), renderer.modelAABB.Depth));
+                               updateViewRequested = true;
+                               rebuildBuffers = true;
+#if WITH_SHADOWS
+                               renderer.shadowMapRenderer.updateShadowMap = true;
+#endif
+                       }
+
+                       if (rebuildBuffers) {
+                               buildCommandBuffers ();
+                               rebuildBuffers = false;
+                       }
+
+               }
+
+               protected override void OnResize () {
+                       base.OnResize ();
+
+                       dev.WaitIdle ();
+
+                       renderer.Resize (Width, Height);
+
+                       UpdateView ();
+
+                       frameBuffers?.Dispose();
+                       frameBuffers = plToneMap.RenderPass.CreateFrameBuffers(swapChain);
+
+                       DescriptorSetWrites dsUpdate = new DescriptorSetWrites (plToneMap.Layout.DescriptorSetLayouts[0].Bindings[0]);
+                       dsUpdate.Write (dev, descriptorSet, renderer.hdrImgResolved.Descriptor);
+
+                       buildCommandBuffers ();
+
+                       dev.WaitIdle ();
+               }
+
+               #region Mouse and keyboard
+               protected override void onScroll (double xOffset, double yOffset) {
+               }
+               protected override void onMouseMove (double xPos, double yPos) {
+                       double diffX = lastMouseX - xPos;
+                       double diffY = lastMouseY - yPos;
+                       if (MouseButton[0]) {
+                               camera.Rotate ((float)-diffY, (float)-diffX, 0);
+                       } else if (MouseButton[1]) {
+                               camera.SetZoom ((float)diffY);
+                       } else
+                               return;
+
+                       updateViewRequested = true;
+               }
+               protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
+                       switch (key) {
+                               case Key.F:
+                                       if (modifiers.HasFlag (Modifier.Shift)) {
+                                               renderer.debugFace--;
+                                               if (renderer.debugFace < 0)
+                                                       renderer.debugFace = 5;
+                                       } else {
+                                               renderer.debugFace++;
+                                               if (renderer.debugFace >= 5)
+                                                       renderer.debugFace = 0;
+                                       }
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.M:
+                                       if (modifiers.HasFlag (Modifier.Shift)) {
+                                               renderer.debugMip--;
+                                               if (renderer.debugMip < 0)
+                                                       renderer.debugMip = (int)renderer.envCube.prefilterCube.CreateInfo.mipLevels - 1;
+                                       } else {
+                                               renderer.debugMip++;
+                                               if (renderer.debugMip >= renderer.envCube.prefilterCube.CreateInfo.mipLevels)
+                                                       renderer.debugMip = 0;
+                                       }
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.L:
+                                       if (modifiers.HasFlag (Modifier.Shift)) {
+                                               renderer.lightNumDebug--;
+                                               if (renderer.lightNumDebug < 0)
+                                                       renderer.lightNumDebug = (int)renderer.lights.Length - 1;
+                                       } else {
+                                               renderer.lightNumDebug++;
+                                               if (renderer.lightNumDebug >= renderer.lights.Length)
+                                                       renderer.lightNumDebug = 0;
+                                       }
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.Keypad0:
+                               case Key.Keypad1:
+                               case Key.Keypad2:
+                               case Key.Keypad3:
+                               case Key.Keypad4:
+                               case Key.Keypad5:
+                               case Key.Keypad6:
+                               case Key.Keypad7:
+                               case Key.Keypad8:
+                               case Key.Keypad9:
+                                       renderer.currentDebugView = (DeferredPbrRenderer.DebugView)(int)key-320;
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.KeypadDivide:
+                                       renderer.currentDebugView = DeferredPbrRenderer.DebugView.irradiance;
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.S:
+                                       if (modifiers.HasFlag (Modifier.Control)) {
+                                               renderer.pipelineCache.Save ();
+                                               Console.WriteLine ($"Pipeline Cache saved.");
+                                       } else {
+                                               renderer.currentDebugView = DeferredPbrRenderer.DebugView.shadowMap;
+                                               rebuildBuffers = true; 
+                                       }
+                                       break;
+                               case Key.Up:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight(-Vector4.UnitZ);
+                                       else
+                                               camera.Move (0, 0, 1);
+                                       break;
+                               case Key.Down:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (Vector4.UnitZ);
+                                       else
+                                               camera.Move (0, 0, -1);
+                                       break;
+                               case Key.Left:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (-Vector4.UnitX);
+                                       else
+                                               camera.Move (1, 0, 0);
+                                       break;
+                               case Key.Right:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (Vector4.UnitX);
+                                       else
+                                               camera.Move (-1, 0, 0);
+                                       break;
+                               case Key.PageUp:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (Vector4.UnitY);
+                                       else
+                                               camera.Move (0, 1, 0);
+                                       break;
+                               case Key.PageDown:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.MoveLight (-Vector4.UnitY);
+                                       else
+                                               camera.Move (0, -1, 0);
+                                       break;
+                               case Key.F2:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.exposure -= 0.3f;
+                                       else
+                                               renderer.exposure += 0.3f;
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.F3:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               renderer.gamma -= 0.1f;
+                                       else
+                                               renderer.gamma += 0.1f;
+                                       rebuildBuffers = true;
+                                       break;
+                               case Key.KeypadAdd:
+                                       curModelIndex++;
+                                       if (curModelIndex >= modelPathes.Length)
+                                               curModelIndex = 0;
+                                       reloadModel = true;
+                                       break;
+                               case Key.KeypadSubtract:
+                                       curModelIndex--;
+                                       if (curModelIndex < 0)
+                                               curModelIndex = modelPathes.Length -1;
+                                       reloadModel = true;
+                                       break;
+                               default:
+                                       base.onKeyDown (key, scanCode, modifiers);
+                                       return;
+                       }
+                       updateViewRequested = true;
+               }
+               #endregion
+
+               protected override void Dispose (bool disposing) {
+                       dev.WaitIdle ();
+                       if (disposing) {
+                               if (!isDisposed) {
+                                       frameBuffers?.Dispose();
+                                       renderer?.Dispose ();
+                                       plToneMap?.Dispose ();
+                                       descriptorPool?.Dispose ();
+                                       dbgmsg?.Dispose ();
+                               }
+                       }
+                       base.Dispose (disposing);
+               }
+       }
+}
diff --git a/samples/glow/mainShadow.cs b/samples/glow/mainShadow.cs
new file mode 100644 (file)
index 0000000..0bc3103
--- /dev/null
@@ -0,0 +1,415 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using Glfw;
+using VK;
+using CVKL;
+
+namespace deferredShadow {
+       class Program : VkWindow{       
+               static void Main (string[] args) {
+                       using (Program vke = new Program ()) {
+                               vke.Run ();
+                       }
+               }
+
+               VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;
+
+               public struct Matrices {
+                       public Matrix4x4 projection;
+                       public Matrix4x4 view;
+                       public Matrix4x4 model;
+                       public Vector4 lightPos;
+                       public float gamma;
+                       public float exposure;
+               }
+
+               public Matrices matrices = new Matrices {
+                       lightPos = new Vector4 (1.0f, 0.0f, 0.0f, 1.0f),
+                       gamma = 1.0f,
+                       exposure = 2.0f,
+               };
+
+               const uint SHADOW_MAP_SIZE = 4096;
+
+#if DEBUG
+               PipelineStatisticsQueryPool statPool;
+               TimestampQueryPool timestampQPool;
+               ulong[] results;
+#endif
+
+               protected override void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) {
+                       base.configureEnabledFeatures (ref features);
+#if DEBUG
+                       features.pipelineStatisticsQuery = true;
+#endif
+               }
+
+               Program () : base(true) {
+                       //camera.Model = Matrix4x4.CreateRotationX (Utils.DegreesToRadians (-90)) * Matrix4x4.CreateRotationY (Utils.DegreesToRadians (180));
+                       //camera.SetRotation (-0.1f,-0.4f);
+                       camera.SetPosition (0, 0, -3);
+
+                       init ();
+
+#if DEBUG
+                       statPool = new PipelineStatisticsQueryPool (dev,
+                               VkQueryPipelineStatisticFlags.InputAssemblyVertices |
+                               VkQueryPipelineStatisticFlags.InputAssemblyPrimitives |
+                               VkQueryPipelineStatisticFlags.ClippingInvocations |
+                               VkQueryPipelineStatisticFlags.ClippingPrimitives |
+                               VkQueryPipelineStatisticFlags.FragmentShaderInvocations);
+
+                       timestampQPool = new TimestampQueryPool (dev);
+#endif
+               }
+
+               Framebuffer[] frameBuffers;
+               Image gbColorRough, gbEmitMetal, gbN, gbPos;
+
+               DescriptorPool descriptorPool;
+               DescriptorSetLayout descLayoutMain, descLayoutModelTextures, descLayoutGBuff;
+               DescriptorSet dsMain, dsGBuff;
+
+               Pipeline gBuffPipeline, composePipeline;
+
+               HostBuffer uboMats;
+
+               RenderPass renderPass;
+
+               Model model;
+               EnvironmentCube envCube;
+
+               DebugDrawPipeline debugDraw;
+               Framebuffer[] debugFB;
+
+               void init () {
+                       VkFormat depthFormat = dev.GetSuitableDepthFormat ();
+                       renderPass = new RenderPass (dev);
+
+                       renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.ColorAttachmentOptimal, VkSampleCountFlags.SampleCount1);
+                       renderPass.AddAttachment (depthFormat, VkImageLayout.DepthStencilAttachmentOptimal, samples);
+                       renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal);
+                       renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal);
+                       renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.ColorAttachmentOptimal);
+                       renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.ColorAttachmentOptimal);
+                       //renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.DepthStencilReadOnlyOptimal);
+
+                       renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) });
+               renderPass.ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) });
+                       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) });
+                       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() };
+                       subpass[0].AddColorReference (  new VkAttachmentReference (2, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (3, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (4, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (5, VkImageLayout.ColorAttachmentOptimal));
+                       subpass[0].SetDepthReference (1, VkImageLayout.DepthStencilAttachmentOptimal);
+
+                       subpass[1].AddColorReference (0, VkImageLayout.ColorAttachmentOptimal);
+                       subpass[1].AddInputReference (  new VkAttachmentReference (2, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (3, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (4, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (5, VkImageLayout.ShaderReadOnlyOptimal));
+                       renderPass.AddSubpass (subpass);
+
+                       renderPass.AddDependency (Vk.SubpassExternal, 0,
+                VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput,
+                VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite);
+                       renderPass.AddDependency (0, 1,
+                VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader,
+                VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead);
+               renderPass.AddDependency (1, Vk.SubpassExternal,
+                VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe,
+                VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead);
+
+                        
+                       descriptorPool = new DescriptorPool (dev, 3,
+                               new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 2),
+                               new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 3),
+                               new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 4)
+                       );
+
+                       descLayoutMain = new DescriptorSetLayout (dev,
+                               new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer),
+                               new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),
+                               new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),
+                               new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));
+
+                       descLayoutModelTextures = 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),
+                               new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),
+                               new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),
+                               new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment));
+
+                       dsMain = descriptorPool.Allocate (descLayoutMain);
+                       dsGBuff = descriptorPool.Allocate (descLayoutGBuff);
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, samples);
+                       cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutModelTextures, descLayoutGBuff);
+                       cfg.Layout.AddPushConstants (
+                               new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()),
+                               new VkPushConstantRange (VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf<Model.PbrMaterial> (), 64)
+                       );
+                       cfg.RenderPass = renderPass;
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+
+                       cfg.AddVertexBinding<Model.Vertex> (0);
+                       cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat);
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/pbrtest.vert.spv");
+                       cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/GBuffPbr.frag.spv");
+
+                       gBuffPipeline = new GraphicPipeline (cfg);
+                       cfg.blendAttachments.Clear ();
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.ResetShadersAndVerticesInfos ();
+                       cfg.SubpassIndex = 1;
+                       cfg.Layout = gBuffPipeline.Layout;
+                       cfg.depthStencilState.depthTestEnable = false;
+                       cfg.depthStencilState.depthWriteEnable = false;
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/FullScreenQuad.vert.spv");
+                       cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/pbrtest.frag.spv");
+                       composePipeline = new GraphicPipeline (cfg);
+
+                       envCube = new EnvironmentCube (presentQueue, renderPass);
+
+                       uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, (ulong)Marshal.SizeOf<Matrices> () * 2);
+                       uboMats.Map ();//permanent map
+
+                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutMain);
+                       uboUpdate.Write (dev, dsMain, uboMats.Descriptor,
+                               envCube.lutBrdf.Descriptor,
+                               envCube.irradianceCube.Descriptor,
+                               envCube.prefilterCube.Descriptor);
+                       uboMats.Descriptor.offset = (ulong)Marshal.SizeOf<Matrices> ();
+                       envCube.WriteDesc (uboMats.Descriptor);
+#if DEBUG
+                       debugDraw = new DebugDrawPipeline (dev, descLayoutMain, swapChain.ColorFormat);
+                       debugDraw.AddLine (Vector3.Zero, new Vector3(matrices.lightPos.X,matrices.lightPos.Y,matrices.lightPos.Z)*3, 1, 1, 1);
+                       debugDraw.AddLine (Vector3.Zero, Vector3.UnitX, 1, 0, 0);
+                       debugDraw.AddLine (Vector3.Zero, Vector3.UnitY, 0, 1, 0);
+                       debugDraw.AddLine (Vector3.Zero, Vector3.UnitZ, 0, 0, 1);
+#endif
+
+
+                       model = new Model (presentQueue, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf");
+                       //model = new Model (presentQueue, "../data/models/chess.gltf");
+                       //model = new Model (presentQueue, "../data/models/Sponza/glTF/Sponza.gltf");
+                       //model = new Model (dev, presentQueue, "../data/models/icosphere.gltf");
+                       //model = new Model (dev, presentQueue, cmdPool, "../data/models/cube.gltf");
+                       model.WriteMaterialsDescriptorSets (descLayoutModelTextures,
+                               VK.AttachmentType.Color,
+                               VK.AttachmentType.Normal,
+                               VK.AttachmentType.AmbientOcclusion,
+                               VK.AttachmentType.PhysicalProps,
+                               VK.AttachmentType.Emissive);                            
+               }
+
+               void buildCommandBuffers () {
+                       for (int i = 0; i < swapChain.ImageCount; ++i) {
+                               cmds[i]?.Free ();
+                               cmds[i] = cmdPool.AllocateCommandBuffer ();
+                               cmds[i].Start ();
+
+#if DEBUG
+                               statPool.Begin (cmds[i]);
+                               recordDraw (cmds[i], frameBuffers[i]);
+                               statPool.End (cmds[i]);
+
+                               debugDraw.RecordDraw (cmds[i], debugFB[i], camera);
+#else
+                               recordDraw (cmds[i], frameBuffers[i]);
+#endif
+
+                               cmds[i].End ();
+                       }
+               }
+               void recordDraw (CommandBuffer cmd, Framebuffer fb) {
+                       renderPass.Begin (cmd, fb);
+
+                       cmd.SetViewport (fb.Width, fb.Height);
+                       cmd.SetScissor (fb.Width, fb.Height);
+
+                       cmd.BindDescriptorSet (gBuffPipeline.Layout, dsMain);
+                       gBuffPipeline.Bind (cmd);
+                       model.Bind (cmd);
+                       model.DrawAll (cmd, gBuffPipeline.Layout);
+
+                       renderPass.BeginSubPass (cmd);
+
+                       cmd.BindDescriptorSet (composePipeline.Layout, dsGBuff, 2);
+                       composePipeline.Bind (cmd);
+
+                       cmd.Draw (3, 1, 0, 0);
+
+                       renderPass.End (cmd);
+               }
+
+#region update
+               void updateMatrices () {
+                       camera.AspectRatio = (float)swapChain.Width / swapChain.Height;
+
+                       matrices.projection = camera.Projection;
+                       matrices.view = camera.View;
+                       matrices.model = camera.Model;
+                       uboMats.Update (matrices, (uint)Marshal.SizeOf<Matrices> ());
+                       matrices.view *= Matrix4x4.CreateTranslation (-matrices.view.Translation);
+                       matrices.model = Matrix4x4.Identity;
+                       uboMats.Update (matrices, (uint)Marshal.SizeOf<Matrices> (), (uint)Marshal.SizeOf<Matrices> ());
+               }
+
+               public override void UpdateView () {
+                       updateMatrices ();
+                       updateViewRequested = false;
+               }
+               public override void Update () {
+#if DEBUG
+                       results = statPool.GetResults ();
+#endif
+               }
+#endregion
+
+
+
+               void createGBuff () {
+                       gbColorRough?.Dispose ();
+                       gbEmitMetal?.Dispose ();
+                       gbN?.Dispose ();
+                       gbPos?.Dispose ();
+
+                       gbColorRough = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height);
+                       gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height);
+                       gbN = new Image (dev, VkFormat.R16g16b16a16Sfloat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height);
+                       gbPos = new Image (dev, VkFormat.R16g16b16a16Sfloat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height);
+
+                       gbColorRough.CreateView ();
+                       gbColorRough.CreateSampler ();
+                       gbEmitMetal.CreateView ();
+                       gbEmitMetal.CreateSampler ();
+                       gbN.CreateView ();
+                       gbN.CreateSampler ();
+                       gbPos.CreateView ();
+                       gbPos.CreateSampler ();
+
+                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutGBuff);
+                       uboUpdate.Write (dev, dsGBuff,  gbColorRough.Descriptor,
+                                                                               gbEmitMetal.Descriptor,
+                                                                               gbN.Descriptor,
+                                                                               gbPos.Descriptor);
+                       gbColorRough.SetName ("GBuffColorRough");
+                       gbEmitMetal.SetName ("GBuffEmitMetal");
+                       gbN.SetName ("GBuffN");
+                       gbPos.SetName ("GBuffPos");
+               }
+
+               protected override void OnResize () {
+                       updateMatrices ();
+
+                       if (frameBuffers != null)
+                               for (int i = 0; i < swapChain.ImageCount; ++i)
+                                       frameBuffers[i]?.Dispose ();
+#if DEBUG
+                       if (debugFB != null)
+                               for (int i = 0; i < swapChain.ImageCount; ++i)
+                                       debugFB[i]?.Dispose ();
+#endif
+
+                       createGBuff ();
+
+                       frameBuffers = new Framebuffer[swapChain.ImageCount];
+                       debugFB = new Framebuffer[swapChain.ImageCount];
+
+                       for (int i = 0; i < swapChain.ImageCount; ++i) {
+                               frameBuffers[i] = new Framebuffer (renderPass, swapChain.Width, swapChain.Height, new Image[] {
+                                       swapChain.images[i], null, gbColorRough, gbEmitMetal, gbN, gbPos});
+#if DEBUG
+                               debugFB[i] = new Framebuffer (debugDraw.RenderPass, swapChain.Width, swapChain.Height,(debugDraw.Samples == VkSampleCountFlags.SampleCount1)
+                                       ? new Image[] { swapChain.images[i] } : new Image[] { null, swapChain.images[i] });
+                               debugFB[i].SetName ("main FB " + i);
+#endif
+                       }
+
+                       buildCommandBuffers ();
+               }
+
+
+               #region Mouse and keyboard
+               protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
+                       switch (key) {
+                               case Key.F1:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               matrices.exposure -= 0.3f;
+                                       else
+                                               matrices.exposure += 0.3f;
+                                       break;
+                               case Key.F2:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               matrices.gamma -= 0.1f;
+                                       else
+                                               matrices.gamma += 0.1f;
+                                       break;
+                               case Key.F3:
+                                       if (camera.Type == Camera.CamType.FirstPerson)
+                                               camera.Type = Camera.CamType.LookAt;
+                                       else
+                                               camera.Type = Camera.CamType.FirstPerson;
+                                       Console.WriteLine ($"camera type = {camera.Type}");
+                                       break;
+                               default:
+                                       base.onKeyDown (key, scanCode, modifiers);
+                                       return;
+                       }
+                       updateViewRequested = true;
+               }
+#endregion
+
+               protected override void Dispose (bool disposing) {
+                       if (disposing) {
+                               if (!isDisposed) {
+                                       dev.WaitIdle ();
+                                       for (int i = 0; i < swapChain.ImageCount; ++i)
+                                               frameBuffers[i]?.Dispose ();
+
+                                       gbColorRough.Dispose ();
+                                       gbEmitMetal.Dispose ();
+                                       gbN.Dispose ();
+                                       gbPos.Dispose ();
+
+                                       gBuffPipeline.Dispose ();
+                                       composePipeline.Dispose ();
+
+                                       descLayoutMain.Dispose ();
+                                       descLayoutModelTextures.Dispose ();
+                                       descLayoutGBuff.Dispose ();
+
+                                       uboMats.Dispose ();
+                                       model.Dispose ();
+                                       envCube.Dispose ();
+
+                                       descriptorPool.Dispose ();
+#if DEBUG
+                                       debugDraw.Dispose ();
+                                       timestampQPool?.Dispose ();
+                                       statPool?.Dispose ();
+#endif
+                               }
+                       }
+
+                       base.Dispose (disposing);
+               }
+       }
+}
diff --git a/samples/glow/mainWithDebugDrawer.cs b/samples/glow/mainWithDebugDrawer.cs
new file mode 100644 (file)
index 0000000..f95ed0a
--- /dev/null
@@ -0,0 +1,412 @@
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using Glfw;
+using VK;
+using CVKL;
+
+namespace deferredDebug {
+       class Program : VkWindow{       
+               static void Main (string[] args) {
+                       using (Program vke = new Program ()) {
+                               vke.Run ();
+                       }
+               }
+
+               VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;
+
+               public struct Matrices {
+                       public Matrix4x4 projection;
+                       public Matrix4x4 view;
+                       public Matrix4x4 model;
+                       public Vector4 lightPos;
+                       public float gamma;
+                       public float exposure;
+               }
+
+               public Matrices matrices = new Matrices {
+                       lightPos = new Vector4 (1.0f, 0, 0, 1.0f),
+                       gamma = 1.0f,
+                       exposure = 2.0f,
+               };
+
+#if DEBUG
+               PipelineStatisticsQueryPool statPool;
+               TimestampQueryPool timestampQPool;
+               ulong[] results;
+#endif
+
+               protected override void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) {
+                       base.configureEnabledFeatures (ref features);
+#if DEBUG
+                       features.pipelineStatisticsQuery = true;
+#endif
+               }
+
+               Program () : base(true) {
+                       camera.Model = Matrix4x4.CreateRotationX (Utils.DegreesToRadians (-90)) * Matrix4x4.CreateRotationY (Utils.DegreesToRadians (180));
+                       camera.SetRotation (-0.1f,-0.4f);
+                       camera.SetPosition (0, 0, -3);
+
+                       init ();
+
+#if DEBUG
+                       statPool = new PipelineStatisticsQueryPool (dev,
+                               VkQueryPipelineStatisticFlags.InputAssemblyVertices |
+                               VkQueryPipelineStatisticFlags.InputAssemblyPrimitives |
+                               VkQueryPipelineStatisticFlags.ClippingInvocations |
+                               VkQueryPipelineStatisticFlags.ClippingPrimitives |
+                               VkQueryPipelineStatisticFlags.FragmentShaderInvocations);
+
+                       timestampQPool = new TimestampQueryPool (dev);
+#endif
+               }
+
+               Framebuffer[] frameBuffers;
+               Image gbColorRough, gbEmitMetal, gbN, gbPos;
+
+               DescriptorPool descriptorPool;
+               DescriptorSetLayout descLayoutMain, descLayoutModelTextures, descLayoutGBuff;
+               DescriptorSet dsMain, dsGBuff;
+
+               Pipeline gBuffPipeline, composePipeline;
+
+               HostBuffer uboMats;
+
+               RenderPass renderPass;
+
+               Model model;
+               EnvironmentCube envCube;
+
+               DebugDrawPipeline debugDraw;
+               Framebuffer[] debugFB;
+
+               void init () {
+                       renderPass = new RenderPass (dev);
+                       renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.ColorAttachmentOptimal, VkSampleCountFlags.SampleCount1);
+                       renderPass.AddAttachment (dev.GetSuitableDepthFormat(), VkImageLayout.DepthStencilAttachmentOptimal, samples);
+                       renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal);
+                       renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal);
+                       renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.ColorAttachmentOptimal);
+                       renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.ColorAttachmentOptimal);
+
+                       renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) });
+               renderPass.ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) });
+                       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) });
+                       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 () };
+                       subpass[0].AddColorReference (  new VkAttachmentReference (2, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (3, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (4, VkImageLayout.ColorAttachmentOptimal),
+                                                                       new VkAttachmentReference (5, VkImageLayout.ColorAttachmentOptimal));
+                       subpass[0].SetDepthReference (1, VkImageLayout.DepthStencilAttachmentOptimal);
+
+                       subpass[1].AddColorReference (0, VkImageLayout.ColorAttachmentOptimal);
+                       subpass[1].AddInputReference (  new VkAttachmentReference (2, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (3, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (4, VkImageLayout.ShaderReadOnlyOptimal),
+                                                                       new VkAttachmentReference (5, VkImageLayout.ShaderReadOnlyOptimal));
+                       renderPass.AddSubpass (subpass);
+
+                       renderPass.AddDependency (Vk.SubpassExternal, 0,
+                VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput,
+                VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite);
+                       renderPass.AddDependency (0, 1,
+                VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader,
+                VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead);
+               renderPass.AddDependency (1, Vk.SubpassExternal,
+                VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe,
+                VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead);
+
+                        
+                       descriptorPool = new DescriptorPool (dev, 3,
+                               new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 2),
+                               new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 3),
+                               new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 4)
+                       );
+
+                       descLayoutMain = new DescriptorSetLayout (dev,
+                               new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer),
+                               new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),
+                               new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),
+                               new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));
+
+                       descLayoutModelTextures = 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),
+                               new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),
+                               new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),
+                               new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment));
+
+                       dsMain = descriptorPool.Allocate (descLayoutMain);
+                       dsGBuff = descriptorPool.Allocate (descLayoutGBuff);
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, samples);
+                       cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutModelTextures, descLayoutGBuff);
+                       cfg.Layout.AddPushConstants (
+                               new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()),
+                               new VkPushConstantRange (VkShaderStageFlags.Fragment, sizeof(int), 64)
+                       );
+                       cfg.RenderPass = renderPass;
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+
+                       cfg.AddVertexBinding<Model.Vertex> (0);
+                       cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat);
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/pbrtest.vert.spv");
+                       cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/GBuffPbr.frag.spv");
+
+                       gBuffPipeline = new GraphicPipeline (cfg);
+                       cfg.blendAttachments.Clear ();
+                       cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+                       cfg.ResetShadersAndVerticesInfos ();
+                       cfg.SubpassIndex = 1;
+                       cfg.Layout = gBuffPipeline.Layout;
+                       cfg.depthStencilState.depthTestEnable = false;
+                       cfg.depthStencilState.depthWriteEnable = false;
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/FullScreenQuad.vert.spv");
+                       cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/pbrtest.frag.spv");
+                       composePipeline = new GraphicPipeline (cfg);
+
+                       envCube = new EnvironmentCube (presentQueue, renderPass);
+
+                       uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, (ulong)Marshal.SizeOf<Matrices> () * 2);
+                       uboMats.Map ();//permanent map
+
+                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutMain);
+                       uboUpdate.Write (dev, dsMain, uboMats.Descriptor,
+                               envCube.lutBrdf.Descriptor,
+                               envCube.irradianceCube.Descriptor,
+                               envCube.prefilterCube.Descriptor);
+                       uboMats.Descriptor.offset = (ulong)Marshal.SizeOf<Matrices> ();
+                       envCube.WriteDesc (uboMats.Descriptor);
+#if DEBUG
+                       debugDraw = new DebugDrawPipeline (dev, descLayoutMain, swapChain.ColorFormat);
+                       debugDraw.AddLine (Vector3.Zero, new Vector3(matrices.lightPos.X,matrices.lightPos.Y,matrices.lightPos.Z)*3, 1, 1, 1);
+                       debugDraw.AddLine (Vector3.Zero, Vector3.UnitX, 1, 0, 0);
+                       debugDraw.AddLine (Vector3.Zero, Vector3.UnitY, 0, 1, 0);
+                       debugDraw.AddLine (Vector3.Zero, Vector3.UnitZ, 0, 0, 1);
+#endif
+
+
+                       model = new Model (presentQueue, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf");
+                       //model = new Model (presentQueue, "../data/models/chess.gltf");
+                       //model = new Model (presentQueue, "../data/models/Sponza/glTF/Sponza.gltf");
+                       //model = new Model (dev, presentQueue, "../data/models/icosphere.gltf");
+                       //model = new Model (dev, presentQueue, cmdPool, "../data/models/cube.gltf");
+                       model.WriteMaterialsDescriptorSets (descLayoutModelTextures,
+                               VK.AttachmentType.Color,
+                               VK.AttachmentType.Normal,
+                               VK.AttachmentType.AmbientOcclusion,
+                               VK.AttachmentType.PhysicalProps,
+                               VK.AttachmentType.Emissive);                            
+               }
+
+               void buildCommandBuffers () {
+                       for (int i = 0; i < swapChain.ImageCount; ++i) {
+                               cmds[i]?.Free ();
+                               cmds[i] = cmdPool.AllocateCommandBuffer ();
+                               cmds[i].Start ();
+
+#if DEBUG
+                               statPool.Begin (cmds[i]);
+                               recordDraw (cmds[i], frameBuffers[i]);
+                               statPool.End (cmds[i]);
+
+                               debugDraw.RecordDraw (cmds[i], debugFB[i], camera);
+#else
+                               recordDraw (cmds[i], frameBuffers[i]);
+#endif
+
+                               cmds[i].End ();
+                       }
+               }
+               void recordDraw (CommandBuffer cmd, Framebuffer fb) {
+                       renderPass.Begin (cmd, fb);
+
+                       cmd.SetViewport (fb.Width, fb.Height);
+                       cmd.SetScissor (fb.Width, fb.Height);
+
+                       cmd.BindDescriptorSet (gBuffPipeline.Layout, dsMain);
+                       gBuffPipeline.Bind (cmd);
+                       model.Bind (cmd);
+                       model.DrawAll (cmd, gBuffPipeline.Layout);
+
+                       renderPass.BeginSubPass (cmd);
+
+                       cmd.BindDescriptorSet (composePipeline.Layout, dsGBuff, 2);
+                       composePipeline.Bind (cmd);
+
+                       cmd.Draw (3, 1, 0, 0);
+
+                       renderPass.End (cmd);
+               }
+
+#region update
+               void updateMatrices () {
+                       camera.AspectRatio = (float)swapChain.Width / swapChain.Height;
+
+                       matrices.projection = camera.Projection;
+                       matrices.view = camera.View;
+                       matrices.model = camera.Model;
+                       uboMats.Update (matrices, (uint)Marshal.SizeOf<Matrices> ());
+                       matrices.view *= Matrix4x4.CreateTranslation (-matrices.view.Translation);
+                       matrices.model = Matrix4x4.Identity;
+                       uboMats.Update (matrices, (uint)Marshal.SizeOf<Matrices> (), (uint)Marshal.SizeOf<Matrices> ());
+               }
+
+               public override void UpdateView () {
+                       updateMatrices ();
+                       updateViewRequested = false;
+               }
+               public override void Update () {
+#if DEBUG
+                       results = statPool.GetResults ();
+#endif
+               }
+#endregion
+
+
+
+               void createGBuff () {
+                       gbColorRough?.Dispose ();
+                       gbEmitMetal?.Dispose ();
+                       gbN?.Dispose ();
+                       gbPos?.Dispose ();
+
+                       gbColorRough = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height);
+                       gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height);
+                       gbN = new Image (dev, VkFormat.R16g16b16a16Sfloat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height);
+                       gbPos = new Image (dev, VkFormat.R16g16b16a16Sfloat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height);
+
+                       gbColorRough.CreateView ();
+                       gbColorRough.CreateSampler ();
+                       gbEmitMetal.CreateView ();
+                       gbEmitMetal.CreateSampler ();
+                       gbN.CreateView ();
+                       gbN.CreateSampler ();
+                       gbPos.CreateView ();
+                       gbPos.CreateSampler ();
+
+                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutGBuff);
+                       uboUpdate.Write (dev, dsGBuff,  gbColorRough.Descriptor,
+                                                                               gbEmitMetal.Descriptor,
+                                                                               gbN.Descriptor,
+                                                                               gbPos.Descriptor);
+                       gbColorRough.SetName ("GBuffColorRough");
+                       gbEmitMetal.SetName ("GBuffEmitMetal");
+                       gbN.SetName ("GBuffN");
+                       gbPos.SetName ("GBuffPos");
+               }
+
+               protected override void OnResize () {
+                       updateMatrices ();
+
+                       if (frameBuffers != null)
+                               for (int i = 0; i < swapChain.ImageCount; ++i)
+                                       frameBuffers[i]?.Dispose ();
+#if DEBUG
+                       if (debugFB != null)
+                               for (int i = 0; i < swapChain.ImageCount; ++i)
+                                       debugFB[i]?.Dispose ();
+#endif
+
+                       createGBuff ();
+
+                       frameBuffers = new Framebuffer[swapChain.ImageCount];
+                       debugFB = new Framebuffer[swapChain.ImageCount];
+
+                       for (int i = 0; i < swapChain.ImageCount; ++i) {
+                               frameBuffers[i] = new Framebuffer (renderPass, swapChain.Width, swapChain.Height, new Image[] {
+                                       swapChain.images[i], null, gbColorRough, gbEmitMetal, gbN, gbPos});
+#if DEBUG
+                               debugFB[i] = new Framebuffer (debugDraw.RenderPass, swapChain.Width, swapChain.Height,(debugDraw.Samples == VkSampleCountFlags.SampleCount1)
+                                       ? new Image[] { swapChain.images[i] } : new Image[] { null, swapChain.images[i] });
+                               debugFB[i].SetName ("main FB " + i);
+#endif
+                       }
+
+                       buildCommandBuffers ();
+               }
+
+
+               #region Mouse and keyboard
+               protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
+                       switch (key) {
+                               case Key.F1:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               matrices.exposure -= 0.3f;
+                                       else
+                                               matrices.exposure += 0.3f;
+                                       break;
+                               case Key.F2:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               matrices.gamma -= 0.1f;
+                                       else
+                                               matrices.gamma += 0.1f;
+                                       break;
+                               case Key.F3:
+                                       if (camera.Type == Camera.CamType.FirstPerson)
+                                               camera.Type = Camera.CamType.LookAt;
+                                       else
+                                               camera.Type = Camera.CamType.FirstPerson;
+                                       Console.WriteLine ($"camera type = {camera.Type}");
+                                       break;
+                               default:
+                                       base.onKeyDown (key, scanCode, modifiers);
+                                       return;
+                       }
+                       updateViewRequested = true;
+               }
+#endregion
+
+               protected override void Dispose (bool disposing) {
+                       if (disposing) {
+                               if (!isDisposed) {
+                                       dev.WaitIdle ();
+                                       for (int i = 0; i < swapChain.ImageCount; ++i)
+                                               frameBuffers[i]?.Dispose ();
+
+                                       gbColorRough.Dispose ();
+                                       gbEmitMetal.Dispose ();
+                                       gbN.Dispose ();
+                                       gbPos.Dispose ();
+
+                                       gBuffPipeline.Dispose ();
+                                       composePipeline.Dispose ();
+
+                                       descLayoutMain.Dispose ();
+                                       descLayoutModelTextures.Dispose ();
+                                       descLayoutGBuff.Dispose ();
+
+                                       uboMats.Dispose ();
+                                       model.Dispose ();
+                                       envCube.Dispose ();
+
+                                       descriptorPool.Dispose ();
+#if DEBUG
+                                       foreach (Framebuffer fb in debugFB) 
+                                               fb.Dispose ();
+
+                                       debugDraw.Dispose ();
+                                       timestampQPool?.Dispose ();
+                                       statPool?.Dispose ();
+#endif
+                               }
+                       }
+
+                       base.Dispose (disposing);
+               }
+       }
+}
diff --git a/samples/glow/modelWithVkvgStats.cs b/samples/glow/modelWithVkvgStats.cs
new file mode 100644 (file)
index 0000000..f4ea123
--- /dev/null
@@ -0,0 +1,359 @@
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using Glfw;
+using CVKL;
+using VK;
+using static CVKL.Camera;
+
+namespace modelWithVkvgStats {
+       class Program : VkWindow {
+
+               PipelineStatisticsQueryPool statPool;
+               TimestampQueryPool timestampQPool;
+
+               ulong[] results;
+
+               protected override void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) {
+                       base.configureEnabledFeatures (ref features);
+                       features.pipelineStatisticsQuery = true;
+               }
+               public struct Matrices {
+                       public Matrix4x4 projection;
+                       public Matrix4x4 view;
+                       public Matrix4x4 model;
+                       public Vector4 lightPos;
+                       public float gamma;
+                       public float exposure;
+               }
+
+               public Matrices matrices = new Matrices { 
+                       lightPos = new Vector4 (0.0f, 0.0f, -2.0f, 1.0f),
+                       gamma = 1.0f,
+                       exposure = 2.0f,
+               };
+
+               HostBuffer uboMats;
+
+               DescriptorPool descriptorPool;
+               DescriptorSetLayout descLayoutMatrix;
+               DescriptorSetLayout descLayoutTextures;
+               DescriptorSet dsMats;
+
+               GraphicPipeline pipeline;
+               GraphicPipeline uiPipeline;
+               Framebuffer[] frameBuffers;
+
+               Model model;
+
+               vkvg.Device vkvgDev;
+        vkvg.Surface vkvgSurf;
+               Image vkvgImage;
+
+        void vkvgDraw () {
+
+            using (vkvg.Context ctx = new vkvg.Context (vkvgSurf)) {
+                               ctx.Operator = vkvg.Operator.Clear;
+                               ctx.Paint ();
+                               ctx.Operator = vkvg.Operator.Over;
+
+                               ctx.LineWidth = 1;
+                               ctx.SetSource (0.1, 0.1, 0.1, 0.3);
+                               ctx.Rectangle (5.5, 5.5, 400, 250);
+                               ctx.FillPreserve ();
+                               ctx.Flush ();
+                               ctx.SetSource (0.8, 0.8, 0.8);
+                               ctx.Stroke ();
+
+                               ctx.FontFace = "mono";
+                               ctx.FontSize = 10;
+                               int x = 16;
+                               int y = 40, dy = 16;
+                               ctx.MoveTo (x, y);
+                               ctx.ShowText (string.Format ($"fps:     {fps,5} "));
+                               ctx.MoveTo (x + 200, y - 0.5);
+                               ctx.Rectangle (x + 200, y - 8.5, 0.1 * fps, 10);
+                               ctx.SetSource (0.1, 0.9, 0.1);
+                               ctx.Fill ();
+                               ctx.SetSource (0.8, 0.8, 0.8);
+                               y += dy;
+                               ctx.MoveTo (x, y);
+                               ctx.ShowText (string.Format ($"Exposure:{matrices.exposure,5} "));
+                               y += dy;
+                               ctx.MoveTo (x, y);
+                               ctx.ShowText (string.Format ($"Gamma:   {matrices.gamma,5} "));
+                               if (results == null)
+                                       return;
+
+                               y += dy*2;
+                               ctx.MoveTo (x, y);
+                               ctx.ShowText ("Pipeline Statistics");
+                               ctx.MoveTo (x-2, 2.5+y);
+                               ctx.LineTo (x+160, 2.5+y);
+                               ctx.Stroke ();
+                               y += 4;
+                               x += 20;
+
+                               for (int i = 0; i < statPool.RequestedStats.Length; i++) {
+                                       y += dy;
+                                       ctx.MoveTo (x, y);
+                                       ctx.ShowText (string.Format ($"{statPool.RequestedStats[i].ToString(),-30} :{results[i],12:0,0} "));
+                               }
+
+                               y += dy;
+                               ctx.MoveTo (x, y);
+                               ctx.ShowText (string.Format ($"{"Elapsed microsecond",-20} :{timestampQPool.ElapsedMiliseconds:0.0000} "));
+                       }
+               }
+
+               Program () : base () {
+                       vkvgDev = new vkvg.Device (instance.Handle, phy.Handle, dev.VkDev.Handle, presentQueue.qFamIndex,
+                               vkvg.SampleCount.Sample_4, presentQueue.index);
+
+                       camera.Type = CamType.FirstPerson;
+                       camera.Model = Matrix4x4.CreateScale (0.05f) * Matrix4x4.CreateRotationX((float)Math.PI);
+                       //Camera.SetRotation (-0.1f,-0.4f);
+                       camera.SetPosition (0, 2, -3);
+                                       
+                       init ();
+
+                       model = new Model (presentQueue, "../data/models/Sponza/glTF/Sponza.gltf");
+                       model.WriteMaterialsDescriptorSets (descLayoutTextures,
+                               VK.AttachmentType.Color,
+                               VK.AttachmentType.Normal,
+                               VK.AttachmentType.AmbientOcclusion,
+                               VK.AttachmentType.PhysicalProps,
+                               VK.AttachmentType.Emissive);
+               }
+
+               void init (VkSampleCountFlags samples = VkSampleCountFlags.SampleCount4) { 
+                       descriptorPool = new DescriptorPool (dev, 2,
+                               new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer),
+                               new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler)
+                       );
+
+                       descLayoutMatrix = new DescriptorSetLayout (dev,
+                               new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex|VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer),
+                               new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)
+                       );
+
+                       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)
+                       );
+
+                       dsMats = descriptorPool.Allocate (descLayoutMatrix);
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, samples);
+
+                       cfg.Layout = new PipelineLayout (dev, descLayoutMatrix, descLayoutTextures);
+                       cfg.Layout.AddPushConstants (
+                               new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()),
+                               new VkPushConstantRange (VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf<Model.PbrMaterial> (), 64)
+                       );
+                       cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), samples);
+
+                       cfg.AddVertexBinding<Model.Vertex> (0);
+                       cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat);
+
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/pbrtest.vert.spv");
+                       cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/pbrtest.frag.spv");
+
+                       pipeline = new GraphicPipeline (cfg);
+
+                       cfg.ResetShadersAndVerticesInfos ();
+                       cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/FullScreenQuad.vert.spv");
+                       cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/simpletexture.frag.spv");
+
+                       cfg.blendAttachments[0] = new VkPipelineColorBlendAttachmentState (true);
+
+                       uiPipeline = new GraphicPipeline (cfg);
+
+                       uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, (ulong)Marshal.SizeOf<Matrices>());
+                       uboMats.Map ();//permanent map
+
+                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMats, descLayoutMatrix.Bindings[0]);                         
+                       uboUpdate.Write (dev, uboMats.Descriptor);
+
+                       cfg.Layout.SetName ("Main Pipeline layout");
+                       uboMats.SetName ("uboMats");
+                       descriptorPool.SetName ("main pool");
+                       descLayoutTextures.SetName ("descLayoutTextures");
+
+                       statPool = new PipelineStatisticsQueryPool (dev,
+                               VkQueryPipelineStatisticFlags.InputAssemblyVertices |
+                               VkQueryPipelineStatisticFlags.InputAssemblyPrimitives |
+                               VkQueryPipelineStatisticFlags.ClippingInvocations |
+                               VkQueryPipelineStatisticFlags.ClippingPrimitives |
+                               VkQueryPipelineStatisticFlags.FragmentShaderInvocations);
+
+                       timestampQPool = new TimestampQueryPool (dev);
+
+               }
+
+               void buildCommandBuffers () {
+                       for (int i = 0; i < swapChain.ImageCount; ++i) {                                                                
+                cmds[i]?.Free ();
+
+                               cmds[i] = cmdPool.AllocateCommandBuffer ();
+                               cmds[i].Start ();
+
+                               statPool.Begin (cmds[i]);
+                               cmds[i].BeginRegion ("draw" + i, 0.5f, 1f, 0f);
+                               cmds[i].Handle.SetDebugMarkerName (dev, "cmd Draw" + i); 
+                               recordDraw (cmds[i], frameBuffers[i]);
+                               cmds[i].EndRegion ();
+                               statPool.End (cmds[i]);                 
+                               cmds[i].End ();
+                       }
+               } 
+               void recordDraw (CommandBuffer cmd, Framebuffer fb) {
+                       cmd.BeginRegion ("models", 0.5f, 1f, 0f);
+                       pipeline.RenderPass.Begin (cmd, fb);
+
+                       cmd.SetViewport (fb.Width, fb.Height);
+                       cmd.SetScissor (fb.Width, fb.Height);
+
+                       cmd.BindDescriptorSet (pipeline.Layout, dsMats);
+                       pipeline.Bind (cmd);
+                       model.Bind (cmd);
+                       model.DrawAll (cmd, pipeline.Layout);
+
+                       cmd.EndRegion ();
+                       cmd.BeginRegion ("vkvg", 0.5f, 1f, 0f);
+                       uiPipeline.Bind (cmd);
+
+                       timestampQPool.Start (cmd);
+
+                       vkvgImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ColorAttachmentOptimal, VkImageLayout.ShaderReadOnlyOptimal,
+                               VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader);
+
+                       cmd.Draw (3, 1, 0, 0);
+
+                       vkvgImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ShaderReadOnlyOptimal, VkImageLayout.ColorAttachmentOptimal,
+                               VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.BottomOfPipe);
+
+                       timestampQPool.End (cmd);
+
+                       pipeline.RenderPass.End (cmd);
+                       cmd.EndRegion ();
+               }
+
+               #region update
+               void updateMatrices () {
+
+                       camera.AspectRatio = (float)swapChain.Width / swapChain.Height;
+
+                       matrices.projection = camera.Projection;
+                       matrices.view = camera.View;
+                       matrices.model = camera.Model;
+                       uboMats.Update (matrices, (uint)Marshal.SizeOf<Matrices> ());
+               }
+                       
+               public override void UpdateView () {
+                       updateMatrices ();
+                       updateViewRequested = false;
+               }
+               public override void Update () {
+                       results = statPool.GetResults ();
+                       vkvgDraw ();
+               }
+               #endregion
+
+               #region mouse and keyboard
+               protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
+                       switch (key) {
+                               case Key.F1:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               matrices.exposure -= 0.3f;
+                                       else
+                                               matrices.exposure += 0.3f;
+                                       break;
+                               case Key.F2:
+                                       if (modifiers.HasFlag (Modifier.Shift))
+                                               matrices.gamma -= 0.1f;
+                                       else
+                                               matrices.gamma += 0.1f;
+                                       break;
+                               case Key.F3:
+                                       if (camera.Type == CamType.FirstPerson)
+                                               camera.Type = CamType.LookAt;
+                                       else
+                                               camera.Type = CamType.FirstPerson;
+                                       break;
+                               default:
+                                       base.onKeyDown (key, scanCode, modifiers);
+                                       return;
+                       }
+                       updateViewRequested = true;
+               }
+               #endregion
+
+               protected override void OnResize () {
+
+                       vkvgImage?.Dispose ();
+                       vkvgSurf?.Dispose ();
+                       vkvgSurf = new vkvg.Surface (vkvgDev, (int)swapChain.Width, (int)swapChain.Height);
+                       vkvgImage = new Image (dev, new VkImage ((ulong)vkvgSurf.VkImage.ToInt64 ()), VkFormat.B8g8r8a8Unorm,
+                               VkImageUsageFlags.ColorAttachment, (uint)vkvgSurf.Width, (uint)vkvgSurf.Height);
+                       vkvgImage.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color);
+                       vkvgImage.CreateSampler (VkFilter.Nearest,VkFilter.Nearest, VkSamplerMipmapMode.Nearest, VkSamplerAddressMode.ClampToBorder);
+
+                       vkvgImage.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+                       DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMats, descLayoutMatrix.Bindings[1]);                         
+                       uboUpdate.Write (dev, vkvgImage.Descriptor);
+
+                       updateMatrices ();
+
+                       if (frameBuffers!=null)
+                               for (int i = 0; i < swapChain.ImageCount; ++i)
+                                       frameBuffers[i]?.Dispose ();
+
+                       frameBuffers = new Framebuffer[swapChain.ImageCount];
+
+                       for (int i = 0; i < swapChain.ImageCount; ++i) {
+                               frameBuffers[i] = new Framebuffer (pipeline.RenderPass, swapChain.Width, swapChain.Height,
+                                       (pipeline.Samples == VkSampleCountFlags.SampleCount1) ? new Image[] {
+                                               swapChain.images[i],
+                                               null
+                                       } : new Image[] {
+                                               null,
+                                               null,
+                                               swapChain.images[i]
+                                       });
+                               frameBuffers[i].SetName ("main FB " + i);
+
+                       }
+
+                       buildCommandBuffers ();
+               }       
+
+               protected override void Dispose (bool disposing) {
+                       if (disposing) {
+                               if (!isDisposed) {
+                                       dev.WaitIdle ();
+                                       for (int i = 0; i < swapChain.ImageCount; ++i)
+                                               frameBuffers[i]?.Dispose ();
+                                       model.Dispose ();
+                                       pipeline.Dispose ();
+                                       descLayoutMatrix.Dispose ();
+                                       descLayoutTextures.Dispose ();
+                                       descriptorPool.Dispose ();
+
+                                       uboMats.Dispose ();
+
+                                       vkvgSurf?.Dispose ();
+                                       vkvgDev.Dispose ();
+
+                                       timestampQPool.Dispose ();
+                                       statPool.Dispose ();
+                               }
+                       }
+
+                       base.Dispose (disposing);
+               }
+       }
+}
diff --git a/samples/glow/shaders/GBuffPbr.frag b/samples/glow/shaders/GBuffPbr.frag
new file mode 100644 (file)
index 0000000..9e30cab
--- /dev/null
@@ -0,0 +1,140 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+#define MANUAL_SRGB 0
+
+struct Material {
+    vec4 baseColorFactor;
+    vec4 emissiveFactor;
+    vec4 diffuseFactor;
+    vec4 specularFactor;
+    float workflow;
+    uint tex0;
+    uint tex1;
+    float metallicFactor;   
+    float roughnessFactor;  
+    float alphaMask;    
+    float alphaMaskCutoff;
+    int pad0;
+};
+
+#include "GBuffPbrCommon.inc"
+#include "tonemap.inc"
+
+// Material bindings
+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;
+
+// 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(normalMap, inUV0).xyz * 2.0 - 1.0;
+    else if ((materials[materialIdx].tex1 & MAP_NORMAL) == MAP_NORMAL)
+        tangentNormal = texture(normalMap, inUV1).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);
+}
+
+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(physicalDescriptorMap, inUV0).g;
+            metallic *= texture(physicalDescriptorMap, inUV0).b;
+        }else if ((materials[materialIdx].tex1 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS){
+            perceptualRoughness *= texture(physicalDescriptorMap, inUV1).g;
+            metallic *= texture(physicalDescriptorMap, inUV1).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(colorMap, inUV0));
+        else if ((materials[materialIdx].tex1 & MAP_COLOR) == MAP_COLOR)
+            baseColor *= SRGBtoLINEAR(texture(colorMap, inUV1));        
+    }
+    
+    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(physicalDescriptorMap, inUV0).a;            
+        else if ((materials[materialIdx].tex1 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS)
+            perceptualRoughness = 1.0 - texture(physicalDescriptorMap, inUV1).a;            
+        else
+            perceptualRoughness = 0.0;
+
+        const float epsilon = 1e-6;
+
+        vec4 diffuse = SRGBtoLINEAR(texture(colorMap, inUV0));
+        vec3 specular = SRGBtoLINEAR(texture(physicalDescriptorMap, inUV0)).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(emissiveMap, inUV0)).rgb * u_EmissiveFactor;
+    else if ((materials[materialIdx].tex1 & MAP_EMISSIVE) == MAP_EMISSIVE)    
+        emissive = SRGBtoLINEAR(texture(emissiveMap, inUV1)).rgb * u_EmissiveFactor;
+    
+    if ((materials[materialIdx].tex0 & MAP_AO) == MAP_AO)
+        ao = texture(aoMap, inUV0).r;
+    else if ((materials[materialIdx].tex1 & MAP_AO) == MAP_AO)
+        ao = texture(aoMap, inUV1).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/glow/shaders/GBuffPbr.vert b/samples/glow/shaders/GBuffPbr.vert
new file mode 100644 (file)
index 0000000..7cafe49
--- /dev/null
@@ -0,0 +1,37 @@
+#version 450
+
+layout (location = 0) in vec3 inPos;
+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;    
+} ubo;
+
+layout(push_constant) uniform PushConsts {
+    mat4 model;
+} pc;
+
+layout (location = 0) out vec3 outWorldPos;
+layout (location = 1) out vec3 outNormal;
+layout (location = 2) out vec2 outUV0;
+layout (location = 3) out vec2 outUV1;
+
+out gl_PerVertex
+{
+    vec4 gl_Position;
+};
+
+void main() 
+{        
+    vec4 locPos = ubo.model * pc.model * vec4(inPos, 1.0);
+    outNormal = normalize(transpose(inverse(mat3(ubo.model * pc.model))) * inNormal);        
+        
+    outWorldPos = locPos.xyz;
+    outUV0 = inUV0;
+    outUV1 = inUV1;
+    gl_Position =  ubo.projection * ubo.view * vec4(outWorldPos, 1.0);
+}
diff --git a/samples/glow/shaders/GBuffPbrCommon.inc b/samples/glow/shaders/GBuffPbrCommon.inc
new file mode 100644 (file)
index 0000000..4146fa5
--- /dev/null
@@ -0,0 +1,56 @@
+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;
+
+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 (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;
+
+// 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));   
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/GBuffPbrTexArray.frag b/samples/glow/shaders/GBuffPbrTexArray.frag
new file mode 100644 (file)
index 0000000..cddf49f
--- /dev/null
@@ -0,0 +1,142 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+#define MANUAL_SRGB 0
+
+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;    
+};
+
+#include "GBuffPbrCommon.inc"
+#include "tonemap.inc"
+
+layout (set = 0, binding = 7) uniform sampler2DArray texArray;
+
+// 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);
+}
+
+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/glow/shaders/bloom.comp b/samples/glow/shaders/bloom.comp
new file mode 100644 (file)
index 0000000..e2b1318
--- /dev/null
@@ -0,0 +1,60 @@
+#version 450
+
+layout (local_size_x = 16, local_size_y = 16) in;
+layout (binding = 0, rgba16f) uniform readonly image2D inputImage;
+layout (binding = 1, rgba16f) uniform image2D resultImage;
+
+layout(push_constant) uniform PushConsts {
+    vec2 texSize;
+    int dir;
+    float scale;
+    float strength;
+} pc;
+
+void main(void)
+{
+       // From the OpenGL Super bible
+       const float weights[] = float[](0.0024499299678342,
+                                                                       0.0043538453346397,
+                                                                       0.0073599963704157,
+                                                                       0.0118349786570722,
+                                                                       0.0181026699707781,
+                                                                       0.0263392293891488,
+                                                                       0.0364543006660986,
+                                                                       0.0479932050577658,
+                                                                       0.0601029809166942,
+                                                                       0.0715974486241365,
+                                                                       0.0811305381519717,
+                                                                       0.0874493212267511,
+                                                                       0.0896631113333857,
+                                                                       0.0874493212267511,
+                                                                       0.0811305381519717,
+                                                                       0.0715974486241365,
+                                                                       0.0601029809166942,
+                                                                       0.0479932050577658,
+                                                                       0.0364543006660986,
+                                                                       0.0263392293891488,
+                                                                       0.0181026699707781,
+                                                                       0.0118349786570722,
+                                                                       0.0073599963704157,
+                                                                       0.0043538453346397,
+                                                                       0.0024499299678342);
+                                                                       
+
+       float ar = 1.0;
+    vec4 color = vec4(0.0);
+    
+       // Aspect ratio for vertical blur pass
+       if (pc.dir == 1)
+               ar = pc.texSize.y / pc.texSize.x;
+            
+       vec2 P = gl_GlobalInvocationID.yx - vec2(0, (weights.length() >> 1) * ar * pc.scale);
+       
+       for (int i = 0; i < weights.length(); i++)
+       {
+               vec2 dv = vec2(0.0, i * pc.scale) * ar;
+               color += imageLoad (inputImage, ivec2(P + dv)) * weights[i] * pc.strength;
+       }
+  
+    imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), color);
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/bloom.frag b/samples/glow/shaders/bloom.frag
new file mode 100644 (file)
index 0000000..c3bf402
--- /dev/null
@@ -0,0 +1,63 @@
+#version 450
+
+layout (binding = 0) uniform sampler2D samplerColor0;
+layout (binding = 1) uniform sampler2D samplerColor1;
+
+layout (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+layout (constant_id = 0) const int dir = 0;
+
+void main(void)
+{
+       // From the OpenGL Super bible
+       const float weights[] = float[](0.0024499299678342,
+                                                                       0.0043538453346397,
+                                                                       0.0073599963704157,
+                                                                       0.0118349786570722,
+                                                                       0.0181026699707781,
+                                                                       0.0263392293891488,
+                                                                       0.0364543006660986,
+                                                                       0.0479932050577658,
+                                                                       0.0601029809166942,
+                                                                       0.0715974486241365,
+                                                                       0.0811305381519717,
+                                                                       0.0874493212267511,
+                                                                       0.0896631113333857,
+                                                                       0.0874493212267511,
+                                                                       0.0811305381519717,
+                                                                       0.0715974486241365,
+                                                                       0.0601029809166942,
+                                                                       0.0479932050577658,
+                                                                       0.0364543006660986,
+                                                                       0.0263392293891488,
+                                                                       0.0181026699707781,
+                                                                       0.0118349786570722,
+                                                                       0.0073599963704157,
+                                                                       0.0043538453346397,
+                                                                       0.0024499299678342);
+
+
+       const float blurScale = 0.003;
+       const float blurStrength = 1.0;
+
+       float ar = 1.0;
+       // Aspect ratio for vertical blur pass
+       if (dir == 1)
+       {
+               vec2 ts = textureSize(samplerColor1, 0);
+               ar = ts.y / ts.x;
+       }
+
+       vec2 P = inUV.yx - vec2(0, (weights.length() >> 1) * ar * blurScale);
+
+       vec4 color = vec4(0.0);
+       for (int i = 0; i < weights.length(); i++)
+       {
+               vec2 dv = vec2(0.0, i * blurScale) * ar;
+               color += texture(samplerColor1, P + dv) * weights[i] * blurStrength;
+       }
+
+       outColor = color;
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/compose.frag b/samples/glow/shaders/compose.frag
new file mode 100644 (file)
index 0000000..e6ab256
--- /dev/null
@@ -0,0 +1,157 @@
+#include "preamble.inc"
+
+layout (set = 0, binding = 0) uniform UBO {
+    mat4 projection;
+    mat4 model;
+    mat4 view;
+    vec4 camPos;    
+    float exposure;
+    float gamma;
+    float prefilteredCubeMipLevels;
+    float scaleIBLAmbient;
+} ubo;
+
+layout (constant_id = 0) const uint NUM_LIGHTS = 1;
+
+struct Light {
+    vec4 position;
+    vec4 color;
+    mat4 mvp;
+};
+
+layout (set = 0, binding = 4) uniform UBOLights {
+    Light lights[NUM_LIGHTS];
+};
+
+const float M_PI = 3.141592653589793;
+const float c_MinRoughness = 0.04;
+
+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 (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+#include "pbr.inc"
+
+// Calculation of the lighting contribution from an optional Image Based Light source.
+// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
+// See our README.md on Environment Maps [3] for additional discussion.
+vec3 getIBLContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection)
+{
+    float lod = (pbrInputs.perceptualRoughness * ubo.prefilteredCubeMipLevels);
+    // retrieve a scale and bias to F0. See [1], Figure 3
+    vec3 brdf = (texture(samplerBRDFLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness))).rgb;
+    vec3 diffuseLight = texture(samplerIrradiance, reflection).rgb;
+
+    vec3 specularLight = textureLod(prefilteredMap, reflection, lod).rgb;
+
+    vec3 diffuse = diffuseLight * pbrInputs.diffuseColor;
+    vec3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y);
+
+    // For presentation, this allows us to disable IBL terms
+    // For presentation, this allows us to disable IBL terms
+    diffuse *= ubo.scaleIBLAmbient;
+    specular *= ubo.scaleIBLAmbient;
+
+    return diffuse + specular;
+}
+
+void main() 
+{
+    if (subpassLoad(samplerPos, gl_SampleID).a == 1.0f)
+        discard;
+    
+    float perceptualRoughness = subpassLoad(samplerColorRough, gl_SampleID).a;
+    float metallic = subpassLoad(samplerEmitMetal, gl_SampleID).a;
+    vec3 diffuseColor;
+    vec4 baseColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).rgb, 1);    
+    vec3 emissive = subpassLoad (samplerEmitMetal, gl_SampleID).rgb;        
+
+    vec3 f0 = vec3(0.04);
+    
+    diffuseColor = baseColor.rgb * (vec3(1.0) - f0);
+    diffuseColor *= 1.0 - metallic;
+        
+    float alphaRoughness = perceptualRoughness * perceptualRoughness;
+
+    vec3 specularColor = mix(f0, baseColor.rgb, metallic);
+
+    // Compute reflectance.
+    float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
+
+    // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+    // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+    float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
+    vec3 specularEnvironmentR0 = specularColor.rgb;
+    vec3 specularEnvironmentR90 = vec3(1.0) * reflectance90;
+
+    vec3 n = subpassLoad(samplerN_AO, gl_SampleID).rgb;
+    vec3 pos = subpassLoad(samplerPos, gl_SampleID).rgb;
+    vec3 v = normalize(ubo.camPos.xyz - pos); // Vector from surface point to camera
+    
+    vec3 colors = vec3(0);
+    vec3 lightTarget = vec3(0);
+    
+    for (int i=0; i<NUM_LIGHTS; i++) {
+    
+        vec3 l = normalize(lights[i].position.xyz-pos);     // Vector from surface point to light
+        vec3 h = normalize(l+v);                        // Half vector between both l and v
+        vec3 reflection = -normalize(reflect(v, n));
+        reflection.y *= -1.0f;
+
+        float NdotL = clamp(dot(n, l), 0.001, 1.0);
+        float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
+        float NdotH = clamp(dot(n, h), 0.0, 1.0);
+        float LdotH = clamp(dot(l, h), 0.0, 1.0);
+        float VdotH = clamp(dot(v, h), 0.0, 1.0);
+
+        PBRInfo pbrInputs = PBRInfo(
+            NdotL,
+            NdotV,
+            NdotH,
+            LdotH,
+            VdotH,
+            perceptualRoughness,
+            metallic,
+            specularEnvironmentR0,
+            specularEnvironmentR90,
+            alphaRoughness,
+            diffuseColor,
+            specularColor
+        );
+
+        // Calculate the shading terms for the microfacet specular shading model
+        vec3 F = specularReflection(pbrInputs);
+        float G = geometricOcclusion(pbrInputs);
+        float D = microfacetDistribution(pbrInputs);
+
+        // Calculation of analytical lighting contribution
+        vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs);
+        vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);        
+        // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
+        vec3 color = NdotL * lights[i].color.rgb * (diffuseContrib + specContrib);
+        // Calculate lighting contribution from image based lighting source (IBL)
+        colors += (color + getIBLContribution(pbrInputs, n, reflection));
+        
+        
+    }
+    colors /= NUM_LIGHTS;
+    
+    
+    const float u_OcclusionStrength = 1.0f;
+    const float u_EmissiveFactor = 1.0f;
+    
+    //AO is in the alpha channel of the normalAttachment    
+    colors = mix(colors, colors * subpassLoad(samplerN_AO, gl_SampleID).a, u_OcclusionStrength);
+    colors += emissive;             
+    
+    outColor = vec4(colors, baseColor.a);       
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/compose_with_shadows.frag b/samples/glow/shaders/compose_with_shadows.frag
new file mode 100644 (file)
index 0000000..95d4940
--- /dev/null
@@ -0,0 +1,206 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (set = 0, binding = 0) uniform UBO {
+    mat4 projection;
+    mat4 model;
+    mat4 view;
+    vec4 camPos;    
+    float prefilteredCubeMipLevels;
+    float scaleIBLAmbient;
+} ubo;
+
+layout (constant_id = 0) const uint NUM_LIGHTS = 1;
+
+struct Light {
+    vec4 position;
+    vec4 color;
+    mat4 mvp;
+};
+
+layout (set = 0, binding = 4) uniform UBOLights {
+    Light lights[NUM_LIGHTS];
+};
+
+const float M_PI = 3.141592653589793;
+const float c_MinRoughness = 0.04;
+#define SHADOW_FACTOR 0.15
+
+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 = 6) uniform sampler2DArray samplerShadowMap;
+
+layout (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+#include "pbr.inc"
+
+// Calculation of the lighting contribution from an optional Image Based Light source.
+// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
+// See our README.md on Environment Maps [3] for additional discussion.
+vec3 getIBLContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection)
+{
+    float lod = (pbrInputs.perceptualRoughness * ubo.prefilteredCubeMipLevels);
+    // retrieve a scale and bias to F0. See [1], Figure 3
+    vec3 brdf = (texture(samplerBRDFLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness))).rgb;
+    
+    vec3 diffuseLight = texture(samplerIrradiance, reflection).rgb;
+    vec3 specularLight = textureLod(prefilteredMap, reflection, lod).rgb;
+
+    vec3 diffuse = diffuseLight * pbrInputs.diffuseColor;
+    vec3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y);
+
+    // For presentation, this allows us to disable IBL terms
+    // For presentation, this allows us to disable IBL terms
+    diffuse *= ubo.scaleIBLAmbient;
+    specular *= ubo.scaleIBLAmbient;
+
+    return diffuse + specular;
+}
+
+float textureProj(vec4 P, float layer, vec2 offset)
+{
+    float shadow = 1.0;
+    vec4 shadowCoord = P / P.w;
+    shadowCoord.st = shadowCoord.st * 0.5 + 0.5;
+    
+    if (shadowCoord.z > -1.0 && shadowCoord.z < 1.0) 
+    {
+        float dist = texture(samplerShadowMap, vec3(shadowCoord.st + offset, layer)).r;
+        if (shadowCoord.w > 0.0 && dist < shadowCoord.z)         
+            shadow = SHADOW_FACTOR;
+    }else
+        shadow = 0.05f;//for debug view out of light proj
+    
+    return shadow;
+}
+
+float filterPCF(vec4 sc, float layer)
+{
+    ivec2 texDim = textureSize(samplerShadowMap, 0).xy;
+    float scale = 1.5;
+    float dx = scale * 1.0 / float(texDim.x);
+    float dy = scale * 1.0 / float(texDim.y);
+
+    float shadowFactor = 0.0;
+    int count = 0;
+    int range = 1;
+    
+    for (int x = -range; x <= range; x++)
+    {
+        for (int y = -range; y <= range; y++)
+        {
+            shadowFactor += textureProj(sc, layer, vec2(dx*x, dy*y));
+            count++;
+        }
+    
+    }
+    return shadowFactor / count;
+}
+
+void main() 
+{
+    if (subpassLoad(samplerPos, gl_SampleID).a == 1.0f)
+        discard;
+    
+    float perceptualRoughness = subpassLoad(samplerColorRough, gl_SampleID).a;
+    float metallic = subpassLoad(samplerEmitMetal, gl_SampleID).a;
+    vec3 diffuseColor;
+    vec4 baseColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).rgb, 1);    
+    vec3 emissive = subpassLoad (samplerEmitMetal, gl_SampleID).rgb;        
+
+    vec3 f0 = vec3(0.04);
+    
+    diffuseColor = baseColor.rgb * (vec3(1.0) - f0);
+    diffuseColor *= 1.0 - metallic;
+        
+    float alphaRoughness = perceptualRoughness * perceptualRoughness;
+
+    vec3 specularColor = mix(f0, baseColor.rgb, metallic);
+
+    // Compute reflectance.
+    float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
+
+    // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+    // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+    float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
+    vec3 specularEnvironmentR0 = specularColor.rgb;
+    vec3 specularEnvironmentR90 = vec3(1.0) * reflectance90;
+
+    vec3 n = subpassLoad(samplerN_AO, gl_SampleID).rgb;
+    vec3 pos = subpassLoad(samplerPos, gl_SampleID).rgb;
+    vec3 v = normalize(ubo.camPos.xyz - pos); // Vector from surface point to camera
+    
+    vec3 colors = vec3(0);
+    vec3 lightTarget = vec3(0);
+    
+    for (int i=0; i<NUM_LIGHTS; i++) {
+    
+        vec3 l = normalize(lights[i].position.xyz-pos);     // Vector from surface point to light
+        vec3 h = normalize(l+v);                        // Half vector between both l and v
+        vec3 reflection = -normalize(reflect(v, n));
+        reflection.y *= -1.0f;
+
+        float NdotL = clamp(dot(n, l), 0.001, 1.0);
+        float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
+        float NdotH = clamp(dot(n, h), 0.0, 1.0);
+        float LdotH = clamp(dot(l, h), 0.0, 1.0);
+        float VdotH = clamp(dot(v, h), 0.0, 1.0);
+
+        PBRInfo pbrInputs = PBRInfo(
+            NdotL,
+            NdotV,
+            NdotH,
+            LdotH,
+            VdotH,
+            perceptualRoughness,
+            metallic,
+            specularEnvironmentR0,
+            specularEnvironmentR90,
+            alphaRoughness,
+            diffuseColor,
+            specularColor
+        );
+
+        // Calculate the shading terms for the microfacet specular shading model
+        vec3 F = specularReflection(pbrInputs);
+        float G = geometricOcclusion(pbrInputs);
+        float D = microfacetDistribution(pbrInputs);
+
+        // Calculation of analytical lighting contribution
+        vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs);
+        vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);        
+        // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
+        vec3 color = NdotL * lights[i].color.rgb * (diffuseContrib + specContrib);
+        
+        #ifdef WITH_SHADOWS
+        vec4 shadowClip = lights[i].mvp * vec4(pos, 1);
+        float shadowFactor = filterPCF(shadowClip, i);
+        // Calculate lighting contribution from image based lighting source (IBL)
+        colors += shadowFactor * (color + getIBLContribution(pbrInputs, n, reflection));
+        #else
+        colors += color + getIBLContribution(pbrInputs, n, reflection);
+        #endif
+        
+        
+    }
+    colors /= NUM_LIGHTS;
+    
+    
+    const float u_OcclusionStrength = 1.0f;
+    const float u_EmissiveFactor = 3.0f;
+    
+    //AO is in the alpha channel of the normalAttachment    
+    colors = mix(colors, colors * subpassLoad(samplerN_AO, gl_SampleID).a, u_OcclusionStrength);
+    colors += emissive * u_EmissiveFactor;             
+    
+    outColor = vec4(colors, baseColor.a);       
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/debug.frag b/samples/glow/shaders/debug.frag
new file mode 100644 (file)
index 0000000..fd419ff
--- /dev/null
@@ -0,0 +1,12 @@
+#version 450
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (location = 0) in vec3 inColor;
+layout (location = 0) out vec4 outFragColor;
+
+void main() 
+{
+  outFragColor = vec4(inColor, 1.0);
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/debug.vert b/samples/glow/shaders/debug.vert
new file mode 100644 (file)
index 0000000..180e58e
--- /dev/null
@@ -0,0 +1,34 @@
+#version 450
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (location = 0) in vec3 inPos;
+layout (location = 1) in vec3 inColor;
+
+layout (location = 0) out vec3 outColor;
+
+layout (binding = 0) uniform UBO 
+{
+    mat4 projectionMatrix;
+    mat4 viewMatrix;
+    mat4 modelMatrix;    
+    float gamma;
+    float exposure;    
+} ubo;
+
+layout(push_constant) uniform PushConsts {
+    mat4 projectionMatrix;
+} pc;
+
+out gl_PerVertex 
+{
+    vec4 gl_Position;   
+};
+
+void main() 
+{
+    outColor = inColor;
+    
+       gl_Position = pc.projectionMatrix * vec4 ((ubo.viewMatrix * vec4(inPos.xyz, 0.0)).xyz, 1);
+}
diff --git a/samples/glow/shaders/emissive.frag b/samples/glow/shaders/emissive.frag
new file mode 100644 (file)
index 0000000..2efe331
--- /dev/null
@@ -0,0 +1,25 @@
+#version 450
+#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 (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+const float offset[5] = float[](0.0, 1.0, 2.0, 3.0, 4.0);
+const float weight[5] = float[](0.2270270270, 0.1945945946, 0.1216216216,
+                                  0.0540540541, 0.0162162162);
+void main() 
+{
+    if (subpassLoad(samplerPos, gl_SampleID).a == 1.0f)
+        discard;
+    vec3 emissive = subpassLoad (samplerEmitMetal, gl_SampleID).rgb;        
+        
+    outColor = vec4(emissive, 1);
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/shadow.geom b/samples/glow/shaders/shadow.geom
new file mode 100644 (file)
index 0000000..a0ab742
--- /dev/null
@@ -0,0 +1,38 @@
+#version 420
+
+#define NUM_LIGHTS 2
+
+layout (triangles, invocations = NUM_LIGHTS) in;
+layout (triangle_strip, max_vertices = 3) out;
+
+struct Light {
+    vec4 position;
+    vec4 color;
+    mat4 mvp;
+};
+layout (set = 0, binding = 0) uniform UBO {
+    mat4 projection;
+    mat4 model;
+    mat4 view;    
+};
+layout (set = 0, binding = 1) uniform UBOLights {
+    Light lights[NUM_LIGHTS];
+};
+
+//layout (location = 0) in int inInstanceIndex[];
+
+in gl_PerVertex
+{
+  vec4 gl_Position;
+} gl_in[];
+
+void main() 
+{
+       for (int i = 0; i < gl_in.length(); i++)
+       {
+               gl_Layer = gl_InvocationID;        
+               gl_Position = lights[gl_InvocationID].mvp * model * gl_in[i].gl_Position;        
+               EmitVertex();
+       }
+       EndPrimitive();
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/shadow.vert b/samples/glow/shaders/shadow.vert
new file mode 100644 (file)
index 0000000..32e93ca
--- /dev/null
@@ -0,0 +1,17 @@
+#version 450
+
+layout (location = 0) in vec3 inPos;
+
+layout(push_constant) uniform PushConsts {
+    mat4 model;
+} pc;
+
+out gl_PerVertex
+{
+  vec4 gl_Position;
+};
+
+void main()
+{
+       gl_Position = pc.model * vec4(inPos,1);
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/show_gbuff.frag b/samples/glow/shaders/show_gbuff.frag
new file mode 100644 (file)
index 0000000..7859e36
--- /dev/null
@@ -0,0 +1,92 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+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 = 6) uniform sampler2DArray samplerShadowMap;
+
+layout (push_constant) uniform PushCsts {
+    layout(offset = 64)
+    int imgIdx;
+};
+
+layout (location = 0) in vec2 inUV;
+layout (location = 0) out vec4 outColor;
+
+const uint color        = 0;
+const uint normal       = 1;
+const uint pos          = 2;
+const uint occlusion    = 3;
+const uint emissive     = 4;
+const uint metallic     = 5;
+const uint roughness    = 6;
+const uint depth        = 7;
+const uint prefill      = 8;
+const uint irradiance   = 9;
+const uint shadowMap    = 10;
+
+vec4 sampleCubeMap (samplerCube sc, uint face, uint lod) {
+    vec2 uv = 2.0 * inUV - vec2(1.0);
+    switch (face) {
+        case 0:
+            return vec4 (textureLod (sc, vec3(1, uv.t, uv.s), lod).rgb, 1);
+        case 1:
+            return vec4 (textureLod (sc, vec3(-1, uv.t, uv.s), lod).rgb, 1);
+        case 2:
+            return vec4 (textureLod (sc, vec3(uv.s, 1, -uv.t), lod).rgb, 1);
+        case 3:
+            return vec4 (textureLod (sc, vec3(uv.s, -1, uv.t), lod).rgb, 1);
+        case 4:
+            return vec4 (textureLod (sc, vec3(uv, 1), lod).rgb, 1);
+        case 5:
+            return vec4 (textureLod (sc, vec3(-uv.s, uv.t, -1), lod).rgb, 1);
+   }
+}
+
+void main() 
+{
+    uint imgNum = bitfieldExtract (imgIdx, 0, 8);
+    switch (imgNum) {
+        case color:
+            outColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).rgb, 1);
+            break;
+        case normal:
+            outColor = vec4(subpassLoad(samplerN_AO, gl_SampleID).rgb, 1);
+            break;
+        case pos:
+            outColor = vec4(subpassLoad(samplerPos, gl_SampleID).rgb, 1);
+            break;
+        case occlusion:
+            outColor = vec4(subpassLoad(samplerN_AO, gl_SampleID).aaa, 1);
+            break;
+        case emissive:
+            outColor = vec4(subpassLoad(samplerEmitMetal, gl_SampleID).rgb, 1);
+            break;
+        case metallic:
+            outColor = vec4(subpassLoad(samplerEmitMetal, gl_SampleID).aaa, 1);
+            break;
+        case roughness:
+            outColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).aaa, 1);
+            break;
+        case depth:
+            outColor = vec4(subpassLoad(samplerPos, gl_SampleID).aaa, 1);
+            break;
+        case shadowMap:            
+            vec3 d = texture(samplerShadowMap, vec3(inUV, bitfieldExtract (imgIdx, 8, 8))).rrr;
+            outColor = vec4(d*d*d, 1);
+            break;
+        default:
+            if (imgNum == prefill)
+                outColor = sampleCubeMap (prefilteredMap, bitfieldExtract (imgIdx, 8, 8), bitfieldExtract (imgIdx, 16, 8));            
+            else if (imgNum == irradiance)
+                outColor = sampleCubeMap (samplerIrradiance, bitfieldExtract (imgIdx, 8, 8), bitfieldExtract (imgIdx, 16, 8));            
+            break;
+    }
+}
\ No newline at end of file
diff --git a/samples/glow/shaders/simpletexture.frag b/samples/glow/shaders/simpletexture.frag
new file mode 100644 (file)
index 0000000..a081876
--- /dev/null
@@ -0,0 +1,15 @@
+#version 450
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (set = 0, binding = 0) uniform sampler2D samplerColor;
+
+layout (location = 0) in       vec2 inUV;
+
+layout (location = 0) out      vec4 outFragColor;
+
+void main()
+{    
+       outFragColor = texture(samplerColor, inUV);
+}
diff --git a/samples/glow/shaders/tone_mapping.frag b/samples/glow/shaders/tone_mapping.frag
new file mode 100644 (file)
index 0000000..98f4a69
--- /dev/null
@@ -0,0 +1,34 @@
+#include "preamble.inc"
+
+layout(push_constant) uniform PushConsts {
+       float exposure;
+       float gamma;    
+};
+
+#include "tonemap.inc"
+
+layout (set = 0, binding = 0) uniform sampler2DMS samplerHDR;
+
+layout (location = 0) in vec2 inUV;
+layout (location = 0) out vec4 outColor;
+                                                                                                         
+void main() 
+{
+               ivec2 ts = textureSize(samplerHDR);
+           vec4 hdrColor = texelFetch (samplerHDR, ivec2(gl_FragCoord.xy), gl_SampleID);
+           //vec4 hdrColor = texelFetch (samplerHDR, inUV);    
+           //vec4 c = texture (bloom, inUV);
+           //float lum = (0.299*c.r + 0.587*c.g + 0.114*c.b);
+           //if (lum>1.0)
+           //    hdrColor.rgb += c.rgb * 0.05;
+           //outColor = SRGBtoLINEAR(tonemap(hdrColor, exposure, gamma));          
+           outColor = tonemap(hdrColor, exposure, gamma);              
+    
+    
+    /*
+    outColor = vec4(SRGBtoLINEAR(tonemap(hdrColor.rgb)), hdrColor.a);;*/
+    
+/*  vec3 mapped = vec3(1.0) - exp(-hdrColor.rgb * pc.exposure);        
+    mapped = pow(mapped, vec3(1.0 / pc.gamma));
+    outColor = vec4(mapped, hdrColor.a);*/
+}
\ No newline at end of file
diff --git a/samples/glow/shadowMapRenderer.cs b/samples/glow/shadowMapRenderer.cs
new file mode 100644 (file)
index 0000000..d7eafd1
--- /dev/null
@@ -0,0 +1,159 @@
+/*shadow mapping greatly inspired from:
+* Vulkan Example - Deferred shading with shadows from multiple light sources using geometry shader instancing
+* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
+* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+*/
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using vke;
+using vke.glTF;
+using Vulkan;
+using static glow.DeferredPbrRenderer;
+
+namespace glow {
+       public class ShadowMapRenderer : IDisposable {
+               Device dev;
+               Queue gQueue;
+
+               public static uint SHADOWMAP_SIZE = 4096;
+               public static VkFormat SHADOWMAP_FORMAT = VkFormat.D32SfloatS8Uint;
+               public static VkSampleCountFlags SHADOWMAP_NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
+               public bool updateShadowMap = true;
+
+               public float depthBiasConstant = 1.5f;
+               public float depthBiasSlope = 1.75f;
+               float lightFOV = Utils.DegreesToRadians (60);
+               float lightFarPlane;
+
+
+
+               RenderPass shadowPass;
+               FrameBuffer fbShadowMap;
+               public Image shadowMap { get; private set; }
+               Pipeline shadowPipeline;
+               DescriptorPool descriptorPool;
+               DescriptorSetLayout descLayoutShadow;
+               DescriptorSet dsShadow;
+               DeferredPbrRenderer renderer;
+
+               public ShadowMapRenderer (Queue gQueue, DeferredPbrRenderer renderer, float farPlane = 16f) {
+                       this.lightFarPlane = farPlane;
+                       this.gQueue = gQueue;
+                       this.dev = gQueue.Dev;
+                       this.renderer = renderer;
+
+                       descriptorPool = new DescriptorPool (dev, 1,
+                               new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 2)
+                       );
+
+                       init ();
+               }
+
+               void init () {
+
+                       //Shadow map renderpass
+                       shadowPass = new RenderPass (dev, VkSampleCountFlags.SampleCount1);
+                       shadowPass.AddAttachment (SHADOWMAP_FORMAT, VkImageLayout.DepthStencilReadOnlyOptimal, SHADOWMAP_NUM_SAMPLES);
+                       shadowPass.ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) });
+
+                       SubPass subpass0 = new SubPass ();
+                       subpass0.SetDepthReference (0);
+                       shadowPass.AddSubpass (subpass0);
+
+                       shadowPass.AddDependency (Vk.SubpassExternal, 0,
+                               VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.EarlyFragmentTests,
+                               VkAccessFlags.ShaderRead, VkAccessFlags.DepthStencilAttachmentWrite);
+                       shadowPass.AddDependency (0, Vk.SubpassExternal,
+                               VkPipelineStageFlags.LateFragmentTests, VkPipelineStageFlags.FragmentShader,
+                               VkAccessFlags.DepthStencilAttachmentWrite, VkAccessFlags.ShaderRead);
+
+                       descLayoutShadow = new DescriptorSetLayout (dev,
+                               new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Geometry, VkDescriptorType.UniformBuffer),//matrices
+                               new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Geometry, VkDescriptorType.UniformBuffer));//lights
+
+                       GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList);
+                       cfg.rasterizationState.cullMode = VkCullModeFlags.Back;
+                       cfg.rasterizationState.depthBiasEnable = true;
+                       cfg.dynamicStates.Add (VkDynamicState.DepthBias);
+
+                       cfg.RenderPass = shadowPass;
+
+                       cfg.Layout = new PipelineLayout (dev, descLayoutShadow);
+                       cfg.Layout.AddPushConstants (
+                               new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ())
+                       );
+
+                       cfg.AddVertexBinding<PbrModelTexArray.Vertex> (0);
+                       cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat);
+
+                       using (ShaderInfo vs = new ShaderInfo (dev, VkShaderStageFlags.Vertex, "#shaders.shadow.vert.spv"))
+                       using (ShaderInfo fs = new ShaderInfo (dev, VkShaderStageFlags.Geometry, "#shaders.shadow.geom.spv")) {
+                               cfg.AddShaders (vs, fs);
+
+                               shadowPipeline = new GraphicPipeline (cfg);
+                       }
+
+                       //shadow map image
+                       shadowMap = new Image (dev, SHADOWMAP_FORMAT, VkImageUsageFlags.DepthStencilAttachment | VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, SHADOWMAP_SIZE, SHADOWMAP_SIZE,
+                               VkImageType.Image2D, SHADOWMAP_NUM_SAMPLES, VkImageTiling.Optimal, 1, (uint)renderer.lights.Length);
+                       shadowMap.CreateView (VkImageViewType.ImageView2DArray, VkImageAspectFlags.Depth, shadowMap.CreateInfo.arrayLayers);
+                       shadowMap.CreateSampler (VkSamplerAddressMode.ClampToBorder);
+                       shadowMap.Descriptor.imageLayout = VkImageLayout.DepthStencilReadOnlyOptimal;
+
+                       fbShadowMap = new FrameBuffer (shadowPass, SHADOWMAP_SIZE, SHADOWMAP_SIZE, (uint)renderer.lights.Length);
+                       fbShadowMap.attachments.Add (shadowMap);
+                       fbShadowMap.Activate ();
+
+                       dsShadow = descriptorPool.Allocate (descLayoutShadow);
+
+                       DescriptorSetWrites dsWrite = new DescriptorSetWrites (dsShadow, descLayoutShadow);
+                       dsWrite.Write (dev, renderer.uboMatrices.Descriptor, renderer.uboLights.Descriptor);
+               }
+
+               public void update_light_matrices () {
+                       Matrix4x4 proj = Utils.CreatePerspectiveFieldOfView (lightFOV, 1, 0.1f, lightFarPlane);
+                       for (int i = 0; i < renderer.lights.Length; i++) {
+                               Matrix4x4 view = Matrix4x4.CreateLookAt (renderer.lights[i].position.ToVector3 (), Vector3.Zero, Vector3.UnitY);
+                               renderer.lights[i].mvp = view * proj;
+                       }
+                       renderer.uboLights.Update (renderer.lights);
+                       dev.WaitIdle ();
+               }
+
+               public void update_shadow_map (CommandPool cmdPool) {
+                       update_light_matrices ();
+
+                       PrimaryCommandBuffer cmd = cmdPool.AllocateAndStart ();
+
+                       shadowPass.Begin (cmd, fbShadowMap);
+
+                       cmd.SetViewport (SHADOWMAP_SIZE, SHADOWMAP_SIZE);
+                       cmd.SetScissor (SHADOWMAP_SIZE, SHADOWMAP_SIZE);
+
+                       cmd.BindDescriptorSet (shadowPipeline.Layout, dsShadow);
+
+                       Vk.vkCmdSetDepthBias (cmd.Handle, depthBiasConstant, 0.0f, depthBiasSlope);
+
+                       shadowPipeline.Bind (cmd);
+
+                       if (renderer.model != null) {
+                               renderer.model.Bind (cmd);
+                               renderer.model.DrawAll (cmd, shadowPipeline.Layout, true);
+                       }
+
+                       shadowPass.End (cmd);
+
+                       gQueue.EndSubmitAndWait (cmd);
+                       updateShadowMap = false;
+               }
+
+
+               public void Dispose () {
+                       shadowPipeline?.Dispose ();
+                       fbShadowMap?.Dispose ();
+                       shadowMap?.Dispose ();
+                       descriptorPool?.Dispose ();
+               }
+       }
+}
diff --git a/samples/glow/ui/debug.crow b/samples/glow/ui/debug.crow
new file mode 100644 (file)
index 0000000..4d78bf1
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<Window Caption="Debug" Icon="#deferred.crow.svg" Left="10" Top="100" Width="40%" Height="50%">
+    <VerticalStack Spacing="1" Margin="10" CacheEnabled="true">     
+        <HorizontalStack Height="Fit">
+            <Label Text="Fps:" Width="80"/>            
+            <Label Text="{fps}" Width="Stretched" TextAlignment="Center"/>    
+        </HorizontalStack>       
+        <Expandable Caption="Debug Views">
+            <EnumSelector Left="20" EnumValue="{²CurrentDebugView}" Width="50%"/>        
+        </Expandable>
+    </VerticalStack>
+</Window>
+
diff --git a/samples/glow/ui/deferred.style b/samples/glow/ui/deferred.style
new file mode 100644 (file)
index 0000000..c21ffb6
--- /dev/null
@@ -0,0 +1,61 @@
+icon {
+       Width="14";
+       Height="14";
+}
+MemberViewLabel {
+       Margin="1";
+       Height="Fit";
+       Width="50%";
+       Background="White";
+}
+MemberViewHStack {
+       Focusable="true";
+       Height="Fit";
+       Spacing="1";
+       MouseEnter="{Background=SteelBlue}";
+       MouseLeave="{Background=Transparent}";
+}
+
+IcoBut {
+       Template = "#Crow.Coding.ui.IcoBut.template";
+       MinimumSize = "10,10";
+       Width = "8";
+       Height = "14";
+       Background = "White";
+}
+
+WinSchema {
+       Template="#Crow.Coding.ui.DockWindows.WinSchemaItem.template";
+       Focusable = "true";
+       MinimumSize="150,50";
+       Width = "Fit";
+       Height = "Fit";
+}
+TabItem {
+       AllowDrag="false";
+       Background="Jet";
+}
+TreeItemBorder {
+       CornerRadius="2";
+       Margin="0";
+       Focusable="true";
+       Height="Fit";
+       Width="Stretched";
+       Foreground="Transparent";
+       MouseEnter="{Foreground=DimGrey}";
+       MouseLeave="{Foreground=Transparent}";
+}
+TreeIcon {
+       Margin="0";
+       Width="14";
+       Height="14";
+}
+NormalizedFloat {
+    Minimum="0.0";
+    Maximum="1.0";
+    SmallIncrement="0.01";
+    LargeIncrement="0.1";
+    Decimals="2";
+    Width="60";
+    Foreground="Black";
+}
diff --git a/samples/glow/ui/main.crow b/samples/glow/ui/main.crow
new file mode 100644 (file)
index 0000000..14e6082
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<Window Caption="Lighting" Icon="#deferred.crow.svg" Left="10" Top="100" Width="40%" Height="40%" CornerRadius="10">
+    <VerticalStack Spacing="1" Margin="10" CacheEnabled="true">     
+        <HorizontalStack Height="Fit" >
+            <Label Text="Exposure:" Width="80"/>
+            <Slider Height="10" Value="{²Exposure}" Maximum="10.0" SmallIncrement="0.1" LargeIncrement="1.0"/>
+            <Label Text="{Exposure}" Width="40" TextAlignment="Right" />
+        </HorizontalStack>
+        <HorizontalStack Height="Fit">
+            <Label Text="Gamma:" Width="80" />
+            <Slider Height="10" Value="{²Gamma}" Maximum="10.0" SmallIncrement="0.1" LargeIncrement="1.0"/>
+            <Label Text="{Gamma}" Width="40" TextAlignment="Right" />
+        </HorizontalStack>
+        <HorizontalStack Height="Fit">
+            <Label Text="Light Strength:" Width="100" />
+            <Slider Height="10" Value="{²LightStrength}" Maximum="50.0" SmallIncrement="0.1" LargeIncrement="5.0"/>
+            <Label Text="{LightStrength}" Width="40" TextAlignment="Right" />
+        </HorizontalStack>
+        <ListBox Name="dv" Data="{Lights}" Width="Stretched" Height="Fit">
+            <ItemTemplate>
+                <Border Height="Fit">
+                    <VerticalStack>
+                        <HorizontalStack>
+                            <Label Text="Position" Width="50"/>
+                            <Label Text="{position}"/>
+                        </HorizontalStack>
+                        <HorizontalStack>
+                            <Label Text="Color" Width="50"/>
+                            <Label Text="{color}"/>
+                        </HorizontalStack>
+                    </VerticalStack>                    
+                </Border>                    
+            </ItemTemplate>            
+        </ListBox>        
+    </VerticalStack>
+</Window>
+
diff --git a/samples/glow/ui/materials.crow b/samples/glow/ui/materials.crow
new file mode 100644 (file)
index 0000000..b4c5432
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<Window Icon="#deferred.crow.svg" Left="10" Top="100" Width="40%" Height="40%" CornerRadius="10">
+    <VerticalStack>
+    <ListBox Data="{Materials}">
+        <ItemTemplate  DataType="PbrMaterial">
+            <VerticalStack>
+                <ColorPicker Width="260" Height="Fit"/>
+                <HorizontalStack>
+                    <Label Width="Stretched" Text="Metallic Factor"/>
+                    <Spinner Style="NormalizedFloat" Value="{²metallicFactor}"/>
+                </HorizontalStack>
+                <HorizontalStack>
+                    <Label Width="Stretched" Text="Roughness Factor"/>
+                    <Spinner Style="NormalizedFloat" Value="{²roughnessFactor}"/>
+                </HorizontalStack>
+                <HorizontalStack>
+                    <Label Width="Stretched" Text="Alpha Mask"/>
+                    <Spinner Style="NormalizedFloat" Value="{²alphaMask}"/>
+                </HorizontalStack>
+                <HorizontalStack>
+                    <Label Width="Stretched" Text="Alpha Mask Cutoff"/>
+                    <Spinner Style="NormalizedFloat" Value="{²alphaMaskCutoff}"/>            
+                </HorizontalStack>
+            </VerticalStack>
+        </ItemTemplate>        
+    </ListBox>
+    <Button Caption="Apply" MouseClick="onApplyMaterialChanges"/>
+    </VerticalStack>
+</Window>
+
diff --git a/samples/glow/ui/menu.crow b/samples/glow/ui/menu.crow
new file mode 100644 (file)
index 0000000..1cc36be
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<Menu>
+    <MenuItem Caption="View" Fit="true" PopWidth="150">
+        <MenuItem Command="{CMDViewScenes}"/>
+        <MenuItem Command="{CMDViewDebug}"/>
+        <MenuItem Command="{CMDViewEditor}"/>
+        <MenuItem Command="{CMDViewMaterials}"/>
+    </MenuItem>
+</Menu>
\ No newline at end of file
diff --git a/samples/glow/ui/sceneItem.crow b/samples/glow/ui/sceneItem.crow
new file mode 100644 (file)
index 0000000..ecb3a53
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<VerticalStack>
+    <Border Style="TreeItemBorder" MouseDoubleClick="./onClickForExpand">
+        <HorizontalStack Spacing="5">
+            <Image Margin="1" Width="10" Height="10" Focusable="true" MouseDown="./onClickForExpand"
+                Path="{./Image}"
+                Visible="{./IsExpandable}"
+                SvgSub="{./IsExpanded}"
+                MouseEnter="{Background=LightGrey}"
+                MouseLeave="{Background=Transparent}"/>
+            <Image Style="TreeIcon"
+                Path="#Crow.Icons.folder.svg" SvgSub="{./IsExpanded}"/>
+            <Label Text="{./Caption}"/>
+        </HorizontalStack>
+    </Border>
+    <Container Name="Content" Visible="false"/>
+</VerticalStack>
+
diff --git a/samples/glow/ui/scenes.crow b/samples/glow/ui/scenes.crow
new file mode 100644 (file)
index 0000000..b7f1b4f
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<Window Caption="Scenes" Icon="#deferred.crow.svg" Left="10" Top="100" Width="40%" Height="80%" CornerRadius="10">    
+        <TreeView Data="{Scenes}" Width="Stretched">
+            <ItemTemplate DataType="Scene" Data="GetNodes">
+                <Expandable Caption="{Name}" Template="#deferred.sceneItem.crow" IsExpanded="{²IsExpanded}">
+                    <HorizontalStack Height="Fit">
+                        <Widget Width="8" Height="10"/>
+                        <VerticalStack Height="Fit" Name="ItemsContainer"/>
+                    </HorizontalStack>
+                </Expandable>                
+            </ItemTemplate>
+            <ItemTemplate DataType="Node" Data="Children">
+                <Expandable Caption="Node" IsExpanded="{²IsExpanded}">
+                    <Template>
+                        <VerticalStack>
+                            <Border Style="TreeItemBorder" MouseDoubleClick="./onClickForExpand">
+                                <HorizontalStack Spacing="5">
+                                    <Image Margin="1" Width="10" Height="10" Focusable="true" MouseDown="./onClickForExpand"
+                                        Path="{./Image}"
+                                        Visible="{./IsExpandable}"
+                                        SvgSub="{./IsExpanded}"
+                                        MouseEnter="{Background=LightGrey}"
+                                        MouseLeave="{Background=Transparent}"/>
+                                    <Image Style="TreeIcon"
+                                        Path="#Crow.Icons.folder.svg" SvgSub="{./IsExpanded}"/>
+                                    <Label Text="{./Caption}"/>
+                                    <Label DataSource="{Mesh}" Text="{Name}"/>
+                                </HorizontalStack>
+                            </Border>
+                            <Container Name="Content" Visible="false"/>
+                        </VerticalStack>                        
+                    </Template>>
+                    <HorizontalStack Height="Fit">
+                        <Widget Width="8" Height="10"/>
+                        <VerticalStack Height="Fit" Name="ItemsContainer"/>                    
+                    </HorizontalStack>
+                </Expandable>                
+            </ItemTemplate>
+        </TreeView>           
+</Window>
+
diff --git a/samples/glow/ui/testImage.crow b/samples/glow/ui/testImage.crow
new file mode 100644 (file)
index 0000000..c245e14
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<EnumSelector Height="300" EnumValue="{²CurrentDebugView}"/>
+
index 475e6288389a65d55a4a8465a45ae9d12ebad69d..084c27ea8e1fe97c3ee1336dc05438f975abba06 100644 (file)
@@ -47,6 +47,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "deferred", "samples\deferre
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "pbr", "samples\pbr\pbr.csproj", "{7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "glow", "samples\glow\glow.csproj", "{82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "crowWin", "samples\crowWin\crowWin.csproj", "{A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrowWindow", "addons\CrowWindow\CrowWindow.csproj", "{5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -171,6 +177,36 @@ Global
                {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
                {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
                {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.Release|Any CPU.Build.0 = Release|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.DebugCrow|Any CPU.ActiveCfg = DebugCrow|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.DebugCrow|Any CPU.Build.0 = DebugCrow|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.Release|Any CPU.Build.0 = Release|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.Release|Any CPU.Build.0 = Release|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
        EndGlobalSection
        GlobalSection(NestedProjects) = preSolution
                {FEF3AF30-5B88-4D3C-8BD7-8734200E0D1E} = {4AA67AB0-C331-4CB2-9C00-B74F5DE31658}
@@ -186,6 +222,9 @@ Global
                {124152F8-FAE6-4D4B-87B9-6074DD365E9B} = {16439374-B8DB-4643-8116-EB3358B49A12}
                {7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5} = {16439374-B8DB-4643-8116-EB3358B49A12}
                {1D2A1968-8F04-4BE0-B03A-573F1F68AB66} = {16439374-B8DB-4643-8116-EB3358B49A12}
+               {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE} = {16439374-B8DB-4643-8116-EB3358B49A12}
+               {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536} = {16439374-B8DB-4643-8116-EB3358B49A12}
+               {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D} = {4AA67AB0-C331-4CB2-9C00-B74F5DE31658}
        EndGlobalSection
        GlobalSection(MonoDevelopProperties) = preSolution
                Policies = $0
index e6ab58e25f7d41200343d9dac3c16b8cac861ff9..6b1b0f73d5abe121c71d3a26986e7d74b225a920 100644 (file)
@@ -168,36 +168,15 @@ namespace vke {
                #endregion
 
                #region shaderc
+
+
                public static ShaderInfo CreateShaderInfo (this shaderc.Compiler comp, Device dev, string shaderPath, shaderc.ShaderKind shaderKind,
                        SpecializationInfo specializationInfo = null, string entryPoint = "main") {
 
                        using (shaderc.Result res = comp.Compile (shaderPath, shaderKind)) {
-                               Console.WriteLine ($"SpirV generation: {shaderPath} {res.Status}");
                                if (res.Status != shaderc.Status.Success) 
                                        throw new Exception ($"Shaderc compilation failure: {res.ErrorMessage}");
-                               VkShaderStageFlags stageFlags;
-                               switch (shaderKind) {
-                               case shaderc.ShaderKind.VertexShader:
-                                       stageFlags = VkShaderStageFlags.Vertex;
-                                       break;
-                               case shaderc.ShaderKind.FragmentShader:
-                                       stageFlags = VkShaderStageFlags.Fragment;
-                                       break;
-                               case shaderc.ShaderKind.ComputeShader:
-                                       stageFlags = VkShaderStageFlags.Compute;
-                                       break;
-                               case shaderc.ShaderKind.GeometryShader:
-                                       stageFlags = VkShaderStageFlags.Geometry;
-                                       break;
-                               case shaderc.ShaderKind.TessControlShader:
-                                       stageFlags = VkShaderStageFlags.TessellationControl;
-                                       break;
-                               case shaderc.ShaderKind.TessEvaluationShader:
-                                       stageFlags = VkShaderStageFlags.TessellationEvaluation;
-                                       break;
-                               default:
-                                       throw new NotSupportedException ($"shaderc compilation: shaderKind {shaderKind} not handled");
-                               }
+                               VkShaderStageFlags stageFlags = Utils.ShaderKindToStageFlag (shaderKind);
                                return new ShaderInfo (dev, stageFlags, res.CodePointer, (UIntPtr)res.CodeLength, specializationInfo, entryPoint);
                        }
                }
index 9792dd8f728953bb5abeecf46ab7101595552194..57f39742d4722aaf07850a7a1940d771a0debc50 100644 (file)
@@ -11,8 +11,19 @@ namespace vke {
        public class ShaderInfo : IDisposable {
                readonly FixedUtf8String EntryPoint;
 
-               internal VkPipelineShaderStageCreateInfo info = VkPipelineShaderStageCreateInfo.New ();
-               Device dev;
+               protected VkPipelineShaderStageCreateInfo info = VkPipelineShaderStageCreateInfo.New ();
+               protected Device dev;
+
+               public VkShaderStageFlags Stage => info.stage;
+               public VkPipelineShaderStageCreateInfo Info => info;
+
+               public void RecreateModule(IntPtr code, UIntPtr codeSize) {
+                       if (dev == null)
+                               throw new Exception ("[ShaderInfo]Trying to recreate unowned shader module.");
+                       dev.DestroyShaderModule (info.module);
+                       info.module = dev.CreateShaderModule (code, codeSize);
+               }
+
                /// <summary>
                /// Create a new 'ShaderInfo' object by providing a handle to an native memory holding the compiled SpirV code
                /// and its size in byte.
index 0e4db152330fbf535705e07f29482ee51d2778ad..0a188184e34959a5f4c72fe715f95b3aaa4358ee 100644 (file)
@@ -399,5 +399,88 @@ namespace Vulkan {
                                0, 0, zNear * zFar / (zNear - zFar), 0
                        );
                }
+
+               public static VkShaderStageFlags ShaderKindToStageFlag (shaderc.ShaderKind shaderKind) {
+                       switch (shaderKind) {
+                       case shaderc.ShaderKind.VertexShader:
+                       case shaderc.ShaderKind.GlslDefaultVertexShader:
+                               return VkShaderStageFlags.Vertex;
+                       case shaderc.ShaderKind.FragmentShader:
+                       case shaderc.ShaderKind.GlslDefaultFragmentShader:
+                               return VkShaderStageFlags.Fragment;
+                       case shaderc.ShaderKind.ComputeShader:
+                       case shaderc.ShaderKind.GlslDefaultComputeShader:
+                               return VkShaderStageFlags.Compute;
+                       case shaderc.ShaderKind.GeometryShader:
+                       case shaderc.ShaderKind.GlslDefaultGeometryShader:
+                               return VkShaderStageFlags.Geometry;
+                       case shaderc.ShaderKind.TessControlShader:
+                       case shaderc.ShaderKind.GlslDefaultTessControlShader:
+                               return VkShaderStageFlags.TessellationControl;
+                       case shaderc.ShaderKind.TessEvaluationShader:
+                       case shaderc.ShaderKind.GlslDefaultTessEvaluationShader:
+                               return VkShaderStageFlags.TessellationEvaluation;
+                       case shaderc.ShaderKind.RaygenShader:
+                       case shaderc.ShaderKind.GlslDefaultRaygenShader:
+                               return VkShaderStageFlags.RaygenKHR;
+                       case shaderc.ShaderKind.AnyhitShader:
+                       case shaderc.ShaderKind.GlslDefaultAnyhitShader:
+                               return VkShaderStageFlags.AnyHitKHR;
+                       case shaderc.ShaderKind.ClosesthitShader:
+                       case shaderc.ShaderKind.GlslDefaultClosesthitShader:
+                               return VkShaderStageFlags.ClosestHitKHR;
+                       case shaderc.ShaderKind.MissShader:
+                       case shaderc.ShaderKind.GlslDefaultMissShader:
+                               return VkShaderStageFlags.MissKHR;
+                       case shaderc.ShaderKind.IntersectionShader:
+                       case shaderc.ShaderKind.GlslDefaultIntersectionShader:
+                               return VkShaderStageFlags.IntersectionKHR;
+                       case shaderc.ShaderKind.CallableShader:
+                       case shaderc.ShaderKind.GlslDefaultCallableShader:
+                               return VkShaderStageFlags.CallableKHR;
+                       case shaderc.ShaderKind.TaskShader:
+                       case shaderc.ShaderKind.GlslDefaultTaskShader:
+                               return VkShaderStageFlags.TaskNV;
+                       case shaderc.ShaderKind.MeshShader:
+                       case shaderc.ShaderKind.GlslDefaultMeshShader:
+                               return VkShaderStageFlags.MeshNV;
+                       default:
+                               throw new NotSupportedException ($"shaderc shaderKind {shaderKind} conversion to VK StageFlag  not handled");
+                       }
+               }
+               public static shaderc.ShaderKind ShaderStageToShaderKind (VkShaderStageFlags stageFlag) {
+                       switch (stageFlag) {
+                       case VkShaderStageFlags.Vertex:
+                               return shaderc.ShaderKind.VertexShader;
+                       case VkShaderStageFlags.TessellationControl:
+                               return shaderc.ShaderKind.TessControlShader;
+                       case VkShaderStageFlags.TessellationEvaluation:
+                               return shaderc.ShaderKind.TessEvaluationShader;
+                       case VkShaderStageFlags.Geometry:
+                               return shaderc.ShaderKind.GeometryShader;
+                       case VkShaderStageFlags.Fragment:
+                               return shaderc.ShaderKind.FragmentShader;
+                       case VkShaderStageFlags.Compute:
+                               return shaderc.ShaderKind.ComputeShader;
+                       case VkShaderStageFlags.RaygenKHR:
+                               return shaderc.ShaderKind.RaygenShader;
+                       case VkShaderStageFlags.AnyHitKHR:
+                               return shaderc.ShaderKind.AnyhitShader;
+                       case VkShaderStageFlags.ClosestHitKHR:
+                               return shaderc.ShaderKind.ClosesthitShader;
+                       case VkShaderStageFlags.MissKHR:
+                               return shaderc.ShaderKind.MissShader;
+                       case VkShaderStageFlags.IntersectionKHR:
+                               return shaderc.ShaderKind.IntersectionShader;
+                       case VkShaderStageFlags.CallableKHR:
+                               return shaderc.ShaderKind.CallableShader;
+                       case VkShaderStageFlags.TaskNV:
+                               return shaderc.ShaderKind.TaskShader;
+                       case VkShaderStageFlags.MeshNV:
+                               return shaderc.ShaderKind.MeshShader;
+                       default:
+                               throw new NotSupportedException ($"Error Shader Stage flag conversion to ShaderKind: {stageFlag}");
+                       }
+               }
        }
 }
index 5735e3f3440058aac3ccc8eda91bb906cea6c775..1d61ad8710a4f0643995891a0babdaf54bcfe365 100644 (file)
@@ -34,7 +34,7 @@ namespace vke {
                                using (ShaderInfo shader = new ShaderInfo (Dev, VkShaderStageFlags.Compute, SpirVPath)) {
                                        VkComputePipelineCreateInfo info = VkComputePipelineCreateInfo.New ();
                                        info.layout = layout.Handle;
-                                       info.stage = shader.info;
+                                       info.stage = shader.Info;
                                        info.basePipelineHandle = 0;
                                        info.basePipelineIndex = 0;
 
index 2e2d4edb16a62fc35dfc6335c6304c1c33533237..81da69c8c21ed89d409e7e137942161d3e0bd66e 100644 (file)
@@ -44,7 +44,7 @@ namespace vke {
 
                                List<VkPipelineShaderStageCreateInfo> shaderStages = new List<VkPipelineShaderStageCreateInfo> ();
                                foreach (ShaderInfo shader in cfg.Shaders)
-                                       shaderStages.Add (shader.info);
+                                       shaderStages.Add (shader.Info);
 
                                using (PinnedObjects pctx = new PinnedObjects ()) {
 
index 8da99ec013173cc3c9d324647b5267b6dec927ba..0cd0e982875bee2904500a9a5a8de10652051a32 100644 (file)
@@ -54,8 +54,8 @@ namespace vke {
                        memory = memoryPool.vkMemory,
                        offset = poolOffset,
 #else
-                               memory = vkMemory,
-                               offset = 0,
+                       memory = vkMemory,
+                       offset = 0,
 #endif
                        size = AllocatedDeviceMemorySize
                };
index a4385366cdc24c750619b8c1c446137155925970..14199d96104515a1dc63539b8cd255e40eaf46ab 100644 (file)
                <DebugType>full</DebugType>
                <Optimize>false</Optimize>
                <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
-               <DefineConstants>MEMORY_POOLS;NETSTANDARD;NETSTANDARD2_0;DEBUG</DefineConstants>
+               <DefineConstants>_MEMORY_POOLS;NETSTANDARD;NETSTANDARD2_0;DEBUG</DefineConstants>
        </PropertyGroup>
        
        <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
                <Optimize>true</Optimize>
-               <DefineConstants>MEMORY_POOLS;NETSTANDARD;NETSTANDARD2_0</DefineConstants>
+               <DefineConstants>_MEMORY_POOLS;NETSTANDARD;NETSTANDARD2_0</DefineConstants>
        </PropertyGroup>
        
        <ItemGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
@@ -56,9 +56,9 @@
                
        <ItemGroup>
                <PackageReference Include="SpirVTasks" Version="$(SpirVTasksPackageVersion)" />
-               <PackageReference Include="Vulkan" Version="0.2.20-beta" />
+               <PackageReference Include="Vulkan" Version="0.2.2.2-beta" />
                <PackageReference Include="shaderc.net" Version="0.1.0" />
-               <PackageReference Include="glfw-sharp" Version="0.2.3.4" />
+               <PackageReference Include="glfw-sharp" Version="0.2.5" />
        </ItemGroup>
        <ItemGroup>
                <GLSLShader Include="shaders\**\*.frag;shaders\**\*.vert;shaders\**\*.comp;shaders\**\*.geom" />