diff --git a/src/CortexEngine.App/Program.cs b/src/CortexEngine.App/Program.cs
index 66a07ca..3efa5f1 100644
--- a/src/CortexEngine.App/Program.cs
+++ b/src/CortexEngine.App/Program.cs
@@ -12,15 +12,17 @@ class Program
try
{
- using var window = new Sdl3Window("Cortex Engine — Step 1", 1280, 720);
+ using var window = new Sdl3Window("Cortex Engine — Step 2", 1280, 720);
var timing = new Timing();
var input = new InputMapping();
- using var vulkan = new VulkanContext(window, enableValidation: true);
+ using var vulkan = new VulkanContext(window, enableValidation: false);
using var swapchain = new Swapchain(vulkan);
using var renderer = new TriangleRenderer(vulkan, swapchain);
var frames = 0;
var lastFpsTime = 0.0;
+ var lastWidth = window.Width;
+ var lastHeight = window.Height;
while (!window.ShouldClose)
{
@@ -30,6 +32,13 @@ class Program
// Note: SDL events are already polled in PumpEvents.
// In a real engine, the window would expose an event iterator.
+ if (window.Width != lastWidth || window.Height != lastHeight)
+ {
+ lastWidth = window.Width;
+ lastHeight = window.Height;
+ swapchain.Recreate(lastWidth, lastHeight);
+ }
+
renderer.RenderFrame();
frames++;
diff --git a/src/Engine.Graphics/ClearRenderer.cs b/src/Engine.Graphics/ClearRenderer.cs
deleted file mode 100644
index 959da14..0000000
--- a/src/Engine.Graphics/ClearRenderer.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using System;
-using Vortice.Vulkan;
-
-namespace Engine.Graphics;
-
-///
-/// Minimal renderer that clears the swapchain image to a solid color.
-/// Serves as the foundational Step 1 rendering proof-of-concept.
-///
-public sealed unsafe class ClearRenderer : IDisposable
-{
- private readonly VulkanContext _context;
- private readonly Swapchain _swapchain;
- private VkCommandPool _commandPool;
- private VkCommandBuffer[] _commandBuffers = null!;
- private VkSemaphore[] _imageAvailableSemaphores = null!;
- private VkSemaphore[] _renderFinishedSemaphores = null!;
- private VkFence[] _inFlightFences = null!;
- private int _currentFrame;
-
- public ClearRenderer(VulkanContext context, Swapchain swapchain)
- {
- _context = context;
- _swapchain = swapchain;
- CreateCommandPool();
- CreateCommandBuffers();
- CreateSyncObjects();
- }
-
- private void CreateCommandPool()
- {
- var createInfo = new VkCommandPoolCreateInfo
- {
- sType = VkStructureType.CommandPoolCreateInfo,
- queueFamilyIndex = _context.GraphicsFamilyIndex,
- flags = VkCommandPoolCreateFlags.ResetCommandBuffer
- };
-
- var result = _context.DeviceApi.vkCreateCommandPool(&createInfo, null, out _commandPool);
- if (result != VkResult.Success)
- throw new InvalidOperationException($"vkCreateCommandPool failed: {result}");
- }
-
- private void CreateCommandBuffers()
- {
- _commandBuffers = new VkCommandBuffer[2];
- for (var i = 0; i < _commandBuffers.Length; i++)
- {
- var allocInfo = new VkCommandBufferAllocateInfo
- {
- sType = VkStructureType.CommandBufferAllocateInfo,
- commandPool = _commandPool,
- level = VkCommandBufferLevel.Primary,
- commandBufferCount = 1
- };
-
- var result = _context.DeviceApi.vkAllocateCommandBuffer(&allocInfo, out _commandBuffers[i]);
- if (result != VkResult.Success)
- throw new InvalidOperationException($"vkAllocateCommandBuffers failed: {result}");
- }
- }
-
- private void CreateSyncObjects()
- {
- _imageAvailableSemaphores = new VkSemaphore[2];
- _renderFinishedSemaphores = new VkSemaphore[2];
- _inFlightFences = new VkFence[2];
-
- var semaphoreInfo = new VkSemaphoreCreateInfo { sType = VkStructureType.SemaphoreCreateInfo };
- var fenceInfo = new VkFenceCreateInfo
- {
- sType = VkStructureType.FenceCreateInfo,
- flags = VkFenceCreateFlags.Signaled
- };
-
- for (var i = 0; i < 2; i++)
- {
- _context.DeviceApi.vkCreateSemaphore(&semaphoreInfo, null, out _imageAvailableSemaphores[i]);
- _context.DeviceApi.vkCreateSemaphore(&semaphoreInfo, null, out _renderFinishedSemaphores[i]);
- _context.DeviceApi.vkCreateFence(&fenceInfo, null, out _inFlightFences[i]);
- }
- }
-
- public void RenderFrame(float r, float g, float b)
- {
- var frame = _currentFrame % 2;
-
- _context.DeviceApi.vkWaitForFences(_inFlightFences[frame], true, ulong.MaxValue);
- _context.DeviceApi.vkResetFences(_inFlightFences[frame]);
-
- var result = _context.DeviceApi.vkAcquireNextImageKHR(
- _swapchain.Handle,
- ulong.MaxValue,
- _imageAvailableSemaphores[frame],
- VkFence.Null,
- out var imageIndex);
-
- if (result == VkResult.ErrorOutOfDateKHR)
- {
- return;
- }
-
- var cmd = _commandBuffers[frame];
- _context.DeviceApi.vkResetCommandBuffer(cmd, VkCommandBufferResetFlags.None);
-
- var beginInfo = new VkCommandBufferBeginInfo
- {
- sType = VkStructureType.CommandBufferBeginInfo,
- flags = VkCommandBufferUsageFlags.OneTimeSubmit
- };
- _context.DeviceApi.vkBeginCommandBuffer(cmd, &beginInfo);
-
- var clearColor = new VkClearValue(r, g, b, 1.0f);
-
- var renderPassInfo = new VkRenderPassBeginInfo
- {
- sType = VkStructureType.RenderPassBeginInfo,
- renderPass = _swapchain.RenderPass,
- framebuffer = _swapchain.Framebuffers[imageIndex],
- renderArea = new VkRect2D(0, 0, _swapchain.Extent.width, _swapchain.Extent.height),
- clearValueCount = 1,
- pClearValues = &clearColor
- };
-
- _context.DeviceApi.vkCmdBeginRenderPass(cmd, &renderPassInfo, VkSubpassContents.Inline);
- _context.DeviceApi.vkCmdEndRenderPass(cmd);
- _context.DeviceApi.vkEndCommandBuffer(cmd);
-
- var waitSemaphore = _imageAvailableSemaphores[frame];
- var signalSemaphore = _renderFinishedSemaphores[frame];
- var stageMask = VkPipelineStageFlags.ColorAttachmentOutput;
- var submitInfo = new VkSubmitInfo
- {
- sType = VkStructureType.SubmitInfo,
- waitSemaphoreCount = 1,
- pWaitSemaphores = &waitSemaphore,
- pWaitDstStageMask = &stageMask,
- commandBufferCount = 1,
- pCommandBuffers = &cmd,
- signalSemaphoreCount = 1,
- pSignalSemaphores = &signalSemaphore
- };
-
- _context.DeviceApi.vkQueueSubmit(_context.GraphicsQueue, 1, &submitInfo, _inFlightFences[frame]);
-
- var swapchain = _swapchain.Handle;
- var presentInfo = new VkPresentInfoKHR
- {
- sType = VkStructureType.PresentInfoKHR,
- waitSemaphoreCount = 1,
- pWaitSemaphores = &signalSemaphore,
- swapchainCount = 1,
- pSwapchains = &swapchain,
- pImageIndices = &imageIndex
- };
-
- var presentResult = _context.DeviceApi.vkQueuePresentKHR(_context.PresentQueue, &presentInfo);
- if (presentResult == VkResult.ErrorOutOfDateKHR || presentResult == VkResult.SuboptimalKHR)
- {
- // Recreate handled externally.
- }
-
- _currentFrame++;
- }
-
- public void Dispose()
- {
- _context.DeviceApi.vkDeviceWaitIdle();
-
- for (var i = 0; i < 2; i++)
- {
- if (_renderFinishedSemaphores[i] != VkSemaphore.Null)
- _context.DeviceApi.vkDestroySemaphore(_renderFinishedSemaphores[i]);
- if (_imageAvailableSemaphores[i] != VkSemaphore.Null)
- _context.DeviceApi.vkDestroySemaphore(_imageAvailableSemaphores[i]);
- if (_inFlightFences[i] != VkFence.Null)
- _context.DeviceApi.vkDestroyFence(_inFlightFences[i]);
- }
-
- if (_commandPool != VkCommandPool.Null)
- _context.DeviceApi.vkDestroyCommandPool(_commandPool);
- }
-}
diff --git a/src/Engine.Graphics/Engine.Graphics.csproj b/src/Engine.Graphics/Engine.Graphics.csproj
index b5eed86..3f59fa0 100644
--- a/src/Engine.Graphics/Engine.Graphics.csproj
+++ b/src/Engine.Graphics/Engine.Graphics.csproj
@@ -18,7 +18,8 @@
-
+
+
diff --git a/src/Engine.Graphics/Shaders/fragment.spv b/src/Engine.Graphics/Shaders/fragment.spv
index a0856c9..828f1e5 100644
Binary files a/src/Engine.Graphics/Shaders/fragment.spv and b/src/Engine.Graphics/Shaders/fragment.spv differ
diff --git a/src/Engine.Graphics/Shaders/vertex.spv b/src/Engine.Graphics/Shaders/vertex.spv
index f05ea45..791f44a 100644
Binary files a/src/Engine.Graphics/Shaders/vertex.spv and b/src/Engine.Graphics/Shaders/vertex.spv differ
diff --git a/src/Engine.Graphics/Swapchain.cs b/src/Engine.Graphics/Swapchain.cs
index 9849b24..6f4fc3d 100644
--- a/src/Engine.Graphics/Swapchain.cs
+++ b/src/Engine.Graphics/Swapchain.cs
@@ -1,28 +1,30 @@
using System;
-using Vortice.Vulkan;
+using Silk.NET.Core;
+using Silk.NET.Vulkan;
+using Silk.NET.Vulkan.Extensions.KHR;
namespace Engine.Graphics;
///
/// Manages the Vulkan swapchain, image views, render pass, and framebuffers.
-/// Recreates itself automatically when the window is resized.
+/// Uses Silk.NET.Vulkan.
///
public sealed unsafe class Swapchain : IDisposable
{
private readonly VulkanContext _context;
- private VkRenderPass _renderPass;
- private VkSwapchainKHR _swapchain;
- private VkImage[] _images = null!;
- private VkImageView[] _imageViews = null!;
- private VkFramebuffer[] _framebuffers = null!;
- private VkSurfaceFormatKHR _surfaceFormat;
- private VkPresentModeKHR _presentMode;
- private VkExtent2D _extent;
+ private RenderPass _renderPass;
+ private SwapchainKHR _swapchain;
+ private Image[] _images = null!;
+ private ImageView[] _imageViews = null!;
+ private Framebuffer[] _framebuffers = null!;
+ private SurfaceFormatKHR _surfaceFormat;
+ private PresentModeKHR _presentMode;
+ private Extent2D _extent;
- public VkRenderPass RenderPass => _renderPass;
- public VkFramebuffer[] Framebuffers => _framebuffers;
- public VkExtent2D Extent => _extent;
- public VkSwapchainKHR Handle => _swapchain;
+ public RenderPass RenderPass => _renderPass;
+ public Framebuffer[] Framebuffers => _framebuffers;
+ public Extent2D Extent => _extent;
+ public SwapchainKHR Handle => _swapchain;
public uint ImageCount => (uint)_images.Length;
public Swapchain(VulkanContext context)
@@ -35,7 +37,7 @@ public sealed unsafe class Swapchain : IDisposable
public void Recreate(int width, int height)
{
- _context.DeviceApi.vkDeviceWaitIdle();
+ _context.Vk.DeviceWaitIdle(_context.Device);
CleanupSwapchain();
var capabilities = GetSurfaceCapabilities();
@@ -43,60 +45,63 @@ public sealed unsafe class Swapchain : IDisposable
_presentMode = ChoosePresentMode();
_extent = ChooseExtent(capabilities, (uint)width, (uint)height);
- var imageCount = capabilities.minImageCount + 1;
- if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount)
- imageCount = capabilities.maxImageCount;
+ var imageCount = capabilities.MinImageCount + 1;
+ if (capabilities.MaxImageCount > 0 && imageCount > capabilities.MaxImageCount)
+ imageCount = capabilities.MaxImageCount;
- var createInfo = new VkSwapchainCreateInfoKHR
+ var createInfo = new SwapchainCreateInfoKHR
{
- sType = VkStructureType.SwapchainCreateInfoKHR,
- surface = _context.Surface,
- minImageCount = imageCount,
- imageFormat = _surfaceFormat.format,
- imageColorSpace = _surfaceFormat.colorSpace,
- imageExtent = _extent,
- imageArrayLayers = 1,
- imageUsage = VkImageUsageFlags.ColorAttachment,
- imageSharingMode = VkSharingMode.Exclusive,
- preTransform = capabilities.currentTransform,
- compositeAlpha = VkCompositeAlphaFlagsKHR.Opaque,
- presentMode = _presentMode,
- clipped = true,
- oldSwapchain = _swapchain
+ SType = StructureType.SwapchainCreateInfoKhr,
+ Surface = _context.Surface,
+ MinImageCount = imageCount,
+ ImageFormat = _surfaceFormat.Format,
+ ImageColorSpace = _surfaceFormat.ColorSpace,
+ ImageExtent = _extent,
+ ImageArrayLayers = 1,
+ ImageUsage = ImageUsageFlags.ColorAttachmentBit,
+ ImageSharingMode = SharingMode.Exclusive,
+ PreTransform = capabilities.CurrentTransform,
+ CompositeAlpha = CompositeAlphaFlagsKHR.OpaqueBitKhr,
+ PresentMode = _presentMode,
+ Clipped = true,
+ OldSwapchain = _swapchain
};
- var result = _context.DeviceApi.vkCreateSwapchainKHR(&createInfo, null, out _swapchain);
- if (result != VkResult.Success)
+ SwapchainKHR swapchain;
+ var result = _context.KhrSwapchain!.CreateSwapchain(_context.Device, &createInfo, null, &swapchain);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateSwapchainKHR failed: {result}");
+ _swapchain = swapchain;
_images = GetSwapchainImages();
- _imageViews = new VkImageView[_images.Length];
- _framebuffers = new VkFramebuffer[_images.Length];
+ _imageViews = new ImageView[_images.Length];
+ _framebuffers = new Framebuffer[_images.Length];
for (var i = 0; i < _images.Length; i++)
{
- _imageViews[i] = CreateImageView(_images[i], _surfaceFormat.format);
+ _imageViews[i] = CreateImageView(_images[i], _surfaceFormat.Format);
_framebuffers[i] = CreateFramebuffer(_imageViews[i]);
}
}
- private VkSurfaceCapabilitiesKHR GetSurfaceCapabilities()
+ private SurfaceCapabilitiesKHR GetSurfaceCapabilities()
{
- var result = _context.InstanceApi.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(_context.PhysicalDevice, _context.Surface, out var capabilities);
- if (result != VkResult.Success)
+ SurfaceCapabilitiesKHR capabilities;
+ var result = _context.KhrSurface!.GetPhysicalDeviceSurfaceCapabilities(_context.PhysicalDevice, _context.Surface, &capabilities);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: {result}");
return capabilities;
}
- private VkImage[] GetSwapchainImages()
+ private Image[] GetSwapchainImages()
{
uint count = 0;
- _context.DeviceApi.vkGetSwapchainImagesKHR(_swapchain, &count, null);
- var images = new VkImage[count];
- fixed (VkImage* p = images)
+ _context.KhrSwapchain!.GetSwapchainImages(_context.Device, _swapchain, &count, null);
+ var images = new Image[count];
+ fixed (Image* p = images)
{
- var result = _context.DeviceApi.vkGetSwapchainImagesKHR(_swapchain, &count, p);
- if (result != VkResult.Success)
+ var result = _context.KhrSwapchain!.GetSwapchainImages(_context.Device, _swapchain, &count, p);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkGetSwapchainImagesKHR failed: {result}");
}
return images;
@@ -104,167 +109,169 @@ public sealed unsafe class Swapchain : IDisposable
private void CreateRenderPass()
{
- var colorAttachment = new VkAttachmentDescription
+ var colorAttachment = new AttachmentDescription
{
- format = _surfaceFormat.format != VkFormat.Undefined ? _surfaceFormat.format : VkFormat.B8G8R8A8Unorm,
- samples = VkSampleCountFlags.Count1,
- loadOp = VkAttachmentLoadOp.Clear,
- storeOp = VkAttachmentStoreOp.Store,
- stencilLoadOp = VkAttachmentLoadOp.DontCare,
- stencilStoreOp = VkAttachmentStoreOp.DontCare,
- initialLayout = VkImageLayout.Undefined,
- finalLayout = VkImageLayout.PresentSrcKHR
+ Format = _surfaceFormat.Format != Format.Undefined ? _surfaceFormat.Format : Format.B8G8R8A8Unorm,
+ Samples = SampleCountFlags.Count1Bit,
+ LoadOp = AttachmentLoadOp.Clear,
+ StoreOp = AttachmentStoreOp.Store,
+ StencilLoadOp = AttachmentLoadOp.DontCare,
+ StencilStoreOp = AttachmentStoreOp.DontCare,
+ InitialLayout = ImageLayout.Undefined,
+ FinalLayout = ImageLayout.PresentSrcKhr
};
- var colorAttachmentRef = new VkAttachmentReference
+ var colorAttachmentRef = new AttachmentReference
{
- attachment = 0,
- layout = VkImageLayout.ColorAttachmentOptimal
+ Attachment = 0,
+ Layout = ImageLayout.ColorAttachmentOptimal
};
- var subpass = new VkSubpassDescription
+ var subpass = new SubpassDescription
{
- pipelineBindPoint = VkPipelineBindPoint.Graphics,
- colorAttachmentCount = 1,
- pColorAttachments = &colorAttachmentRef
+ PipelineBindPoint = PipelineBindPoint.Graphics,
+ ColorAttachmentCount = 1,
+ PColorAttachments = &colorAttachmentRef
};
- var dependency = new VkSubpassDependency
+ var dependency = new SubpassDependency
{
- srcSubpass = Vulkan.VK_SUBPASS_EXTERNAL,
- dstSubpass = 0,
- srcStageMask = VkPipelineStageFlags.ColorAttachmentOutput,
- dstStageMask = VkPipelineStageFlags.ColorAttachmentOutput,
- srcAccessMask = VkAccessFlags.None,
- dstAccessMask = VkAccessFlags.ColorAttachmentWrite
+ SrcSubpass = ~0u,
+ DstSubpass = 0,
+ SrcStageMask = PipelineStageFlags.ColorAttachmentOutputBit,
+ DstStageMask = PipelineStageFlags.ColorAttachmentOutputBit,
+ SrcAccessMask = AccessFlags.None,
+ DstAccessMask = AccessFlags.ColorAttachmentWriteBit
};
- var createInfo = new VkRenderPassCreateInfo
+ var createInfo = new RenderPassCreateInfo
{
- sType = VkStructureType.RenderPassCreateInfo,
- attachmentCount = 1,
- pAttachments = &colorAttachment,
- subpassCount = 1,
- pSubpasses = &subpass,
- dependencyCount = 1,
- pDependencies = &dependency
+ SType = StructureType.RenderPassCreateInfo,
+ AttachmentCount = 1,
+ PAttachments = &colorAttachment,
+ SubpassCount = 1,
+ PSubpasses = &subpass,
+ DependencyCount = 1,
+ PDependencies = &dependency
};
- var result = _context.DeviceApi.vkCreateRenderPass(&createInfo, null, out _renderPass);
- if (result != VkResult.Success)
+ RenderPass renderPass;
+ var result = _context.Vk.CreateRenderPass(_context.Device, &createInfo, null, &renderPass);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateRenderPass failed: {result}");
+ _renderPass = renderPass;
}
- private VkImageView CreateImageView(VkImage image, VkFormat format)
+ private ImageView CreateImageView(Image image, Format format)
{
- var createInfo = new VkImageViewCreateInfo
+ var createInfo = new ImageViewCreateInfo
{
- sType = VkStructureType.ImageViewCreateInfo,
- image = image,
- viewType = VkImageViewType.Image2D,
- format = format,
- components = new VkComponentMapping(VkComponentSwizzle.R, VkComponentSwizzle.G, VkComponentSwizzle.B, VkComponentSwizzle.A),
- subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1)
+ SType = StructureType.ImageViewCreateInfo,
+ Image = image,
+ ViewType = ImageViewType.Type2D,
+ Format = format,
+ Components = new ComponentMapping(ComponentSwizzle.R, ComponentSwizzle.G, ComponentSwizzle.B, ComponentSwizzle.A),
+ SubresourceRange = new ImageSubresourceRange(ImageAspectFlags.ColorBit, 0, 1, 0, 1)
};
- var result = _context.DeviceApi.vkCreateImageView(&createInfo, null, out var imageView);
- if (result != VkResult.Success)
+ ImageView imageView;
+ var result = _context.Vk.CreateImageView(_context.Device, &createInfo, null, &imageView);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateImageView failed: {result}");
-
return imageView;
}
- private VkFramebuffer CreateFramebuffer(VkImageView imageView)
+ private Framebuffer CreateFramebuffer(ImageView imageView)
{
- var createInfo = new VkFramebufferCreateInfo
+ var createInfo = new FramebufferCreateInfo
{
- sType = VkStructureType.FramebufferCreateInfo,
- renderPass = _renderPass,
- attachmentCount = 1,
- pAttachments = &imageView,
- width = _extent.width,
- height = _extent.height,
- layers = 1
+ SType = StructureType.FramebufferCreateInfo,
+ RenderPass = _renderPass,
+ AttachmentCount = 1,
+ PAttachments = &imageView,
+ Width = _extent.Width,
+ Height = _extent.Height,
+ Layers = 1
};
- var result = _context.DeviceApi.vkCreateFramebuffer(&createInfo, null, out var framebuffer);
- if (result != VkResult.Success)
+ Framebuffer framebuffer;
+ var result = _context.Vk.CreateFramebuffer(_context.Device, &createInfo, null, &framebuffer);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateFramebuffer failed: {result}");
-
return framebuffer;
}
- private VkSurfaceFormatKHR ChooseSurfaceFormat()
+ private SurfaceFormatKHR ChooseSurfaceFormat()
{
var formats = GetSurfaceFormats();
foreach (var format in formats)
{
- if (format.format == VkFormat.B8G8R8A8Unorm && format.colorSpace == VkColorSpaceKHR.SrgbNonLinear)
+ if (format.Format == Format.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.SpaceSrgbNonlinearKhr)
return format;
}
return formats[0];
}
- private VkSurfaceFormatKHR[] GetSurfaceFormats()
+ private SurfaceFormatKHR[] GetSurfaceFormats()
{
uint count = 0;
- _context.InstanceApi.vkGetPhysicalDeviceSurfaceFormatsKHR(_context.PhysicalDevice, _context.Surface, &count, null);
- var formats = new VkSurfaceFormatKHR[count];
- fixed (VkSurfaceFormatKHR* p = formats)
+ _context.KhrSurface!.GetPhysicalDeviceSurfaceFormats(_context.PhysicalDevice, _context.Surface, &count, null);
+ var formats = new SurfaceFormatKHR[count];
+ fixed (SurfaceFormatKHR* p = formats)
{
- var result = _context.InstanceApi.vkGetPhysicalDeviceSurfaceFormatsKHR(_context.PhysicalDevice, _context.Surface, &count, p);
- if (result != VkResult.Success)
+ var result = _context.KhrSurface!.GetPhysicalDeviceSurfaceFormats(_context.PhysicalDevice, _context.Surface, &count, p);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkGetPhysicalDeviceSurfaceFormatsKHR failed: {result}");
}
return formats;
}
- private VkPresentModeKHR ChoosePresentMode()
+ private PresentModeKHR ChoosePresentMode()
{
var modes = GetSurfacePresentModes();
- if (Array.Exists(modes, m => m == VkPresentModeKHR.Mailbox))
- return VkPresentModeKHR.Mailbox;
- return VkPresentModeKHR.Fifo;
+ if (Array.Exists(modes, m => m == PresentModeKHR.MailboxKhr))
+ return PresentModeKHR.MailboxKhr;
+ return PresentModeKHR.FifoKhr;
}
- private VkPresentModeKHR[] GetSurfacePresentModes()
+ private PresentModeKHR[] GetSurfacePresentModes()
{
uint count = 0;
- _context.InstanceApi.vkGetPhysicalDeviceSurfacePresentModesKHR(_context.PhysicalDevice, _context.Surface, &count, null);
- var modes = new VkPresentModeKHR[count];
- fixed (VkPresentModeKHR* p = modes)
+ _context.KhrSurface!.GetPhysicalDeviceSurfacePresentModes(_context.PhysicalDevice, _context.Surface, &count, null);
+ var modes = new PresentModeKHR[count];
+ fixed (PresentModeKHR* p = modes)
{
- var result = _context.InstanceApi.vkGetPhysicalDeviceSurfacePresentModesKHR(_context.PhysicalDevice, _context.Surface, &count, p);
- if (result != VkResult.Success)
+ var result = _context.KhrSurface!.GetPhysicalDeviceSurfacePresentModes(_context.PhysicalDevice, _context.Surface, &count, p);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkGetPhysicalDeviceSurfacePresentModesKHR failed: {result}");
}
return modes;
}
- private VkExtent2D ChooseExtent(VkSurfaceCapabilitiesKHR capabilities, uint width, uint height)
+ private Extent2D ChooseExtent(SurfaceCapabilitiesKHR capabilities, uint width, uint height)
{
- if (capabilities.currentExtent.width != uint.MaxValue)
- return capabilities.currentExtent;
+ if (capabilities.CurrentExtent.Width != uint.MaxValue)
+ return capabilities.CurrentExtent;
- var extent = new VkExtent2D
+ var extent = new Extent2D
{
- width = Math.Clamp(width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width),
- height = Math.Clamp(height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height)
+ Width = Math.Clamp(width, capabilities.MinImageExtent.Width, capabilities.MaxImageExtent.Width),
+ Height = Math.Clamp(height, capabilities.MinImageExtent.Height, capabilities.MaxImageExtent.Height)
};
return extent;
}
private void CleanupSwapchain()
{
- if (_context.Device == VkDevice.Null)
+ if (_context.Device.Handle == 0)
return;
if (_framebuffers != null)
{
foreach (var fb in _framebuffers)
{
- if (fb != VkFramebuffer.Null)
- _context.DeviceApi.vkDestroyFramebuffer(fb);
+ if (fb.Handle != 0)
+ _context.Vk.DestroyFramebuffer(_context.Device, fb, null);
}
}
@@ -272,21 +279,21 @@ public sealed unsafe class Swapchain : IDisposable
{
foreach (var view in _imageViews)
{
- if (view != VkImageView.Null)
- _context.DeviceApi.vkDestroyImageView(view);
+ if (view.Handle != 0)
+ _context.Vk.DestroyImageView(_context.Device, view, null);
}
}
- if (_swapchain != VkSwapchainKHR.Null)
- _context.DeviceApi.vkDestroySwapchainKHR(_swapchain);
+ if (_swapchain.Handle != 0)
+ _context.KhrSwapchain!.DestroySwapchain(_context.Device, _swapchain, null);
}
public void Dispose()
{
- _context.DeviceApi.vkDeviceWaitIdle();
+ _context.Vk.DeviceWaitIdle(_context.Device);
CleanupSwapchain();
- if (_renderPass != VkRenderPass.Null)
- _context.DeviceApi.vkDestroyRenderPass(_renderPass);
+ if (_renderPass.Handle != 0)
+ _context.Vk.DestroyRenderPass(_context.Device, _renderPass, null);
}
}
diff --git a/src/Engine.Graphics/TriangleRenderer.cs b/src/Engine.Graphics/TriangleRenderer.cs
index 1b0b5f8..1437dae 100644
--- a/src/Engine.Graphics/TriangleRenderer.cs
+++ b/src/Engine.Graphics/TriangleRenderer.cs
@@ -1,10 +1,12 @@
using System;
-using Vortice.Vulkan;
+using Silk.NET.Core;
+using Silk.NET.Vulkan;
namespace Engine.Graphics;
///
/// Renders a colored triangle using a vertex buffer and a simple graphics pipeline.
+/// Uses Silk.NET.Vulkan.
///
public sealed unsafe class TriangleRenderer : IDisposable
{
@@ -12,11 +14,11 @@ public sealed unsafe class TriangleRenderer : IDisposable
private readonly Swapchain _swapchain;
private readonly VulkanPipeline _pipeline;
private readonly VertexBuffer _vertexBuffer;
- private VkCommandPool _commandPool;
- private VkCommandBuffer[] _commandBuffers = null!;
- private VkSemaphore[] _imageAvailableSemaphores = null!;
- private VkSemaphore[] _renderFinishedSemaphores = null!;
- private VkFence[] _inFlightFences = null!;
+ private CommandPool _commandPool;
+ private CommandBuffer[] _commandBuffers = null!;
+ private Silk.NET.Vulkan.Semaphore[] _imageAvailableSemaphores = null!;
+ private Silk.NET.Vulkan.Semaphore[] _renderFinishedSemaphores = null!;
+ private Silk.NET.Vulkan.Fence[] _inFlightFences = null!;
private int _currentFrame;
public TriangleRenderer(VulkanContext context, Swapchain swapchain)
@@ -26,7 +28,6 @@ public sealed unsafe class TriangleRenderer : IDisposable
_pipeline = new VulkanPipeline(context, swapchain);
_vertexBuffer = CreateTriangleBuffer();
-
CreateCommandPool();
CreateCommandBuffers();
CreateSyncObjects();
@@ -36,7 +37,6 @@ public sealed unsafe class TriangleRenderer : IDisposable
{
var vertices = new[]
{
- // Position (vec2) + Color (vec3)
0.0f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f
@@ -46,7 +46,7 @@ public sealed unsafe class TriangleRenderer : IDisposable
fixed (byte* p = bytes)
fixed (float* v = vertices)
{
- Buffer.MemoryCopy(v, p, bytes.Length, vertices.Length * sizeof(float));
+ global::System.Buffer.MemoryCopy(v, p, bytes.Length, vertices.Length * sizeof(float));
}
return new VertexBuffer(_context, bytes);
@@ -54,55 +54,64 @@ public sealed unsafe class TriangleRenderer : IDisposable
private void CreateCommandPool()
{
- var createInfo = new VkCommandPoolCreateInfo
+ var createInfo = new CommandPoolCreateInfo
{
- sType = VkStructureType.CommandPoolCreateInfo,
- queueFamilyIndex = _context.GraphicsFamilyIndex,
- flags = VkCommandPoolCreateFlags.ResetCommandBuffer
+ SType = StructureType.CommandPoolCreateInfo,
+ QueueFamilyIndex = _context.GraphicsFamilyIndex,
+ Flags = CommandPoolCreateFlags.ResetCommandBufferBit
};
- var result = _context.DeviceApi.vkCreateCommandPool(&createInfo, null, out _commandPool);
- if (result != VkResult.Success)
+ CommandPool commandPool;
+ var result = _context.Vk.CreateCommandPool(_context.Device, &createInfo, null, &commandPool);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateCommandPool failed: {result}");
+ _commandPool = commandPool;
}
private void CreateCommandBuffers()
{
- _commandBuffers = new VkCommandBuffer[2];
+ _commandBuffers = new CommandBuffer[2];
for (var i = 0; i < _commandBuffers.Length; i++)
{
- var allocInfo = new VkCommandBufferAllocateInfo
+ var allocInfo = new CommandBufferAllocateInfo
{
- sType = VkStructureType.CommandBufferAllocateInfo,
- commandPool = _commandPool,
- level = VkCommandBufferLevel.Primary,
- commandBufferCount = 1
+ SType = StructureType.CommandBufferAllocateInfo,
+ CommandPool = _commandPool,
+ Level = CommandBufferLevel.Primary,
+ CommandBufferCount = 1
};
- var result = _context.DeviceApi.vkAllocateCommandBuffer(&allocInfo, out _commandBuffers[i]);
- if (result != VkResult.Success)
+ CommandBuffer cmd;
+ var result = _context.Vk.AllocateCommandBuffers(_context.Device, &allocInfo, &cmd);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkAllocateCommandBuffers failed: {result}");
+ _commandBuffers[i] = cmd;
}
}
private void CreateSyncObjects()
{
- _imageAvailableSemaphores = new VkSemaphore[2];
- _renderFinishedSemaphores = new VkSemaphore[2];
- _inFlightFences = new VkFence[2];
+ _imageAvailableSemaphores = new Silk.NET.Vulkan.Semaphore[2];
+ _renderFinishedSemaphores = new Silk.NET.Vulkan.Semaphore[2];
+ _inFlightFences = new Silk.NET.Vulkan.Fence[2];
- var semaphoreInfo = new VkSemaphoreCreateInfo { sType = VkStructureType.SemaphoreCreateInfo };
- var fenceInfo = new VkFenceCreateInfo
+ var semaphoreInfo = new SemaphoreCreateInfo { SType = StructureType.SemaphoreCreateInfo };
+ var fenceInfo = new FenceCreateInfo
{
- sType = VkStructureType.FenceCreateInfo,
- flags = VkFenceCreateFlags.Signaled
+ SType = StructureType.FenceCreateInfo,
+ Flags = FenceCreateFlags.SignaledBit
};
for (var i = 0; i < 2; i++)
{
- _context.DeviceApi.vkCreateSemaphore(&semaphoreInfo, null, out _imageAvailableSemaphores[i]);
- _context.DeviceApi.vkCreateSemaphore(&semaphoreInfo, null, out _renderFinishedSemaphores[i]);
- _context.DeviceApi.vkCreateFence(&fenceInfo, null, out _inFlightFences[i]);
+ Silk.NET.Vulkan.Semaphore imageAvailable, renderFinished;
+ Silk.NET.Vulkan.Fence fence;
+ _context.Vk.CreateSemaphore(_context.Device, &semaphoreInfo, null, &imageAvailable);
+ _context.Vk.CreateSemaphore(_context.Device, &semaphoreInfo, null, &renderFinished);
+ _context.Vk.CreateFence(_context.Device, &fenceInfo, null, &fence);
+ _imageAvailableSemaphores[i] = imageAvailable;
+ _renderFinishedSemaphores[i] = renderFinished;
+ _inFlightFences[i] = fence;
}
}
@@ -110,106 +119,96 @@ public sealed unsafe class TriangleRenderer : IDisposable
{
var frame = _currentFrame % 2;
- _context.DeviceApi.vkWaitForFences(_inFlightFences[frame], true, ulong.MaxValue);
- _context.DeviceApi.vkResetFences(_inFlightFences[frame]);
+ var fence = _inFlightFences[frame];
+ _context.Vk.WaitForFences(_context.Device, 1, &fence, true, ulong.MaxValue);
+ _context.Vk.ResetFences(_context.Device, 1, &fence);
- var result = _context.DeviceApi.vkAcquireNextImageKHR(
- _swapchain.Handle,
- ulong.MaxValue,
- _imageAvailableSemaphores[frame],
- VkFence.Null,
- out var imageIndex);
-
- if (result == VkResult.ErrorOutOfDateKHR)
+ uint imageIndex;
+ var result = _context.KhrSwapchain!.AcquireNextImage(_context.Device, _swapchain.Handle, ulong.MaxValue, _imageAvailableSemaphores[frame], new Silk.NET.Vulkan.Fence(), &imageIndex);
+ if (result == Result.ErrorOutOfDateKhr)
return;
var cmd = _commandBuffers[frame];
- _context.DeviceApi.vkResetCommandBuffer(cmd, VkCommandBufferResetFlags.None);
+ _context.Vk.ResetCommandBuffer(cmd, CommandBufferResetFlags.None);
- var beginInfo = new VkCommandBufferBeginInfo
+ var beginInfo = new CommandBufferBeginInfo
{
- sType = VkStructureType.CommandBufferBeginInfo,
- flags = VkCommandBufferUsageFlags.OneTimeSubmit
+ SType = StructureType.CommandBufferBeginInfo,
+ Flags = CommandBufferUsageFlags.OneTimeSubmitBit
};
- _context.DeviceApi.vkBeginCommandBuffer(cmd, &beginInfo);
+ _context.Vk.BeginCommandBuffer(cmd, &beginInfo);
- var clearColor = new VkClearValue(0.0f, 0.0f, 0.0f, 1.0f);
-
- var renderPassInfo = new VkRenderPassBeginInfo
+ var clearColor = new ClearValue(new ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f));
+ var renderPassInfo = new RenderPassBeginInfo
{
- sType = VkStructureType.RenderPassBeginInfo,
- renderPass = _swapchain.RenderPass,
- framebuffer = _swapchain.Framebuffers[imageIndex],
- renderArea = new VkRect2D(0, 0, _swapchain.Extent.width, _swapchain.Extent.height),
- clearValueCount = 1,
- pClearValues = &clearColor
+ SType = StructureType.RenderPassBeginInfo,
+ RenderPass = _swapchain.RenderPass,
+ Framebuffer = _swapchain.Framebuffers[imageIndex],
+ RenderArea = new Rect2D(new Offset2D(0, 0), _swapchain.Extent),
+ ClearValueCount = 1,
+ PClearValues = &clearColor
};
- _context.DeviceApi.vkCmdBeginRenderPass(cmd, &renderPassInfo, VkSubpassContents.Inline);
+ _context.Vk.CmdBeginRenderPass(cmd, &renderPassInfo, SubpassContents.Inline);
+ _context.Vk.CmdBindPipeline(cmd, PipelineBindPoint.Graphics, _pipeline.Handle);
- _context.DeviceApi.vkCmdBindPipeline(cmd, VkPipelineBindPoint.Graphics, _pipeline.Handle);
-
- var viewport = new VkViewport(0, 0, _swapchain.Extent.width, _swapchain.Extent.height, 0, 1);
- var scissor = new VkRect2D(0, 0, _swapchain.Extent.width, _swapchain.Extent.height);
- _context.DeviceApi.vkCmdSetViewport(cmd, 0, viewport);
- _context.DeviceApi.vkCmdSetScissor(cmd, 0, scissor);
+ var viewport = new Viewport(0, 0, _swapchain.Extent.Width, _swapchain.Extent.Height, 0, 1);
+ var scissor = new Rect2D(new Offset2D(0, 0), _swapchain.Extent);
+ _context.Vk.CmdSetViewport(cmd, 0, 1, &viewport);
+ _context.Vk.CmdSetScissor(cmd, 0, 1, &scissor);
var vertexBuffer = _vertexBuffer.Buffer;
var offset = 0ul;
- _context.DeviceApi.vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBuffer, &offset);
- _context.DeviceApi.vkCmdDraw(cmd, 3, 1, 0, 0);
+ _context.Vk.CmdBindVertexBuffers(cmd, 0, 1, &vertexBuffer, &offset);
+ _context.Vk.CmdDraw(cmd, 3, 1, 0, 0);
- _context.DeviceApi.vkCmdEndRenderPass(cmd);
- _context.DeviceApi.vkEndCommandBuffer(cmd);
+ _context.Vk.CmdEndRenderPass(cmd);
+ _context.Vk.EndCommandBuffer(cmd);
var waitSemaphore = _imageAvailableSemaphores[frame];
var signalSemaphore = _renderFinishedSemaphores[frame];
- var stageMask = VkPipelineStageFlags.ColorAttachmentOutput;
- var submitInfo = new VkSubmitInfo
+ var stageMask = PipelineStageFlags.ColorAttachmentOutputBit;
+ var submitInfo = new SubmitInfo
{
- sType = VkStructureType.SubmitInfo,
- waitSemaphoreCount = 1,
- pWaitSemaphores = &waitSemaphore,
- pWaitDstStageMask = &stageMask,
- commandBufferCount = 1,
- pCommandBuffers = &cmd,
- signalSemaphoreCount = 1,
- pSignalSemaphores = &signalSemaphore
+ SType = StructureType.SubmitInfo,
+ WaitSemaphoreCount = 1,
+ PWaitSemaphores = &waitSemaphore,
+ PWaitDstStageMask = &stageMask,
+ CommandBufferCount = 1,
+ PCommandBuffers = &cmd,
+ SignalSemaphoreCount = 1,
+ PSignalSemaphores = &signalSemaphore
};
- _context.DeviceApi.vkQueueSubmit(_context.GraphicsQueue, 1, &submitInfo, _inFlightFences[frame]);
+ _context.Vk.QueueSubmit(_context.GraphicsQueue, 1, &submitInfo, _inFlightFences[frame]);
var swapchain = _swapchain.Handle;
- var presentInfo = new VkPresentInfoKHR
+ var presentInfo = new PresentInfoKHR
{
- sType = VkStructureType.PresentInfoKHR,
- waitSemaphoreCount = 1,
- pWaitSemaphores = &signalSemaphore,
- swapchainCount = 1,
- pSwapchains = &swapchain,
- pImageIndices = &imageIndex
+ SType = StructureType.PresentInfoKhr,
+ WaitSemaphoreCount = 1,
+ PWaitSemaphores = &signalSemaphore,
+ SwapchainCount = 1,
+ PSwapchains = &swapchain,
+ PImageIndices = &imageIndex
};
- _context.DeviceApi.vkQueuePresentKHR(_context.PresentQueue, &presentInfo);
+ _context.KhrSwapchain!.QueuePresent(_context.PresentQueue, &presentInfo);
_currentFrame++;
}
public void Dispose()
{
- _context.DeviceApi.vkDeviceWaitIdle();
+ _context.Vk.DeviceWaitIdle(_context.Device);
for (var i = 0; i < 2; i++)
{
- if (_renderFinishedSemaphores[i] != VkSemaphore.Null)
- _context.DeviceApi.vkDestroySemaphore(_renderFinishedSemaphores[i]);
- if (_imageAvailableSemaphores[i] != VkSemaphore.Null)
- _context.DeviceApi.vkDestroySemaphore(_imageAvailableSemaphores[i]);
- if (_inFlightFences[i] != VkFence.Null)
- _context.DeviceApi.vkDestroyFence(_inFlightFences[i]);
+ _context.Vk.DestroySemaphore(_context.Device, _renderFinishedSemaphores[i], null);
+ _context.Vk.DestroySemaphore(_context.Device, _imageAvailableSemaphores[i], null);
+ _context.Vk.DestroyFence(_context.Device, _inFlightFences[i], null);
}
- if (_commandPool != VkCommandPool.Null)
- _context.DeviceApi.vkDestroyCommandPool(_commandPool);
+ _context.Vk.DestroyCommandPool(_context.Device, _commandPool, null);
_vertexBuffer.Dispose();
_pipeline.Dispose();
diff --git a/src/Engine.Graphics/VertexBuffer.cs b/src/Engine.Graphics/VertexBuffer.cs
index ba3f2a1..a840cef 100644
--- a/src/Engine.Graphics/VertexBuffer.cs
+++ b/src/Engine.Graphics/VertexBuffer.cs
@@ -1,16 +1,18 @@
using System;
-using Vortice.Vulkan;
+using Silk.NET.Core;
+using Silk.NET.Vulkan;
namespace Engine.Graphics;
///
-/// Interleaved vertex: vec2 position + vec3 color.
+/// Interleaved vertex buffer: vec2 position + vec3 color.
+/// Uses Silk.NET.Vulkan.
///
public sealed unsafe class VertexBuffer : IDisposable
{
private readonly VulkanContext _context;
- public VkBuffer Buffer { get; }
- public VkDeviceMemory Memory { get; }
+ public Silk.NET.Vulkan.Buffer Buffer { get; }
+ public DeviceMemory Memory { get; }
public ulong Size { get; }
public VertexBuffer(VulkanContext context, ReadOnlySpan data)
@@ -18,62 +20,66 @@ public sealed unsafe class VertexBuffer : IDisposable
_context = context;
Size = (ulong)data.Length;
- Buffer = CreateBuffer(Size, VkBufferUsageFlags.VertexBuffer);
+ Buffer = CreateBuffer(Size, BufferUsageFlags.VertexBufferBit);
var memoryRequirements = GetMemoryRequirements(Buffer);
- Memory = AllocateMemory(memoryRequirements, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
+ Memory = AllocateMemory(memoryRequirements, MemoryPropertyFlags.HostVisibleBit | MemoryPropertyFlags.HostCoherentBit);
- var result = _context.DeviceApi.vkBindBufferMemory(Buffer, Memory, 0);
- if (result != VkResult.Success)
+ var result = _context.Vk.BindBufferMemory(_context.Device, Buffer, Memory, 0);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkBindBufferMemory failed: {result}");
CopyData(data);
}
- private VkBuffer CreateBuffer(ulong size, VkBufferUsageFlags usage)
+ private Silk.NET.Vulkan.Buffer CreateBuffer(ulong size, BufferUsageFlags usage)
{
- var createInfo = new VkBufferCreateInfo
+ var createInfo = new BufferCreateInfo
{
- sType = VkStructureType.BufferCreateInfo,
- size = size,
- usage = usage,
- sharingMode = VkSharingMode.Exclusive
+ SType = StructureType.BufferCreateInfo,
+ Size = size,
+ Usage = usage,
+ SharingMode = SharingMode.Exclusive
};
- var result = _context.DeviceApi.vkCreateBuffer(&createInfo, null, out var buffer);
- if (result != VkResult.Success)
+ Silk.NET.Vulkan.Buffer buffer;
+ var result = _context.Vk.CreateBuffer(_context.Device, &createInfo, null, &buffer);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateBuffer failed: {result}");
return buffer;
}
- private VkMemoryRequirements GetMemoryRequirements(VkBuffer buffer)
+ private MemoryRequirements GetMemoryRequirements(Silk.NET.Vulkan.Buffer buffer)
{
- _context.DeviceApi.vkGetBufferMemoryRequirements(buffer, out var requirements);
+ MemoryRequirements requirements;
+ _context.Vk.GetBufferMemoryRequirements(_context.Device, buffer, &requirements);
return requirements;
}
- private VkDeviceMemory AllocateMemory(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties)
+ private DeviceMemory AllocateMemory(MemoryRequirements requirements, MemoryPropertyFlags properties)
{
- var memoryTypeIndex = FindMemoryType(requirements.memoryTypeBits, properties);
- var allocateInfo = new VkMemoryAllocateInfo
+ var memoryTypeIndex = FindMemoryType(requirements.MemoryTypeBits, properties);
+ var allocateInfo = new MemoryAllocateInfo
{
- sType = VkStructureType.MemoryAllocateInfo,
- allocationSize = requirements.size,
- memoryTypeIndex = memoryTypeIndex
+ SType = StructureType.MemoryAllocateInfo,
+ AllocationSize = requirements.Size,
+ MemoryTypeIndex = memoryTypeIndex
};
- var result = _context.DeviceApi.vkAllocateMemory(&allocateInfo, null, out var memory);
- if (result != VkResult.Success)
+ DeviceMemory memory;
+ var result = _context.Vk.AllocateMemory(_context.Device, &allocateInfo, null, &memory);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkAllocateMemory failed: {result}");
return memory;
}
- private uint FindMemoryType(uint typeFilter, VkMemoryPropertyFlags properties)
+ private uint FindMemoryType(uint typeFilter, MemoryPropertyFlags properties)
{
- _context.InstanceApi.vkGetPhysicalDeviceMemoryProperties(_context.PhysicalDevice, out var memoryProperties);
- for (var i = 0; i < memoryProperties.memoryTypeCount; i++)
+ PhysicalDeviceMemoryProperties memoryProperties;
+ _context.Vk.GetPhysicalDeviceMemoryProperties(_context.PhysicalDevice, &memoryProperties);
+ for (var i = 0; i < memoryProperties.MemoryTypeCount; i++)
{
if ((typeFilter & (1u << i)) != 0 &&
- (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
+ (memoryProperties.MemoryTypes[i].PropertyFlags & properties) == properties)
{
return (uint)i;
}
@@ -84,22 +90,22 @@ public sealed unsafe class VertexBuffer : IDisposable
private void CopyData(ReadOnlySpan data)
{
void* mappedData;
- var result = _context.DeviceApi.vkMapMemory(Memory, 0, Size, VkMemoryMapFlags.None, &mappedData);
- if (result != VkResult.Success)
+ var result = _context.Vk.MapMemory(_context.Device, Memory, 0, Size, MemoryMapFlags.None, &mappedData);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkMapMemory failed: {result}");
fixed (byte* src = data)
{
- System.Buffer.MemoryCopy(src, mappedData, (long)Size, data.Length);
+ global::System.Buffer.MemoryCopy(src, mappedData, (long)Size, data.Length);
}
- _context.DeviceApi.vkUnmapMemory(Memory);
+ _context.Vk.UnmapMemory(_context.Device, Memory);
}
public void Dispose()
{
- _context.DeviceApi.vkDeviceWaitIdle();
- _context.DeviceApi.vkDestroyBuffer(Buffer);
- _context.DeviceApi.vkFreeMemory(Memory);
+ _context.Vk.DeviceWaitIdle(_context.Device);
+ _context.Vk.DestroyBuffer(_context.Device, Buffer, null);
+ _context.Vk.FreeMemory(_context.Device, Memory, null);
}
}
diff --git a/src/Engine.Graphics/VulkanContext.cs b/src/Engine.Graphics/VulkanContext.cs
index 496f531..cced80f 100644
--- a/src/Engine.Graphics/VulkanContext.cs
+++ b/src/Engine.Graphics/VulkanContext.cs
@@ -5,37 +5,42 @@ using System.Runtime.InteropServices;
using System.Text;
using Engine.Core;
using SDL;
-using Vortice.Vulkan;
+using Silk.NET.Core;
+using Silk.NET.Core.Native;
+using Silk.NET.Vulkan;
+using Silk.NET.Vulkan.Extensions.KHR;
namespace Engine.Graphics;
///
-/// Owns the Vulkan instance, physical device, logical device, queues, and API handles.
-/// Created once per application lifetime.
+/// Owns the Vulkan instance, physical device, logical device, queues, and surface.
+/// Uses Silk.NET.Vulkan because Vortice.Vulkan's loader segfaulted on this Kubuntu setup.
///
public sealed unsafe class VulkanContext : IDisposable
{
private bool _disposed;
- public VkInstance Instance { get; private set; }
- public VkInstanceApi InstanceApi { get; private set; }
- public VkPhysicalDevice PhysicalDevice { get; private set; }
- public VkDevice Device { get; private set; }
- public VkDeviceApi DeviceApi { get; private set; }
- public VkQueue GraphicsQueue { get; private set; }
- public VkQueue PresentQueue { get; private set; }
+ public Vk Vk { get; }
+ public KhrSurface? KhrSurface { get; private set; }
+ public KhrSwapchain? KhrSwapchain { get; private set; }
+ public Instance Instance { get; private set; }
+ public PhysicalDevice PhysicalDevice { get; private set; }
+ public Device Device { get; private set; }
+ public Queue GraphicsQueue { get; private set; }
+ public Queue PresentQueue { get; private set; }
+ public SurfaceKHR Surface { get; private set; }
public uint GraphicsFamilyIndex { get; private set; }
public uint PresentFamilyIndex { get; private set; }
- public VkSurfaceKHR Surface { get; private set; }
public VulkanContext(Sdl3Window window, bool enableValidation = true)
{
+ Vk = Vk.GetApi();
CreateInstance(window, enableValidation);
- InstanceApi = Vulkan.GetApi(Instance);
+ LoadInstanceExtensions();
CreateSurface(window);
PickPhysicalDevice();
CreateLogicalDevice();
- DeviceApi = Vulkan.GetApi(Instance, Device);
+ LoadDeviceExtensions();
GetQueues();
}
@@ -51,55 +56,74 @@ public sealed unsafe class VulkanContext : IDisposable
? new[] { "VK_LAYER_KHRONOS_validation" }
: Array.Empty();
- var appName = VkStringInterop.ConvertToUnmanaged("Cortex Engine");
- var engineName = VkStringInterop.ConvertToUnmanaged("CortexEngine");
+ var appName = SilkMarshal.StringToMemory("Cortex Engine", NativeStringEncoding.UTF8);
+ var engineName = SilkMarshal.StringToMemory("CortexEngine", NativeStringEncoding.UTF8);
+ var extensionMemory = SilkMarshal.StringArrayToMemory(requiredExtensions, NativeStringEncoding.UTF8);
+ var layerMemory = SilkMarshal.StringArrayToMemory(layerNames, NativeStringEncoding.UTF8);
- var appInfo = new VkApplicationInfo
+ try
{
- sType = VkStructureType.ApplicationInfo,
- pApplicationName = appName,
- pEngineName = engineName,
- apiVersion = VkVersion.Version_1_3
- };
-
- using var extensionPin = new StringArrayPin(requiredExtensions);
- using var layerPin = new StringArrayPin(layerNames);
-
- {
- var createInfo = new VkInstanceCreateInfo
+ var appInfo = new ApplicationInfo
{
- sType = VkStructureType.InstanceCreateInfo,
- pApplicationInfo = &appInfo,
- enabledExtensionCount = (uint)requiredExtensions.Count,
- ppEnabledExtensionNames = extensionPin.Pointers,
- enabledLayerCount = (uint)layerNames.Length,
- ppEnabledLayerNames = layerPin.Pointers
+ SType = StructureType.ApplicationInfo,
+ PApplicationName = (byte*)appName.Handle,
+ PEngineName = (byte*)engineName.Handle,
+ ApiVersion = Vk.Version13
};
- var result = Vulkan.vkCreateInstance(&createInfo, null, out var instance);
- if (result != VkResult.Success)
+ var createInfo = new InstanceCreateInfo
+ {
+ SType = StructureType.InstanceCreateInfo,
+ PApplicationInfo = &appInfo,
+ EnabledExtensionCount = (uint)requiredExtensions.Count,
+ PpEnabledExtensionNames = (byte**)extensionMemory.Handle,
+ EnabledLayerCount = (uint)layerNames.Length,
+ PpEnabledLayerNames = (byte**)layerMemory.Handle
+ };
+
+ Instance instance;
+ var result = Vk.CreateInstance(&createInfo, null, &instance);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateInstance failed: {result}");
Instance = instance;
}
+ finally
+ {
+ appName.Dispose();
+ engineName.Dispose();
+ extensionMemory.Dispose();
+ layerMemory.Dispose();
+ }
+ }
- VkStringInterop.Free(appName);
- VkStringInterop.Free(engineName);
+ private void LoadInstanceExtensions()
+ {
+ if (!Vk.TryGetInstanceExtension(Instance, out KhrSurface khrSurface))
+ throw new InvalidOperationException("VK_KHR_surface not available.");
+ KhrSurface = khrSurface;
+ }
+
+ private void LoadDeviceExtensions()
+ {
+ if (!Vk.TryGetDeviceExtension(Instance, Device, out KhrSwapchain khrSwapchain))
+ throw new InvalidOperationException("VK_KHR_swapchain not available.");
+ KhrSwapchain = khrSwapchain;
}
private void CreateSurface(Sdl3Window window)
{
var sdlInstance = (SDL.VkInstance_T*)Instance.Handle;
var sdlSurface = (SDL.VkSurfaceKHR_T*)null;
- var result = SDL3.SDL_Vulkan_CreateSurface(
+ var sdlResult = SDL3.SDL_Vulkan_CreateSurface(
(SDL_Window*)window.Handle,
sdlInstance,
null,
&sdlSurface);
- if (result != true)
+ if (sdlResult != true)
throw new InvalidOperationException($"SDL_Vulkan_CreateSurface failed: {SDL3.SDL_GetError()}");
- Surface = new VkSurfaceKHR((ulong)sdlSurface);
+ Surface = new SurfaceKHR((ulong)sdlSurface);
}
private void PickPhysicalDevice()
@@ -110,93 +134,108 @@ public sealed unsafe class VulkanContext : IDisposable
foreach (var device in devices)
{
- var properties = InstanceApi.vkGetPhysicalDeviceProperties(device);
+ var properties = Vk.GetPhysicalDeviceProperties(device);
var queueFamilies = GetPhysicalDeviceQueueFamilyProperties(device);
var hasGraphics = false;
var hasPresent = false;
for (var i = 0; i < queueFamilies.Length; i++)
{
- if (queueFamilies[i].queueFlags.HasFlag(VkQueueFlags.Graphics))
+ if (queueFamilies[i].QueueFlags.HasFlag(QueueFlags.GraphicsBit))
hasGraphics = true;
- var supportResult = InstanceApi.vkGetPhysicalDeviceSurfaceSupportKHR(device, (uint)i, Surface, out VkBool32 supported);
- if (supportResult == VkResult.Success && supported)
+
+ Bool32 supported;
+ KhrSurface!.GetPhysicalDeviceSurfaceSupport(device, (uint)i, Surface, &supported);
+ if (supported)
hasPresent = true;
}
if (hasGraphics && hasPresent)
{
PhysicalDevice = device;
- if (properties.deviceType == VkPhysicalDeviceType.DiscreteGpu)
+ if (properties.DeviceType == PhysicalDeviceType.DiscreteGpu)
break;
}
}
- if (PhysicalDevice == VkPhysicalDevice.Null)
+ if (PhysicalDevice.Handle == 0)
throw new InvalidOperationException("No suitable Vulkan physical device found.");
}
- private VkPhysicalDevice[] EnumeratePhysicalDevices()
+ private PhysicalDevice[] EnumeratePhysicalDevices()
{
uint count = 0;
- InstanceApi.vkEnumeratePhysicalDevices(&count, null);
+ Vk.EnumeratePhysicalDevices(Instance, &count, null);
if (count == 0)
- return Array.Empty();
+ return Array.Empty();
- var devices = new VkPhysicalDevice[count];
- fixed (VkPhysicalDevice* p = devices)
+ var devices = new PhysicalDevice[count];
+ fixed (PhysicalDevice* p = devices)
{
- var result = InstanceApi.vkEnumeratePhysicalDevices(&count, p);
- if (result != VkResult.Success)
+ var result = Vk.EnumeratePhysicalDevices(Instance, &count, p);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkEnumeratePhysicalDevices failed: {result}");
}
return devices;
}
+ private QueueFamilyProperties[] GetPhysicalDeviceQueueFamilyProperties(PhysicalDevice device)
+ {
+ uint count = 0;
+ Vk.GetPhysicalDeviceQueueFamilyProperties(device, &count, null);
+ var properties = new QueueFamilyProperties[count];
+ fixed (QueueFamilyProperties* p = properties)
+ {
+ Vk.GetPhysicalDeviceQueueFamilyProperties(device, &count, p);
+ }
+ return properties;
+ }
+
private void CreateLogicalDevice()
{
var queueFamilies = GetPhysicalDeviceQueueFamilyProperties(PhysicalDevice);
- GraphicsFamilyIndex = FindQueueFamilyIndex(queueFamilies, VkQueueFlags.Graphics);
+ GraphicsFamilyIndex = FindQueueFamilyIndex(queueFamilies, QueueFlags.GraphicsBit);
PresentFamilyIndex = FindPresentQueueFamilyIndex(queueFamilies);
var uniqueFamilies = new HashSet { GraphicsFamilyIndex, PresentFamilyIndex };
- var queueCreateInfos = uniqueFamilies.Select(family => new VkDeviceQueueCreateInfo
+ var queueCreateInfos = uniqueFamilies.Select(family => new DeviceQueueCreateInfo
{
- sType = VkStructureType.DeviceQueueCreateInfo,
- queueFamilyIndex = family,
- queueCount = 1
+ SType = StructureType.DeviceQueueCreateInfo,
+ QueueFamilyIndex = family,
+ QueueCount = 1
}).ToArray();
- var priorityHandles = new GCHandle[queueCreateInfos.Length];
var extensionNames = new[] { "VK_KHR_swapchain" };
- using var extensionPin = new StringArrayPin(extensionNames);
+ var extensionMemory = SilkMarshal.StringArrayToMemory(extensionNames, NativeStringEncoding.UTF8);
+ var priorityHandles = new GCHandle[queueCreateInfos.Length];
try
{
- var deviceFeatures = new VkPhysicalDeviceFeatures();
+ var deviceFeatures = new PhysicalDeviceFeatures();
for (var i = 0; i < queueCreateInfos.Length; i++)
{
var priority = new[] { 1.0f };
var handle = GCHandle.Alloc(priority, GCHandleType.Pinned);
priorityHandles[i] = handle;
- queueCreateInfos[i].pQueuePriorities = (float*)handle.AddrOfPinnedObject();
+ queueCreateInfos[i].PQueuePriorities = (float*)handle.AddrOfPinnedObject();
}
- fixed (VkDeviceQueueCreateInfo* pQueue = queueCreateInfos)
+ fixed (DeviceQueueCreateInfo* pQueue = queueCreateInfos)
{
- var createInfo = new VkDeviceCreateInfo
+ var createInfo = new DeviceCreateInfo
{
- sType = VkStructureType.DeviceCreateInfo,
- queueCreateInfoCount = (uint)queueCreateInfos.Length,
- pQueueCreateInfos = pQueue,
- pEnabledFeatures = &deviceFeatures,
- enabledExtensionCount = 1,
- ppEnabledExtensionNames = extensionPin.Pointers
+ SType = StructureType.DeviceCreateInfo,
+ QueueCreateInfoCount = (uint)queueCreateInfos.Length,
+ PQueueCreateInfos = pQueue,
+ PEnabledFeatures = &deviceFeatures,
+ EnabledExtensionCount = 1,
+ PpEnabledExtensionNames = (byte**)extensionMemory.Handle
};
- var result = InstanceApi.vkCreateDevice(PhysicalDevice, &createInfo, null, out var device);
- if (result != VkResult.Success)
+ Device device;
+ var result = Vk.CreateDevice(PhysicalDevice, &createInfo, null, &device);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateDevice failed: {result}");
Device = device;
}
@@ -208,101 +247,55 @@ public sealed unsafe class VulkanContext : IDisposable
if (handle.IsAllocated)
handle.Free();
}
+ extensionMemory.Dispose();
}
}
private void GetQueues()
{
- DeviceApi.vkGetDeviceQueue(GraphicsFamilyIndex, 0, out var graphicsQueue);
- DeviceApi.vkGetDeviceQueue(PresentFamilyIndex, 0, out var presentQueue);
+ Queue graphicsQueue;
+ Vk.GetDeviceQueue(Device, GraphicsFamilyIndex, 0, &graphicsQueue);
GraphicsQueue = graphicsQueue;
+
+ Queue presentQueue;
+ Vk.GetDeviceQueue(Device, PresentFamilyIndex, 0, &presentQueue);
PresentQueue = presentQueue;
}
- private uint FindQueueFamilyIndex(VkQueueFamilyProperties[] properties, VkQueueFlags flags)
+ private uint FindQueueFamilyIndex(QueueFamilyProperties[] properties, QueueFlags flags)
{
for (var i = 0; i < properties.Length; i++)
{
- if (properties[i].queueFlags.HasFlag(flags))
+ if (properties[i].QueueFlags.HasFlag(flags))
return (uint)i;
}
throw new InvalidOperationException($"No queue family with flags {flags} found.");
}
- private uint FindPresentQueueFamilyIndex(VkQueueFamilyProperties[] properties)
+ private uint FindPresentQueueFamilyIndex(QueueFamilyProperties[] properties)
{
for (var i = 0; i < properties.Length; i++)
{
- var supportResult = InstanceApi.vkGetPhysicalDeviceSurfaceSupportKHR(PhysicalDevice, (uint)i, Surface, out VkBool32 supported);
- if (supportResult == VkResult.Success && supported)
+ Bool32 supported;
+ KhrSurface!.GetPhysicalDeviceSurfaceSupport(PhysicalDevice, (uint)i, Surface, &supported);
+ if (supported)
return (uint)i;
}
throw new InvalidOperationException("No present queue family found.");
}
- private VkQueueFamilyProperties[] GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice device)
- {
- uint count = 0;
- InstanceApi.vkGetPhysicalDeviceQueueFamilyProperties(device, &count, null);
- var properties = new VkQueueFamilyProperties[count];
- fixed (VkQueueFamilyProperties* p = properties)
- {
- InstanceApi.vkGetPhysicalDeviceQueueFamilyProperties(device, &count, p);
- }
- return properties;
- }
-
- private sealed unsafe class StringArrayPin : IDisposable
- {
- public byte** Pointers;
- private readonly GCHandle[] _handles;
-
- public StringArrayPin(IReadOnlyList strings)
- {
- if (strings.Count == 0)
- {
- Pointers = null;
- _handles = Array.Empty();
- return;
- }
-
- Pointers = (byte**)Marshal.AllocHGlobal(strings.Count * sizeof(byte*));
- _handles = new GCHandle[strings.Count];
-
- for (var i = 0; i < strings.Count; i++)
- {
- var bytes = Encoding.UTF8.GetBytes(strings[i] + '\0');
- _handles[i] = GCHandle.Alloc(bytes, GCHandleType.Pinned);
- Pointers[i] = (byte*)_handles[i].AddrOfPinnedObject();
- }
- }
-
- public void Dispose()
- {
- if (Pointers == null)
- return;
-
- foreach (var handle in _handles)
- {
- if (handle.IsAllocated)
- handle.Free();
- }
-
- Marshal.FreeHGlobal((nint)Pointers);
- Pointers = null;
- }
- }
-
public void Dispose()
{
if (_disposed) return;
_disposed = true;
- if (Device != VkDevice.Null)
- DeviceApi.vkDestroyDevice();
- if (Instance != VkInstance.Null && Surface != VkSurfaceKHR.Null)
- InstanceApi.vkDestroySurfaceKHR(Surface);
- if (Instance != VkInstance.Null)
- InstanceApi.vkDestroyInstance();
+ Vk.DeviceWaitIdle(Device);
+ if (Device.Handle != 0)
+ Vk.DestroyDevice(Device, null);
+ if (Surface.Handle != 0)
+ KhrSurface?.DestroySurface(Instance, Surface, null);
+ if (Instance.Handle != 0)
+ Vk.DestroyInstance(Instance, null);
+ Vk.Dispose();
}
}
diff --git a/src/Engine.Graphics/VulkanPipeline.cs b/src/Engine.Graphics/VulkanPipeline.cs
index 5a74224..298cec0 100644
--- a/src/Engine.Graphics/VulkanPipeline.cs
+++ b/src/Engine.Graphics/VulkanPipeline.cs
@@ -1,21 +1,22 @@
using System;
-using Vortice.Vulkan;
+using Silk.NET.Core.Native;
+using Silk.NET.Vulkan;
namespace Engine.Graphics;
///
-/// A simple graphics pipeline for a single vertex/fragment shader pair.
-/// Assumes a triangle with vec2 position + vec3 color per vertex.
+/// Simple graphics pipeline for a triangle with vec2 position + vec3 color.
+/// Uses Silk.NET.Vulkan.
///
public sealed unsafe class VulkanPipeline : IDisposable
{
private readonly VulkanContext _context;
private readonly Swapchain _swapchain;
- public VkPipeline Handle { get; }
- public VkPipelineLayout Layout { get; }
- private readonly VkShaderModule _vertexModule;
- private readonly VkShaderModule _fragmentModule;
+ public Pipeline Handle { get; }
+ public PipelineLayout Layout { get; }
+ private readonly ShaderModule _vertexModule;
+ private readonly ShaderModule _fragmentModule;
public VulkanPipeline(VulkanContext context, Swapchain swapchain)
{
@@ -29,7 +30,7 @@ public sealed unsafe class VulkanPipeline : IDisposable
Handle = CreateGraphicsPipeline();
}
- private VkShaderModule CreateShaderModule(string resourceName)
+ private ShaderModule CreateShaderModule(string resourceName)
{
var code = ShaderLoader.Load(resourceName);
if (code.Length % 4 != 0)
@@ -37,189 +38,185 @@ public sealed unsafe class VulkanPipeline : IDisposable
fixed (byte* pCode = code)
{
- var createInfo = new VkShaderModuleCreateInfo
+ var createInfo = new ShaderModuleCreateInfo
{
- sType = VkStructureType.ShaderModuleCreateInfo,
- codeSize = (nuint)code.Length,
- pCode = (uint*)pCode
+ SType = StructureType.ShaderModuleCreateInfo,
+ CodeSize = (nuint)code.Length,
+ PCode = (uint*)pCode
};
- var result = _context.DeviceApi.vkCreateShaderModule(&createInfo, null, out var module);
- if (result != VkResult.Success)
+ ShaderModule module;
+ var result = _context.Vk.CreateShaderModule(_context.Device, &createInfo, null, &module);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateShaderModule failed for {resourceName}: {result}");
return module;
}
}
- private VkPipelineLayout CreatePipelineLayout()
+ private PipelineLayout CreatePipelineLayout()
{
- var createInfo = new VkPipelineLayoutCreateInfo
+ var createInfo = new PipelineLayoutCreateInfo
{
- sType = VkStructureType.PipelineLayoutCreateInfo,
- setLayoutCount = 0,
- pushConstantRangeCount = 0
+ SType = StructureType.PipelineLayoutCreateInfo,
+ SetLayoutCount = 0,
+ PushConstantRangeCount = 0
};
- var result = _context.DeviceApi.vkCreatePipelineLayout(&createInfo, null, out var layout);
- if (result != VkResult.Success)
+ PipelineLayout layout;
+ var result = _context.Vk.CreatePipelineLayout(_context.Device, &createInfo, null, &layout);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreatePipelineLayout failed: {result}");
return layout;
}
- private VkPipeline CreateGraphicsPipeline()
+ private Pipeline CreateGraphicsPipeline()
{
+ var entryName = SilkMarshal.StringToPtr("main", NativeStringEncoding.UTF8);
var stages = new[]
{
- new VkPipelineShaderStageCreateInfo
+ new PipelineShaderStageCreateInfo
{
- sType = VkStructureType.PipelineShaderStageCreateInfo,
- stage = VkShaderStageFlags.Vertex,
- module = _vertexModule,
- pName = VkStringInterop.ConvertToUnmanaged("main")
+ SType = StructureType.PipelineShaderStageCreateInfo,
+ Stage = ShaderStageFlags.VertexBit,
+ Module = _vertexModule,
+ PName = (byte*)entryName
},
- new VkPipelineShaderStageCreateInfo
+ new PipelineShaderStageCreateInfo
{
- sType = VkStructureType.PipelineShaderStageCreateInfo,
- stage = VkShaderStageFlags.Fragment,
- module = _fragmentModule,
- pName = VkStringInterop.ConvertToUnmanaged("main")
+ SType = StructureType.PipelineShaderStageCreateInfo,
+ Stage = ShaderStageFlags.FragmentBit,
+ Module = _fragmentModule,
+ PName = (byte*)entryName
}
};
- var bindingDescription = new VkVertexInputBindingDescription
+ var bindingDescription = new VertexInputBindingDescription
{
- binding = 0,
- stride = (uint)(5 * sizeof(float)),
- inputRate = VkVertexInputRate.Vertex
+ Binding = 0,
+ Stride = (uint)(5 * sizeof(float)),
+ InputRate = VertexInputRate.Vertex
};
var attributeDescriptions = new[]
{
- new VkVertexInputAttributeDescription
+ new VertexInputAttributeDescription
{
- binding = 0,
- location = 0,
- format = VkFormat.R32G32Sfloat,
- offset = 0
+ Binding = 0,
+ Location = 0,
+ Format = Format.R32G32Sfloat,
+ Offset = 0
},
- new VkVertexInputAttributeDescription
+ new VertexInputAttributeDescription
{
- binding = 0,
- location = 1,
- format = VkFormat.R32G32B32Sfloat,
- offset = (uint)(2 * sizeof(float))
+ Binding = 0,
+ Location = 1,
+ Format = Format.R32G32B32Sfloat,
+ Offset = (uint)(2 * sizeof(float))
}
};
- VkPipelineVertexInputStateCreateInfo vertexInputInfo;
- fixed (VkVertexInputAttributeDescription* pAttributes = attributeDescriptions)
+ PipelineVertexInputStateCreateInfo vertexInputInfo;
+ fixed (VertexInputAttributeDescription* pAttributes = attributeDescriptions)
{
- vertexInputInfo = new VkPipelineVertexInputStateCreateInfo
+ vertexInputInfo = new PipelineVertexInputStateCreateInfo
{
- sType = VkStructureType.PipelineVertexInputStateCreateInfo,
- vertexBindingDescriptionCount = 1,
- pVertexBindingDescriptions = &bindingDescription,
- vertexAttributeDescriptionCount = (uint)attributeDescriptions.Length,
- pVertexAttributeDescriptions = pAttributes
+ SType = StructureType.PipelineVertexInputStateCreateInfo,
+ VertexBindingDescriptionCount = 1,
+ PVertexBindingDescriptions = &bindingDescription,
+ VertexAttributeDescriptionCount = (uint)attributeDescriptions.Length,
+ PVertexAttributeDescriptions = pAttributes
};
}
- var inputAssembly = new VkPipelineInputAssemblyStateCreateInfo
+ var inputAssembly = new PipelineInputAssemblyStateCreateInfo
{
- sType = VkStructureType.PipelineInputAssemblyStateCreateInfo,
- topology = VkPrimitiveTopology.TriangleList,
- primitiveRestartEnable = false
+ SType = StructureType.PipelineInputAssemblyStateCreateInfo,
+ Topology = PrimitiveTopology.TriangleList,
+ PrimitiveRestartEnable = false
};
- var viewport = new VkViewport(0, 0, _swapchain.Extent.width, _swapchain.Extent.height, 0, 1);
- var scissor = new VkRect2D(0, 0, _swapchain.Extent.width, _swapchain.Extent.height);
-
- var viewportState = new VkPipelineViewportStateCreateInfo
+ var viewportState = new PipelineViewportStateCreateInfo
{
- sType = VkStructureType.PipelineViewportStateCreateInfo,
- viewportCount = 1,
- pViewports = &viewport,
- scissorCount = 1,
- pScissors = &scissor
+ SType = StructureType.PipelineViewportStateCreateInfo,
+ ViewportCount = 1,
+ ScissorCount = 1
};
- var rasterizer = new VkPipelineRasterizationStateCreateInfo
+ var rasterizer = new PipelineRasterizationStateCreateInfo
{
- sType = VkStructureType.PipelineRasterizationStateCreateInfo,
- polygonMode = VkPolygonMode.Fill,
- cullMode = VkCullModeFlags.None,
- frontFace = VkFrontFace.Clockwise,
- lineWidth = 1.0f
+ SType = StructureType.PipelineRasterizationStateCreateInfo,
+ PolygonMode = PolygonMode.Fill,
+ CullMode = CullModeFlags.None,
+ FrontFace = FrontFace.Clockwise,
+ LineWidth = 1.0f
};
- var multisampling = new VkPipelineMultisampleStateCreateInfo
+ var multisampling = new PipelineMultisampleStateCreateInfo
{
- sType = VkStructureType.PipelineMultisampleStateCreateInfo,
- rasterizationSamples = VkSampleCountFlags.Count1,
- sampleShadingEnable = false
+ SType = StructureType.PipelineMultisampleStateCreateInfo,
+ RasterizationSamples = SampleCountFlags.Count1Bit,
+ SampleShadingEnable = false
};
- var colorBlendAttachment = new VkPipelineColorBlendAttachmentState
+ var colorBlendAttachment = new PipelineColorBlendAttachmentState
{
- colorWriteMask = VkColorComponentFlags.R | VkColorComponentFlags.G | VkColorComponentFlags.B | VkColorComponentFlags.A
+ ColorWriteMask = ColorComponentFlags.RBit | ColorComponentFlags.GBit | ColorComponentFlags.BBit | ColorComponentFlags.ABit
};
- var colorBlending = new VkPipelineColorBlendStateCreateInfo
+ var colorBlending = new PipelineColorBlendStateCreateInfo
{
- sType = VkStructureType.PipelineColorBlendStateCreateInfo,
- attachmentCount = 1,
- pAttachments = &colorBlendAttachment
+ SType = StructureType.PipelineColorBlendStateCreateInfo,
+ AttachmentCount = 1,
+ PAttachments = &colorBlendAttachment
};
- var dynamicStates = new[] { VkDynamicState.Viewport, VkDynamicState.Scissor };
- VkPipelineDynamicStateCreateInfo dynamicState;
- fixed (VkDynamicState* pDynamic = dynamicStates)
+ var dynamicStates = new[] { DynamicState.Viewport, DynamicState.Scissor };
+ PipelineDynamicStateCreateInfo dynamicState;
+ fixed (DynamicState* pDynamic = dynamicStates)
{
- dynamicState = new VkPipelineDynamicStateCreateInfo
+ dynamicState = new PipelineDynamicStateCreateInfo
{
- sType = VkStructureType.PipelineDynamicStateCreateInfo,
- dynamicStateCount = (uint)dynamicStates.Length,
- pDynamicStates = pDynamic
+ SType = StructureType.PipelineDynamicStateCreateInfo,
+ DynamicStateCount = (uint)dynamicStates.Length,
+ PDynamicStates = pDynamic
};
}
- VkPipeline pipeline;
- fixed (VkPipelineShaderStageCreateInfo* pStages = stages)
+ Pipeline pipeline;
+ fixed (PipelineShaderStageCreateInfo* pStages = stages)
{
- var createInfo = new VkGraphicsPipelineCreateInfo
+ var createInfo = new GraphicsPipelineCreateInfo
{
- sType = VkStructureType.GraphicsPipelineCreateInfo,
- stageCount = (uint)stages.Length,
- pStages = pStages,
- pVertexInputState = &vertexInputInfo,
- pInputAssemblyState = &inputAssembly,
- pViewportState = &viewportState,
- pRasterizationState = &rasterizer,
- pMultisampleState = &multisampling,
- pColorBlendState = &colorBlending,
- pDynamicState = &dynamicState,
- layout = Layout,
- renderPass = _swapchain.RenderPass,
- subpass = 0
+ SType = StructureType.GraphicsPipelineCreateInfo,
+ StageCount = (uint)stages.Length,
+ PStages = pStages,
+ PVertexInputState = &vertexInputInfo,
+ PInputAssemblyState = &inputAssembly,
+ PViewportState = &viewportState,
+ PRasterizationState = &rasterizer,
+ PMultisampleState = &multisampling,
+ PColorBlendState = &colorBlending,
+ PDynamicState = &dynamicState,
+ Layout = Layout,
+ RenderPass = _swapchain.RenderPass,
+ Subpass = 0
};
- var result = _context.DeviceApi.vkCreateGraphicsPipelines(VkPipelineCache.Null, 1, &createInfo, null, &pipeline);
- if (result != VkResult.Success)
+ var result = _context.Vk.CreateGraphicsPipelines(_context.Device, default, 1, &createInfo, null, &pipeline);
+ if (result != Result.Success)
throw new InvalidOperationException($"vkCreateGraphicsPipelines failed: {result}");
}
- VkStringInterop.Free(stages[0].pName);
- VkStringInterop.Free(stages[1].pName);
-
+ SilkMarshal.FreeString(entryName, NativeStringEncoding.UTF8);
return pipeline;
}
public void Dispose()
{
- _context.DeviceApi.vkDeviceWaitIdle();
- _context.DeviceApi.vkDestroyPipeline(Handle);
- _context.DeviceApi.vkDestroyPipelineLayout(Layout);
- _context.DeviceApi.vkDestroyShaderModule(_vertexModule);
- _context.DeviceApi.vkDestroyShaderModule(_fragmentModule);
+ _context.Vk.DeviceWaitIdle(_context.Device);
+ _context.Vk.DestroyPipeline(_context.Device, Handle, null);
+ _context.Vk.DestroyPipelineLayout(_context.Device, Layout, null);
+ _context.Vk.DestroyShaderModule(_context.Device, _vertexModule, null);
+ _context.Vk.DestroyShaderModule(_context.Device, _fragmentModule, null);
}
}