From: Jean-Philippe Bruyère Date: Sun, 9 Oct 2022 16:34:18 +0000 (+0200) Subject: stroker first tests X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=fee539104ee2e982069a02ee757b58ab09b17259;p=jp%2Fvke.net.git stroker first tests --- diff --git a/samples/compute/compute.csproj b/samples/compute/compute.csproj index 30c6b43..245ffe5 100644 --- a/samples/compute/compute.csproj +++ b/samples/compute/compute.csproj @@ -4,6 +4,6 @@ - + \ No newline at end of file diff --git a/samples/compute/shaders/stroker.comp b/samples/compute/shaders/stroker.comp new file mode 100644 index 0000000..d7a570a --- /dev/null +++ b/samples/compute/shaders/stroker.comp @@ -0,0 +1,50 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_EXT_shader_16bit_storage : require + +layout(binding = 0) buffer readonly path { + vec2 pointsIn[]; +}; + +layout(binding = 1) buffer writeonly vertices { + vec2 vbo[]; +}; +layout(binding = 2) buffer writeonly indices { + uint16_t ibo[]; +}; + +layout(push_constant) uniform PushConsts { + float halfWidth; +}; + + +layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + + +void main() +{ + + if (gl_GlobalInvocationID.x > 0) { + vec2 p0 = pointsIn[gl_GlobalInvocationID.x - 1]; + vec2 p1 = pointsIn[gl_GlobalInvocationID.x]; + vec2 n = normalize(p1 - p0); + vec2 v = halfWidth * vec2(-n.y, n.x); + + uint pV = (gl_GlobalInvocationID.x - 1) * 4; + uint pI = (gl_GlobalInvocationID.x - 1) * 6; + + vbo[pV] = p0 + v; + vbo[pV+1] = p0 - v; + vbo[pV+2] = p1 + v; + vbo[pV+3] = p1 - v; + + ibo[pI] = uint16_t(pV); + ibo[pI+1] = uint16_t(pV+2); + ibo[pI+2] = uint16_t(pV+1); + ibo[pI+3] = uint16_t(pV+2); + ibo[pI+4] = uint16_t(pV+3); + ibo[pI+5] = uint16_t(pV+1); + } + +} diff --git a/samples/compute/shaders/stroker.frag b/samples/compute/shaders/stroker.frag new file mode 100644 index 0000000..82b78a4 --- /dev/null +++ b/samples/compute/shaders/stroker.frag @@ -0,0 +1,11 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + outFragColor = vec4(1.0, 0.5, 0.0, 1.0); +} \ No newline at end of file diff --git a/samples/compute/shaders/stroker.vert b/samples/compute/shaders/stroker.vert new file mode 100644 index 0000000..993dee4 --- /dev/null +++ b/samples/compute/shaders/stroker.vert @@ -0,0 +1,21 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec2 inPos; + +layout(push_constant) uniform PushConsts { + vec2 size; +}; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + + +void main() +{ + gl_Position = vec4(inPos.xy * vec2(2) / size - vec2(1), 0.0, 1.0); +} diff --git a/samples/compute/stroker.cs b/samples/compute/stroker.cs new file mode 100644 index 0000000..2533a5f --- /dev/null +++ b/samples/compute/stroker.cs @@ -0,0 +1,288 @@ +using System; +using Glfw; +using Vulkan; +using vke; +using Image = vke.Image; + +using System.Numerics; +using System.Runtime.InteropServices; + +namespace delaunay { + class Program : VkWindow { +#if DEBUG + public override string[] EnabledLayers => + new string[] { + "VK_LAYER_KHRONOS_validation" + ,"VK_LAYER_RENDERDOC_Capture" + }; + +#endif + public override string[] EnabledInstanceExtensions => new string[] { + Ext.I.VK_EXT_debug_utils, + }; + public override string[] EnabledDeviceExtensions => new string[] { + Ext.D.VK_KHR_swapchain, + Ext.D.VK_AMD_shader_info + }; + Program() : base ("Stroker", 800, 600, false) { + + } + static void Main (string[] args) { + using (Program vke = new Program ()) { + vke.Run (); + } + } + + FrameBuffers frameBuffers; + GraphicPipeline grPipeline; + ComputePipeline plStroke; + Queue computeQ, transferQ; + + HostBuffer pathBuff; + Vector2[] path; + GPUBuffer vbo, ibo; + DescriptorPool dsPool; + DescriptorSetLayout dslStroke; + DescriptorSet dsetStroke; + + + uint zoom = 2; + int invocationCount = 8; + + uint pointCount = 0; + uint maxPointCount = 256; + int curPoint = - 1, hoverPoint = -1; + float lineWidth = 10f; + + const int primitiveSize = 2; + + void addPoint(float x, float y) { + if (pointCount < maxPointCount) { + path[pointCount++] = new Vector2(x,y); + } + } + void addPoint(Vector2 p) { + if (pointCount < maxPointCount) { + path[pointCount++] = p; + } + } + + protected override void initVulkan () { + base.initVulkan (); + + path = new Vector2[maxPointCount]; + + addPoint(50,50); + addPoint(100,150); + addPoint(150,60); + /*addPoint(200,100); + addPoint(300,200);*/ + + pathBuff = new HostBuffer(dev, VkBufferUsageFlags.StorageBuffer, path, true); + + vbo = new GPUBuffer (dev, VkBufferUsageFlags.StorageBuffer | VkBufferUsageFlags.VertexBuffer, (int)(maxPointCount - 1) * 4); + ibo = new GPUBuffer (dev, VkBufferUsageFlags.StorageBuffer | VkBufferUsageFlags.IndexBuffer, (int)(maxPointCount - 1) * 6); + pathBuff.SetName("path"); + vbo.SetName("vbo"); + ibo.SetName("ibo"); + + dsPool = new DescriptorPool (dev, 1, + new VkDescriptorPoolSize (VkDescriptorType.StorageBuffer, 3)); + dslStroke = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Compute, VkDescriptorType.StorageBuffer), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Compute, VkDescriptorType.StorageBuffer), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Compute, VkDescriptorType.StorageBuffer) + ); + + using (GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount8, false)) { + cfg.Layout = new PipelineLayout (dev, new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf())); + cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, VkSampleCountFlags.SampleCount8); + cfg.RenderPass.ClearValues[0] = new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.1f) }; + + cfg.AddVertexBinding (0); + cfg.AddVertexAttributes (0, VkFormat.R32g32Sfloat);//2d position + + cfg.AddShaders ( + new ShaderInfo (dev, VkShaderStageFlags.Vertex, "#shaders.stroker.vert.spv"), + new ShaderInfo (dev, VkShaderStageFlags.Fragment, "#shaders.stroker.frag.spv") + ); + + grPipeline = new GraphicPipeline (cfg); + } + + plStroke = new ComputePipeline ( + new PipelineLayout (dev, new VkPushConstantRange (VkShaderStageFlags.Compute, sizeof (float)), dslStroke), + "#shaders.stroker.comp.spv"); + + dsetStroke = dsPool.Allocate (dslStroke); + + DescriptorSetWrites dsUpdate = new DescriptorSetWrites (dsetStroke, dslStroke); + dsUpdate.Write (dev, pathBuff.Descriptor, vbo.Descriptor, ibo.Descriptor); + + UpdateFrequency = 1; + + cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount); + } + + protected override void createQueues () { + computeQ = new Queue (dev, VkQueueFlags.Compute); + transferQ = new Queue (dev, VkQueueFlags.Transfer); + + base.createQueues (); + } + bool rebuildBuffers = false; + + void buildCommandBuffers() { + cmdPool.Reset (VkCommandPoolResetFlags.ReleaseResources); + + for (int i = 0; i < swapChain.ImageCount; ++i) { + FrameBuffer fb = frameBuffers[i]; + cmds[i].Start (); + + grPipeline.RenderPass.Begin (cmds[i], fb); + + cmds[i].SetViewport (swapChain.Width, swapChain.Height); + cmds[i].SetScissor (swapChain.Width, swapChain.Height); + + cmds[i].BindPipeline (grPipeline); + cmds[i].PushConstant (grPipeline.Layout, VkShaderStageFlags.Vertex, new Vector2(swapChain.Width, swapChain.Height)); + + cmds[i].BindVertexBuffer (vbo); + cmds[i].BindIndexBuffer (ibo, VkIndexType.Uint16); + cmds[i].DrawIndexed ((uint)(pointCount - 1) * 6); + + grPipeline.RenderPass.End (cmds[i]); + + cmds[i].End (); + } + } + + public override void Update () { + + using (CommandPool cmdPoolCompute = new CommandPool (dev, computeQ.qFamIndex)) { + + PrimaryCommandBuffer cmd = cmdPoolCompute.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); + + plStroke.Bind (cmd); + plStroke.BindDescriptorSet (cmd, dsetStroke); + cmd.PushConstant (plStroke.Layout, VkShaderStageFlags.Compute, lineWidth * 0.5f); + cmd.Dispatch (pointCount); + cmd.End (); + computeQ.Submit (cmd); + dev.WaitIdle(); + } + if (rebuildBuffers) { + buildCommandBuffers(); + rebuildBuffers = false; + } + } + protected override void OnResize () { + base.OnResize (); + + dev.WaitIdle(); + + frameBuffers?.Dispose(); + frameBuffers = grPipeline.RenderPass.CreateFrameBuffers(swapChain); + + buildCommandBuffers (); + } + protected override void Dispose (bool disposing) { + if (disposing) { + if (!isDisposed) { + dev.WaitIdle (); + + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i]?.Dispose (); + + grPipeline.Dispose (); + plStroke.Dispose (); + + dslStroke.Dispose (); + dsPool.Dispose (); + + pathBuff.Dispose (); + vbo.Dispose (); + ibo.Dispose (); + } + } + + base.Dispose (disposing); + } + + protected override void onKeyDown(Key key, int scanCode, Modifier modifiers) + { + switch(key) { + case Key.F3: + if (phy.GetDeviceExtensionSupported (Ext.D.VK_AMD_shader_info)) + printAMDStats(); + break; + case Key.KeypadAdd: + lineWidth *= 2.0f; + rebuildBuffers = true; + break; + case Key.KeypadSubtract: + lineWidth /= 2.0f; + rebuildBuffers = true; + break; + default: + base.onKeyDown(key, scanCode, modifiers); + break; + } + } + Vector2 curMousePos; + const float pointSizeSquared = 10; + protected override async void onMouseMove(double xPos, double yPos) + { + base.onMouseMove(xPos, yPos); + + curMousePos = new Vector2((float)xPos, (float)yPos); + + if (curPoint < 0) { + for (int i = 0; i < pointCount; i++) + { + if (Vector2.DistanceSquared(curMousePos, path[i]) < pointSizeSquared) { + hoverPoint = i; + return; + } + } + hoverPoint = -1; + } else { + path[curPoint] = curMousePos; + pathBuff.Update((uint)curPoint, path[curPoint]); + } + } + protected override void onMouseButtonDown(MouseButton button, Modifier mods) + { + if (hoverPoint < 0) { + addPoint(curMousePos); + pathBuff.Update(pointCount - 1, path[pointCount - 1]); + rebuildBuffers = true; + } else { + curPoint = hoverPoint; + } + } + protected override void onMouseButtonUp(MouseButton button, Modifier mods) + { + curPoint = -1; + } + void printAMDStats() { + VkShaderStatisticsInfoAMD stats = new VkShaderStatisticsInfoAMD(); + + Vk.vkGetShaderInfoAMD(dev.Handle, plStroke.Handle, VkShaderStageFlags.Compute, VkShaderInfoTypeAMD.StatisticsAMD, + out UIntPtr statSize, IntPtr.Zero); + + IntPtr statSize2 = (IntPtr)Marshal.SizeOf(); + + Vk.vkGetShaderInfoAMD(dev.Handle, plStroke.Handle, VkShaderStageFlags.Compute, VkShaderInfoTypeAMD.StatisticsAMD, + (IntPtr)(statSize.ToUInt64()), stats.Pin()); + + stats.Unpin(); + + Console.WriteLine ($"AMD Statistics"); + Console.WriteLine ($"=============="); + Console.WriteLine ($"Sgprs: {stats.resourceUsage.numUsedSgprs} / Avail:{stats.numAvailableSgprs} Phy:{stats.numPhysicalSgprs}"); + Console.WriteLine ($"Vgprs: {stats.resourceUsage.numUsedVgprs} / Avail:{stats.numAvailableVgprs} Phy:{stats.numPhysicalVgprs}"); + Console.WriteLine ($"_________________________________________________________________"); + } + } +}