diff --git a/src/Engine.Graphics.Vulkan/Shaders/triangle.vert b/src/Engine.Graphics.Vulkan/Shaders/triangle.vert index ef6021e..7519551 100644 --- a/src/Engine.Graphics.Vulkan/Shaders/triangle.vert +++ b/src/Engine.Graphics.Vulkan/Shaders/triangle.vert @@ -6,7 +6,22 @@ layout(location = 2) in vec3 inNormal; layout(location = 0) out vec3 fragColor; +layout(row_major, set = 0, binding = 0) uniform CameraUBO { + mat4 vp; +}; + +layout(push_constant) uniform PC { + float angle; +} pc; + void main() { - gl_Position = vec4(inPosition, 1.0); + float c = cos(pc.angle); + float s = sin(pc.angle); + vec3 rotated = vec3( + inPosition.x * c - inPosition.y * s, + inPosition.x * s + inPosition.y * c, + inPosition.z + ); + gl_Position = vp * vec4(rotated, 1.0); fragColor = inColor; } diff --git a/src/Engine.Graphics.Vulkan/Shaders/triangle.vert.spv b/src/Engine.Graphics.Vulkan/Shaders/triangle.vert.spv index fd38ea1..c1afffd 100644 Binary files a/src/Engine.Graphics.Vulkan/Shaders/triangle.vert.spv and b/src/Engine.Graphics.Vulkan/Shaders/triangle.vert.spv differ diff --git a/src/Engine.Graphics.Vulkan/Vk.cs b/src/Engine.Graphics.Vulkan/Vk.cs index 286aaaa..6cffbec 100644 --- a/src/Engine.Graphics.Vulkan/Vk.cs +++ b/src/Engine.Graphics.Vulkan/Vk.cs @@ -62,6 +62,14 @@ internal static unsafe class Vk public delegate void VkCmdEndRendering(VkCommandBuffer commandBuffer); public delegate void VkCmdPipelineBarrier2(VkCommandBuffer commandBuffer, VkDependencyInfo* pDependencyInfo); public delegate void VkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint regionCount, VkBufferCopy* pRegions); + public delegate void VkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint offset, uint size, void* pValues); + public delegate void VkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint firstSet, uint descriptorSetCount, VkDescriptorSet* pDescriptorSets, uint dynamicOffsetCount, uint* pDynamicOffsets); + public delegate VkResult VkCreateDescriptorSetLayout(VkDevice device, VkDescriptorSetLayoutCreateInfo* pCreateInfo, nint pAllocator, VkDescriptorSetLayout* pSetLayout); + public delegate void VkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, nint pAllocator); + public delegate VkResult VkCreateDescriptorPool(VkDevice device, VkDescriptorPoolCreateInfo* pCreateInfo, nint pAllocator, VkDescriptorPool* pDescriptorPool); + public delegate void VkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, nint pAllocator); + public delegate VkResult VkAllocateDescriptorSets(VkDevice device, VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); + public delegate void VkUpdateDescriptorSets(VkDevice device, uint descriptorWriteCount, VkWriteDescriptorSet* pDescriptorWrites, uint descriptorCopyCount, nint pDescriptorCopies); public delegate VkResult VkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, ulong timeout, VkSemaphore semaphore, VkFence fence, uint* pImageIndex); public delegate VkResult VkQueueSubmit2(VkQueue queue, uint submitCount, VkSubmitInfo2* pSubmits, VkFence fence); public delegate VkResult VkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo); @@ -129,6 +137,14 @@ internal static unsafe class Vk public static VkCmdEndRendering vkCmdEndRendering; public static VkCmdPipelineBarrier2 vkCmdPipelineBarrier2; public static VkCmdCopyBuffer vkCmdCopyBuffer; + public static VkCmdPushConstants vkCmdPushConstants; + public static VkCmdBindDescriptorSets vkCmdBindDescriptorSets; + public static VkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; + public static VkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; + public static VkCreateDescriptorPool vkCreateDescriptorPool; + public static VkDestroyDescriptorPool vkDestroyDescriptorPool; + public static VkAllocateDescriptorSets vkAllocateDescriptorSets; + public static VkUpdateDescriptorSets vkUpdateDescriptorSets; public static VkAcquireNextImageKHR vkAcquireNextImageKHR; public static VkQueueSubmit2 vkQueueSubmit2; public static VkQueuePresentKHR vkQueuePresentKHR; @@ -203,6 +219,14 @@ internal static unsafe class Vk vkCmdEndRendering = LoadDev(p, "vkCmdEndRendering"); vkCmdPipelineBarrier2 = LoadDev(p, "vkCmdPipelineBarrier2"); vkCmdCopyBuffer = LoadDev(p, "vkCmdCopyBuffer"); + vkCmdPushConstants = LoadDev(p, "vkCmdPushConstants"); + vkCmdBindDescriptorSets = LoadDev(p, "vkCmdBindDescriptorSets"); + vkCreateDescriptorSetLayout = LoadDev(p, "vkCreateDescriptorSetLayout"); + vkDestroyDescriptorSetLayout = LoadDev(p, "vkDestroyDescriptorSetLayout"); + vkCreateDescriptorPool = LoadDev(p, "vkCreateDescriptorPool"); + vkDestroyDescriptorPool = LoadDev(p, "vkDestroyDescriptorPool"); + vkAllocateDescriptorSets = LoadDev(p, "vkAllocateDescriptorSets"); + vkUpdateDescriptorSets = LoadDev(p, "vkUpdateDescriptorSets"); vkAcquireNextImageKHR = LoadDev(p, "vkAcquireNextImageKHR"); vkQueueSubmit2 = LoadDev(p, "vkQueueSubmit2"); vkQueuePresentKHR = LoadDev(p, "vkQueuePresentKHR"); diff --git a/src/Engine.Graphics.Vulkan/VulkanContext.cs b/src/Engine.Graphics.Vulkan/VulkanContext.cs index 51dd16e..59ecd41 100644 --- a/src/Engine.Graphics.Vulkan/VulkanContext.cs +++ b/src/Engine.Graphics.Vulkan/VulkanContext.cs @@ -241,12 +241,13 @@ internal sealed unsafe class VulkanContext : IDisposable var nameLen = Array.IndexOf(nameBytes, (byte)0); if (nameLen < 0) nameLen = 256; var devType = (VkPhysicalDeviceType)Marshal.ReadInt32((nint)propsBytes, 16); - Console.WriteLine($"[Vulkan] GPU {i}: {System.Text.Encoding.UTF8.GetString(nameBytes, 0, nameLen)} (type={devType})"); + var gpuName = System.Text.Encoding.UTF8.GetString(nameBytes, 0, nameLen); if (best.Handle == 0 || (devType == VkPhysicalDeviceType.DiscreteGpu && bestType != VkPhysicalDeviceType.DiscreteGpu)) { best = devices[(int)i]; bestType = devType; + Console.WriteLine($"[Vulkan] Selected GPU: {gpuName} (type={devType})"); } } @@ -373,7 +374,6 @@ internal sealed unsafe class VulkanContext : IDisposable SurfaceColorSpace = formats[0].colorSpace; } - Console.WriteLine($"[Vulkan] Surface format: {SurfaceFormat}, color space: {SurfaceColorSpace}"); } public uint FindMemoryType(uint memoryTypeBits, VkMemoryPropertyFlags desiredFlags) diff --git a/src/Engine.Graphics.Vulkan/VulkanEnums.cs b/src/Engine.Graphics.Vulkan/VulkanEnums.cs index 47cfa7a..90fabd5 100644 --- a/src/Engine.Graphics.Vulkan/VulkanEnums.cs +++ b/src/Engine.Graphics.Vulkan/VulkanEnums.cs @@ -39,6 +39,10 @@ public enum VkStructureType : int MemoryAllocateInfo = 5, BufferCreateInfo = 12, ShaderModuleCreateInfo = 16, + DescriptorSetLayoutCreateInfo = 32, + DescriptorPoolCreateInfo = 33, + DescriptorSetAllocateInfo = 34, + WriteDescriptorSet = 35, PipelineShaderStageCreateInfo = 18, PipelineVertexInputStateCreateInfo = 19, PipelineInputAssemblyStateCreateInfo = 20, diff --git a/src/Engine.Graphics.Vulkan/VulkanFrameResources.cs b/src/Engine.Graphics.Vulkan/VulkanFrameResources.cs index 6b0006c..229f830 100644 --- a/src/Engine.Graphics.Vulkan/VulkanFrameResources.cs +++ b/src/Engine.Graphics.Vulkan/VulkanFrameResources.cs @@ -1,8 +1,11 @@ +using System.Runtime.InteropServices; + namespace Engine.Graphics.Vulkan; internal sealed unsafe class VulkanFrameResources : IDisposable { public const int MaxFramesInFlight = 2; + public const ulong UboSize = 64; public VkCommandPool CommandPool; public VkCommandBuffer[] CommandBuffers = new VkCommandBuffer[MaxFramesInFlight]; @@ -10,10 +13,17 @@ internal sealed unsafe class VulkanFrameResources : IDisposable public VkSemaphore[] AcquireSemaphores = new VkSemaphore[MaxFramesInFlight]; public VkSemaphore[] SubmitSemaphores = Array.Empty(); + public VkBuffer[] UboBuffers = new VkBuffer[MaxFramesInFlight]; + public VkDeviceMemory[] UboMemories = new VkDeviceMemory[MaxFramesInFlight]; + public VkDescriptorSet[] DescriptorSets = new VkDescriptorSet[MaxFramesInFlight]; + + public VkDescriptorPool DescriptorPool; + private readonly VkDevice _device; private bool _disposed; - public VulkanFrameResources(VkDevice device, uint queueFamilyIndex, uint swapchainImageCount) + public VulkanFrameResources(VkDevice device, uint queueFamilyIndex, uint swapchainImageCount, + VulkanContext ctx, VkDescriptorSetLayout descriptorSetLayout) { _device = device; @@ -24,12 +34,11 @@ internal sealed unsafe class VulkanFrameResources : IDisposable queueFamilyIndex = queueFamilyIndex, }; - fixed (VkCommandPool* poolPtr = &CommandPool) - { - var result = Vk.vkCreateCommandPool(_device, &poolInfo, 0, poolPtr); - if (result != VkResult.Success) - throw new InvalidOperationException($"vkCreateCommandPool failed: {result}"); - } + var cmdPool = VkCommandPool.Null; + var result = Vk.vkCreateCommandPool(_device, &poolInfo, 0, &cmdPool); + if (result != VkResult.Success) + throw new InvalidOperationException($"vkCreateCommandPool failed: {result}"); + CommandPool = cmdPool; var allocInfo = new VkCommandBufferAllocateInfo { @@ -41,7 +50,7 @@ internal sealed unsafe class VulkanFrameResources : IDisposable fixed (VkCommandBuffer* cmdPtr = CommandBuffers) { - var result = Vk.vkAllocateCommandBuffers(_device, &allocInfo, cmdPtr); + result = Vk.vkAllocateCommandBuffers(_device, &allocInfo, cmdPtr); if (result != VkResult.Success) throw new InvalidOperationException($"vkAllocateCommandBuffers failed: {result}"); } @@ -60,7 +69,7 @@ internal sealed unsafe class VulkanFrameResources : IDisposable for (int i = 0; i < MaxFramesInFlight; i++) { var fence = VkFence.Null; - var result = Vk.vkCreateFence(_device, &fenceInfo, 0, &fence); + result = Vk.vkCreateFence(_device, &fenceInfo, 0, &fence); if (result != VkResult.Success) throw new InvalidOperationException($"vkCreateFence failed: {result}"); FrameFences[i] = fence; @@ -76,15 +85,133 @@ internal sealed unsafe class VulkanFrameResources : IDisposable for (int i = 0; i < swapchainImageCount; i++) { var sem = VkSemaphore.Null; - var result = Vk.vkCreateSemaphore(_device, &semInfo, 0, &sem); + result = Vk.vkCreateSemaphore(_device, &semInfo, 0, &sem); if (result != VkResult.Success) throw new InvalidOperationException($"vkCreateSemaphore (submit) failed: {result}"); SubmitSemaphores[i] = sem; } + CreateUniformBuffers(ctx); + CreateDescriptorPoolAndSets(descriptorSetLayout); + Console.WriteLine($"[Vulkan] Frame resources: {MaxFramesInFlight} frames in flight, {swapchainImageCount} submit semaphores"); } + private void CreateUniformBuffers(VulkanContext ctx) + { + for (int i = 0; i < MaxFramesInFlight; i++) + { + var info = new VkBufferCreateInfo + { + sType = VkStructureType.BufferCreateInfo, + size = UboSize, + usage = VkBufferUsageFlags.UniformBuffer, + sharingMode = VkSharingMode.Exclusive, + }; + + var buf = VkBuffer.Null; + var result = Vk.vkCreateBuffer(_device, &info, 0, &buf); + if (result != VkResult.Success) + throw new InvalidOperationException($"vkCreateBuffer (UBO) failed: {result}"); + UboBuffers[i] = buf; + + var reqs = new VkMemoryRequirements(); + Vk.vkGetBufferMemoryRequirements(_device, buf, &reqs); + + var memTypeIndex = ctx.FindMemoryType(reqs.memoryTypeBits, + VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent); + + var allocInfo = new VkMemoryAllocateInfo + { + sType = VkStructureType.MemoryAllocateInfo, + allocationSize = reqs.size, + memoryTypeIndex = memTypeIndex, + }; + + var mem = VkDeviceMemory.Null; + result = Vk.vkAllocateMemory(_device, &allocInfo, 0, &mem); + if (result != VkResult.Success) + throw new InvalidOperationException($"vkAllocateMemory (UBO) failed: {result}"); + UboMemories[i] = mem; + + Vk.vkBindBufferMemory(_device, buf, mem, 0); + } + } + + private void CreateDescriptorPoolAndSets(VkDescriptorSetLayout layout) + { + var poolSize = new VkDescriptorPoolSize + { + type = VkDescriptorType.UniformBuffer, + descriptorCount = MaxFramesInFlight, + }; + + var poolInfo = new VkDescriptorPoolCreateInfo + { + sType = VkStructureType.DescriptorPoolCreateInfo, + flags = VkDescriptorPoolCreateFlags.FreeDescriptorSet, + maxSets = MaxFramesInFlight, + poolSizeCount = 1, + pPoolSizes = &poolSize, + }; + + var descPool = VkDescriptorPool.Null; + var result = Vk.vkCreateDescriptorPool(_device, &poolInfo, 0, &descPool); + if (result != VkResult.Success) + throw new InvalidOperationException($"vkCreateDescriptorPool failed: {result}"); + DescriptorPool = descPool; + + var layouts = stackalloc VkDescriptorSetLayout[MaxFramesInFlight]; + for (int i = 0; i < MaxFramesInFlight; i++) + layouts[i] = layout; + + var allocInfo = new VkDescriptorSetAllocateInfo + { + sType = VkStructureType.DescriptorSetAllocateInfo, + descriptorPool = DescriptorPool, + descriptorSetCount = MaxFramesInFlight, + pSetLayouts = layouts, + }; + + fixed (VkDescriptorSet* setPtr = DescriptorSets) + { + result = Vk.vkAllocateDescriptorSets(_device, &allocInfo, setPtr); + if (result != VkResult.Success) + throw new InvalidOperationException($"vkAllocateDescriptorSets failed: {result}"); + } + + for (int i = 0; i < MaxFramesInFlight; i++) + { + var bufferInfo = new VkDescriptorBufferInfo + { + buffer = UboBuffers[i], + offset = 0, + range = UboSize, + }; + + var write = new VkWriteDescriptorSet + { + sType = VkStructureType.WriteDescriptorSet, + dstSet = DescriptorSets[i], + dstBinding = 0, + dstArrayElement = 0, + descriptorCount = 1, + descriptorType = VkDescriptorType.UniformBuffer, + pBufferInfo = &bufferInfo, + }; + + Vk.vkUpdateDescriptorSets(_device, 1, &write, 0, 0); + } + } + + public void UpdateUbo(int frameIndex, void* data, ulong size) + { + void* pData = null; + Vk.vkMapMemory(_device, UboMemories[frameIndex], 0, size, 0, &pData); + System.Buffer.MemoryCopy(data, pData, (long)size, (long)size); + Vk.vkUnmapMemory(_device, UboMemories[frameIndex]); + } + public void WaitFrame(int frameIndex) { fixed (VkFence* fencePtr = &FrameFences[frameIndex]) @@ -105,6 +232,8 @@ internal sealed unsafe class VulkanFrameResources : IDisposable { if (FrameFences[i].Handle != 0) Vk.vkDestroyFence(_device, FrameFences[i], 0); if (AcquireSemaphores[i].Handle != 0) Vk.vkDestroySemaphore(_device, AcquireSemaphores[i], 0); + if (UboBuffers[i].Handle != 0) Vk.vkDestroyBuffer(_device, UboBuffers[i], 0); + if (UboMemories[i].Handle != 0) Vk.vkFreeMemory(_device, UboMemories[i], 0); } for (int i = 0; i < SubmitSemaphores.Length; i++) @@ -112,6 +241,7 @@ internal sealed unsafe class VulkanFrameResources : IDisposable if (SubmitSemaphores[i].Handle != 0) Vk.vkDestroySemaphore(_device, SubmitSemaphores[i], 0); } + if (DescriptorPool.Handle != 0) Vk.vkDestroyDescriptorPool(_device, DescriptorPool, 0); if (CommandPool.Handle != 0) Vk.vkDestroyCommandPool(_device, CommandPool, 0); } } diff --git a/src/Engine.Graphics.Vulkan/VulkanPipeline.cs b/src/Engine.Graphics.Vulkan/VulkanPipeline.cs index 17ab47c..6cfadfd 100644 --- a/src/Engine.Graphics.Vulkan/VulkanPipeline.cs +++ b/src/Engine.Graphics.Vulkan/VulkanPipeline.cs @@ -9,6 +9,7 @@ internal sealed unsafe class VulkanPipeline : IDisposable public VkPipeline Pipeline; public VkShaderModule VertModule; public VkShaderModule FragModule; + public VkDescriptorSetLayout DescriptorSetLayout; private readonly VkDevice _device; private bool _disposed; @@ -19,6 +20,8 @@ internal sealed unsafe class VulkanPipeline : IDisposable VertModule = CreateShaderModule(vertSpv); FragModule = CreateShaderModule(fragSpv); + CreateDescriptorSetLayout(); + fixed (byte* pName = "main\0"u8) { var stages = stackalloc VkPipelineShaderStageCreateInfo[2]; @@ -137,11 +140,21 @@ internal sealed unsafe class VulkanPipeline : IDisposable pDynamicStates = dynamicStates, }; + var pushConstantRange = new VkPushConstantRange + { + stageFlags = VkShaderStageFlags.Vertex, + offset = 0, + size = 4, + }; + + var descLayout = DescriptorSetLayout; var layoutInfo = new VkPipelineLayoutCreateInfo { sType = VkStructureType.PipelineLayoutCreateInfo, - setLayoutCount = 0, - pushConstantRangeCount = 0, + setLayoutCount = 1, + pSetLayouts = &descLayout, + pushConstantRangeCount = 1, + pPushConstantRanges = (nint)(&pushConstantRange), }; fixed (VkPipelineLayout* layoutPtr = &PipelineLayout) @@ -187,6 +200,30 @@ internal sealed unsafe class VulkanPipeline : IDisposable Console.WriteLine("[Vulkan] Graphics pipeline created (dynamic rendering)"); } + private void CreateDescriptorSetLayout() + { + var binding = new VkDescriptorSetLayoutBinding + { + binding = 0, + descriptorType = VkDescriptorType.UniformBuffer, + descriptorCount = 1, + stageFlags = VkShaderStageFlags.Vertex, + }; + + var info = new VkDescriptorSetLayoutCreateInfo + { + sType = VkStructureType.DescriptorSetLayoutCreateInfo, + bindingCount = 1, + pBindings = &binding, + }; + + var descLayout = VkDescriptorSetLayout.Null; + var result = Vk.vkCreateDescriptorSetLayout(_device, &info, 0, &descLayout); + if (result != VkResult.Success) + throw new InvalidOperationException($"vkCreateDescriptorSetLayout failed: {result}"); + DescriptorSetLayout = descLayout; + } + private VkShaderModule CreateShaderModule(byte[] spv) { fixed (byte* pCode = spv) @@ -213,6 +250,7 @@ internal sealed unsafe class VulkanPipeline : IDisposable if (Pipeline.Handle != 0) Vk.vkDestroyPipeline(_device, Pipeline, 0); if (PipelineLayout.Handle != 0) Vk.vkDestroyPipelineLayout(_device, PipelineLayout, 0); + if (DescriptorSetLayout.Handle != 0) Vk.vkDestroyDescriptorSetLayout(_device, DescriptorSetLayout, 0); if (FragModule.Handle != 0) Vk.vkDestroyShaderModule(_device, FragModule, 0); if (VertModule.Handle != 0) Vk.vkDestroyShaderModule(_device, VertModule, 0); } diff --git a/src/Engine.Graphics.Vulkan/VulkanRenderer.cs b/src/Engine.Graphics.Vulkan/VulkanRenderer.cs index 7909b67..f5ae673 100644 --- a/src/Engine.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Engine.Graphics.Vulkan/VulkanRenderer.cs @@ -18,6 +18,7 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen private bool _disposed; private bool _screenshotRequested; private string? _screenshotPath; + private float _totalTime; public bool IsScreenshotRequested => _screenshotRequested; public IScreenshotProvider ScreenshotProvider => this; @@ -32,7 +33,8 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen _pipeline = new VulkanPipeline(ctx.Device, swapchain.Format, vertSpv, fragSpv); - _frameResources = new VulkanFrameResources(ctx.Device, ctx.GraphicsQueueFamilyIndex, swapchain.ImageCount); + _frameResources = new VulkanFrameResources(ctx.Device, ctx.GraphicsQueueFamilyIndex, + swapchain.ImageCount, ctx, _pipeline.DescriptorSetLayout); var vertices = new Vertex[] { @@ -69,6 +71,11 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen if (acquireResult != VkResult.Success) throw new InvalidOperationException($"vkAcquireNextImageKHR failed: {acquireResult}"); + _totalTime += 0.016f; + + var vp = ComputeViewProjection(); + _frameResources.UpdateUbo(_frameIndex, &vp, VulkanFrameResources.UboSize); + var cmd = _frameResources.CommandBuffers[_frameIndex]; Vk.vkResetCommandBuffer(cmd, 0); @@ -132,10 +139,17 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen }; Vk.vkCmdSetScissor(cmd, 0, 1, &scissor); + var descSet = _frameResources.DescriptorSets[_frameIndex]; + Vk.vkCmdBindDescriptorSets(cmd, VkPipelineBindPoint.Graphics, _pipeline.PipelineLayout, + 0, 1, &descSet, 0, null); + var bufferHandle = _vertexBuffer.Buffer; ulong offset = 0; Vk.vkCmdBindVertexBuffers(cmd, 0, 1, &bufferHandle, &offset); + var angle = _totalTime; + Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Vertex, 0, 4, &angle); + Vk.vkCmdDraw(cmd, 3, 1, 0, 0); Vk.vkCmdEndRendering(cmd); @@ -207,6 +221,14 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen _frameIndex = (_frameIndex + 1) % VulkanFrameResources.MaxFramesInFlight; } + private Matrix4x4 ComputeViewProjection() + { + var aspect = (float)_swapchain.Extent.Width / (float)_swapchain.Extent.Height; + var proj = Matrix4x4.CreatePerspectiveFieldOfView(MathF.PI / 4f, aspect, 0.1f, 100f); + var view = Matrix4x4.CreateLookAt(new Vector3(0, 0, -2), Vector3.Zero, Vector3.UnitY); + return view * proj; + } + private static void TransitionImageLayout(VkCommandBuffer cmd, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, ulong srcStage, ulong srcAccess, diff --git a/src/Engine.Graphics.Vulkan/VulkanStructs.cs b/src/Engine.Graphics.Vulkan/VulkanStructs.cs index 2d351ff..bc6f822 100644 --- a/src/Engine.Graphics.Vulkan/VulkanStructs.cs +++ b/src/Engine.Graphics.Vulkan/VulkanStructs.cs @@ -907,3 +907,82 @@ public unsafe struct VkDebugUtilsMessengerCallbackDataEXT public uint objectCount; public nint pObjects; } + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct VkPushConstantRange +{ + public VkShaderStageFlags stageFlags; + public uint offset; + public uint size; +} + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct VkDescriptorSetLayoutBinding +{ + public uint binding; + public VkDescriptorType descriptorType; + public uint descriptorCount; + public VkShaderStageFlags stageFlags; + public nint pImmutableSamplers; +} + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct VkDescriptorSetLayoutCreateInfo +{ + public VkStructureType sType; + public nint pNext; + public uint flags; + public uint bindingCount; + public VkDescriptorSetLayoutBinding* pBindings; +} + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct VkDescriptorPoolSize +{ + public VkDescriptorType type; + public uint descriptorCount; +} + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct VkDescriptorPoolCreateInfo +{ + public VkStructureType sType; + public nint pNext; + public VkDescriptorPoolCreateFlags flags; + public uint maxSets; + public uint poolSizeCount; + public VkDescriptorPoolSize* pPoolSizes; +} + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct VkDescriptorSetAllocateInfo +{ + public VkStructureType sType; + public nint pNext; + public VkDescriptorPool descriptorPool; + public uint descriptorSetCount; + public VkDescriptorSetLayout* pSetLayouts; +} + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct VkDescriptorBufferInfo +{ + public VkBuffer buffer; + public ulong offset; + public ulong range; +} + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct VkWriteDescriptorSet +{ + public VkStructureType sType; + public nint pNext; + public VkDescriptorSet dstSet; + public uint dstBinding; + public uint dstArrayElement; + public uint descriptorCount; + public VkDescriptorType descriptorType; + public nint pImageInfo; + public VkDescriptorBufferInfo* pBufferInfo; + public nint pTexelBufferView; +}