feat: ImGui integration + real screenshot capture via Vulkan
ImGui: - ImGui.NET 1.91.6.1 NuGet package - VulkanImGui: font texture upload, ImGui pipeline (blending, no depth), vertex/index buffer streaming - GLSL 450 ImGui shaders (vert: scale/translate push constants, frag: font texture sampler) - Compiled to SPIR-V via @webgpu/glslang - Debug overlay: FPS, camera position, entity count, light list - 1600+ FPS with ImGui active Screenshot: - vkCmdCopyImageToBuffer embedded in main command buffer - Layout transition PresentSrcKHR→TransferSrcOptimal→PresentSrcKHR - Deferred read: staging buffer read on next frame after fence - BMP format written directly to FileStream (row by row) - All 16 camera tour screenshots captured (1280x720x32bpp) All 66 tests pass.
This commit is contained in:
@@ -14,6 +14,7 @@ using Engine.Graphics.Loaders;
|
||||
using Engine.Graphics.Vulkan;
|
||||
using Engine.Physics;
|
||||
using Flecs.NET.Core;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace CortexEngine.App;
|
||||
|
||||
@@ -46,6 +47,16 @@ class Program
|
||||
var input = window.Input;
|
||||
using var renderer = renderContext.CreateRenderer();
|
||||
|
||||
VulkanImGui? imGuiLayer = null;
|
||||
if (!cameraTour && renderer is VulkanRenderer vkRenderer)
|
||||
{
|
||||
ImGui.CreateContext();
|
||||
imGuiLayer = new VulkanImGui(vkRenderer._ctx, vkRenderer._swapchain);
|
||||
vkRenderer.ImGuiLayer = imGuiLayer;
|
||||
ImGui.GetIO().DisplaySize = new System.Numerics.Vector2(window.Width, window.Height);
|
||||
Console.WriteLine("[App] ImGui initialized.");
|
||||
}
|
||||
|
||||
var (modelPath, mcpPort) = ParseArgs(args);
|
||||
var mesh = LoadModel(modelPath);
|
||||
|
||||
@@ -249,6 +260,35 @@ class Program
|
||||
demoScreenshotRequested = true;
|
||||
}
|
||||
|
||||
if (imGuiLayer != null)
|
||||
{
|
||||
ImGui.NewFrame();
|
||||
ImGui.Begin("Cortex Engine Debug");
|
||||
ImGui.Text($"FPS: {currentFps}");
|
||||
ImGui.Text($"Delta: {timing.DeltaTime * 1000.0:F2} ms");
|
||||
ImGui.Text($"Camera: {cameraController.Name}");
|
||||
ImGui.Separator();
|
||||
var cam = cameraEntity.Get<Camera>();
|
||||
ImGui.Text($"Pos: ({cam.Position.X:F2}, {cam.Position.Y:F2}, {cam.Position.Z:F2})");
|
||||
ImGui.Text($"Target: ({cam.Target.X:F2}, {cam.Target.Y:F2}, {cam.Target.Z:F2})");
|
||||
ImGui.Separator();
|
||||
|
||||
var entityCount = 0;
|
||||
world.Each((Entity e, ref Transform _) => entityCount++);
|
||||
ImGui.Text($"Entities: {entityCount}");
|
||||
ImGui.Text($"Press F to toggle camera");
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Text("Lights:");
|
||||
world.Each((Entity e, ref Light light) =>
|
||||
{
|
||||
ImGui.Text($" {e.Name()}: {light.Type} I={light.Intensity:F1}");
|
||||
});
|
||||
|
||||
ImGui.End();
|
||||
ImGui.Render();
|
||||
}
|
||||
|
||||
renderer.RenderWorld(world);
|
||||
queue.CompletePendingScreenshots();
|
||||
|
||||
@@ -263,6 +303,7 @@ class Program
|
||||
}
|
||||
|
||||
Console.WriteLine("Shutting down...");
|
||||
imGuiLayer?.Dispose();
|
||||
#if !RELEASE_AOT
|
||||
if (mcpApp != null)
|
||||
await mcpApp.StopAsync();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ImGui.NET" Version="1.91.6.1" />
|
||||
<PackageReference Include="Flecs.NET.Debug" Version="4.0.4-build.546" Condition="'$(Configuration)' == 'Debug'" />
|
||||
<PackageReference Include="Flecs.NET.Release" Version="4.0.4-build.546" Condition="'$(Configuration)' == 'Release' OR '$(Configuration)' == 'ReleaseAOT'" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 fragUV;
|
||||
layout(location = 1) in vec4 fragColor;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D fontTexture;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = fragColor * texture(fontTexture, fragUV);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 inPos;
|
||||
layout(location = 1) in vec2 inUV;
|
||||
layout(location = 2) in vec4 inColor;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec2 scale;
|
||||
vec2 translate;
|
||||
} pc;
|
||||
|
||||
layout(location = 0) out vec2 fragUV;
|
||||
layout(location = 1) out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragUV = inUV;
|
||||
fragColor = inColor;
|
||||
gl_Position = vec4(inPos * pc.scale + pc.translate, 0.0, 1.0);
|
||||
}
|
||||
Binary file not shown.
@@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Engine.Graphics.Vulkan;
|
||||
|
||||
internal static unsafe class Vk
|
||||
public static unsafe class Vk
|
||||
{
|
||||
public static VkInstance Instance;
|
||||
public static VkDevice Device;
|
||||
@@ -242,168 +242,168 @@ internal static unsafe class Vk
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateInstance(VkInstanceCreateInfo* pCreateInfo, void* pAllocator, VkInstance* pInstance);
|
||||
unsafe public delegate VkResult PFN_vkCreateInstance(VkInstanceCreateInfo* pCreateInfo, void* pAllocator, VkInstance* pInstance);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyInstance(VkInstance instance, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyInstance(VkInstance instance, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkEnumeratePhysicalDevices(VkInstance instance, uint* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
|
||||
unsafe public delegate VkResult PFN_vkEnumeratePhysicalDevices(VkInstance instance, uint* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties);
|
||||
unsafe public delegate void PFN_vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties);
|
||||
unsafe public delegate void PFN_vkGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties);
|
||||
unsafe public delegate void PFN_vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, byte* pLayerName, uint* pPropertyCount, VkExtensionProperties* pProperties);
|
||||
unsafe public delegate VkResult PFN_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, byte* pLayerName, uint* pPropertyCount, VkExtensionProperties* pProperties);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateDevice(VkPhysicalDevice physicalDevice, VkDeviceCreateInfo* pCreateInfo, void* pAllocator, VkDevice* pDevice);
|
||||
unsafe public delegate VkResult PFN_vkCreateDevice(VkPhysicalDevice physicalDevice, VkDeviceCreateInfo* pCreateInfo, void* pAllocator, VkDevice* pDevice);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyDevice(VkDevice device, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyDevice(VkDevice device, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkGetDeviceQueue(VkDevice device, uint queueFamilyIndex, uint queueIndex, VkQueue* pQueue);
|
||||
unsafe public delegate void PFN_vkGetDeviceQueue(VkDevice device, uint queueFamilyIndex, uint queueIndex, VkQueue* pQueue);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateSwapchainKHR(VkDevice device, VkSwapchainCreateInfoKHR* pCreateInfo, void* pAllocator, VkSwapchainKHR* pSwapchain);
|
||||
unsafe public delegate VkResult PFN_vkCreateSwapchainKHR(VkDevice device, VkSwapchainCreateInfoKHR* pCreateInfo, void* pAllocator, VkSwapchainKHR* pSwapchain);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint* pSwapchainImageCount, VkImage* pSwapchainImages);
|
||||
unsafe public delegate VkResult PFN_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint* pSwapchainImageCount, VkImage* pSwapchainImages);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateImageView(VkDevice device, VkImageViewCreateInfo* pCreateInfo, void* pAllocator, VkImageView* pView);
|
||||
unsafe public delegate VkResult PFN_vkCreateImageView(VkDevice device, VkImageViewCreateInfo* pCreateInfo, void* pAllocator, VkImageView* pView);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyImageView(VkDevice device, VkImageView imageView, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyImageView(VkDevice device, VkImageView imageView, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateImage(VkDevice device, VkImageCreateInfo* pCreateInfo, void* pAllocator, VkImage* pImage);
|
||||
unsafe public delegate VkResult PFN_vkCreateImage(VkDevice device, VkImageCreateInfo* pCreateInfo, void* pAllocator, VkImage* pImage);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyImage(VkDevice device, VkImage image, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyImage(VkDevice device, VkImage image, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkGetImageMemoryRequirements(VkDevice device, VkImage image, void* pMemoryRequirements);
|
||||
unsafe public delegate void PFN_vkGetImageMemoryRequirements(VkDevice device, VkImage image, void* pMemoryRequirements);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, ulong memoryOffset);
|
||||
unsafe public delegate VkResult PFN_vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, ulong memoryOffset);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateRenderPass(VkDevice device, VkRenderPassCreateInfo* pCreateInfo, void* pAllocator, VkRenderPass* pRenderPass);
|
||||
unsafe public delegate VkResult PFN_vkCreateRenderPass(VkDevice device, VkRenderPassCreateInfo* pCreateInfo, void* pAllocator, VkRenderPass* pRenderPass);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateFramebuffer(VkDevice device, VkFramebufferCreateInfo* pCreateInfo, void* pAllocator, VkFramebuffer* pFramebuffer);
|
||||
unsafe public delegate VkResult PFN_vkCreateFramebuffer(VkDevice device, VkFramebufferCreateInfo* pCreateInfo, void* pAllocator, VkFramebuffer* pFramebuffer);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateShaderModule(VkDevice device, VkShaderModuleCreateInfo* pCreateInfo, void* pAllocator, VkShaderModule* pShaderModule);
|
||||
unsafe public delegate VkResult PFN_vkCreateShaderModule(VkDevice device, VkShaderModuleCreateInfo* pCreateInfo, void* pAllocator, VkShaderModule* pShaderModule);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateDescriptorSetLayout(VkDevice device, VkDescriptorSetLayoutCreateInfo* pCreateInfo, void* pAllocator, VkDescriptorSetLayout* pSetLayout);
|
||||
unsafe public delegate VkResult PFN_vkCreateDescriptorSetLayout(VkDevice device, VkDescriptorSetLayoutCreateInfo* pCreateInfo, void* pAllocator, VkDescriptorSetLayout* pSetLayout);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreatePipelineLayout(VkDevice device, VkPipelineLayoutCreateInfo* pCreateInfo, void* pAllocator, VkPipelineLayout* pPipelineLayout);
|
||||
unsafe public delegate VkResult PFN_vkCreatePipelineLayout(VkDevice device, VkPipelineLayoutCreateInfo* pCreateInfo, void* pAllocator, VkPipelineLayout* pPipelineLayout);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateGraphicsPipelines(VkDevice device, ulong pipelineCache, uint createInfoCount, VkGraphicsPipelineCreateInfo* pCreateInfos, void* pAllocator, VkPipeline* pPipelines);
|
||||
unsafe public delegate VkResult PFN_vkCreateGraphicsPipelines(VkDevice device, ulong pipelineCache, uint createInfoCount, VkGraphicsPipelineCreateInfo* pCreateInfos, void* pAllocator, VkPipeline* pPipelines);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyPipeline(VkDevice device, VkPipeline pipeline, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyPipeline(VkDevice device, VkPipeline pipeline, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateDescriptorPool(VkDevice device, VkDescriptorPoolCreateInfo* pCreateInfo, void* pAllocator, VkDescriptorPool* pDescriptorPool);
|
||||
unsafe public delegate VkResult PFN_vkCreateDescriptorPool(VkDevice device, VkDescriptorPoolCreateInfo* pCreateInfo, void* pAllocator, VkDescriptorPool* pDescriptorPool);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkAllocateDescriptorSets(VkDevice device, VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets);
|
||||
unsafe public delegate VkResult PFN_vkAllocateDescriptorSets(VkDevice device, VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkUpdateDescriptorSets(VkDevice device, uint descriptorWriteCount, VkWriteDescriptorSet* pDescriptorWrites, uint descriptorCopyCount, void* pDescriptorCopies);
|
||||
unsafe public delegate void PFN_vkUpdateDescriptorSets(VkDevice device, uint descriptorWriteCount, VkWriteDescriptorSet* pDescriptorWrites, uint descriptorCopyCount, void* pDescriptorCopies);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateBuffer(VkDevice device, VkBufferCreateInfo* pCreateInfo, void* pAllocator, VkBuffer* pBuffer);
|
||||
unsafe public delegate VkResult PFN_vkCreateBuffer(VkDevice device, VkBufferCreateInfo* pCreateInfo, void* pAllocator, VkBuffer* pBuffer);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyBuffer(VkDevice device, VkBuffer buffer, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyBuffer(VkDevice device, VkBuffer buffer, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, void* pMemoryRequirements);
|
||||
unsafe public delegate void PFN_vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, void* pMemoryRequirements);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, ulong memoryOffset);
|
||||
unsafe public delegate VkResult PFN_vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, ulong memoryOffset);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkAllocateMemory(VkDevice device, VkMemoryAllocateInfo* pAllocateInfo, void* pAllocator, VkDeviceMemory* pMemory);
|
||||
unsafe public delegate VkResult PFN_vkAllocateMemory(VkDevice device, VkMemoryAllocateInfo* pAllocateInfo, void* pAllocator, VkDeviceMemory* pMemory);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkFreeMemory(VkDevice device, VkDeviceMemory memory, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkFreeMemory(VkDevice device, VkDeviceMemory memory, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkMapMemory(VkDevice device, VkDeviceMemory memory, ulong offset, ulong size, uint flags, void** ppData);
|
||||
unsafe public delegate VkResult PFN_vkMapMemory(VkDevice device, VkDeviceMemory memory, ulong offset, ulong size, uint flags, void** ppData);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkUnmapMemory(VkDevice device, VkDeviceMemory memory);
|
||||
unsafe public delegate void PFN_vkUnmapMemory(VkDevice device, VkDeviceMemory memory);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateCommandPool(VkDevice device, VkCommandPoolCreateInfo* pCreateInfo, void* pAllocator, VkCommandPool* pCommandPool);
|
||||
unsafe public delegate VkResult PFN_vkCreateCommandPool(VkDevice device, VkCommandPoolCreateInfo* pCreateInfo, void* pAllocator, VkCommandPool* pCommandPool);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkAllocateCommandBuffers(VkDevice device, VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
|
||||
unsafe public delegate VkResult PFN_vkAllocateCommandBuffers(VkDevice device, VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint commandBufferCount, VkCommandBuffer* pCommandBuffers);
|
||||
unsafe public delegate void PFN_vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint commandBufferCount, VkCommandBuffer* pCommandBuffers);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkBeginCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferBeginInfo* pBeginInfo);
|
||||
unsafe public delegate VkResult PFN_vkBeginCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferBeginInfo* pBeginInfo);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkEndCommandBuffer(VkCommandBuffer commandBuffer);
|
||||
unsafe public delegate VkResult PFN_vkEndCommandBuffer(VkCommandBuffer commandBuffer);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkResetCommandBuffer(VkCommandBuffer commandBuffer, uint flags);
|
||||
unsafe public delegate VkResult PFN_vkResetCommandBuffer(VkCommandBuffer commandBuffer, uint flags);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkQueueSubmit(VkQueue queue, uint submitCount, VkSubmitInfo* pSubmits, VkFence fence);
|
||||
unsafe public delegate VkResult PFN_vkQueueSubmit(VkQueue queue, uint submitCount, VkSubmitInfo* pSubmits, VkFence fence);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkQueueWaitIdle(VkQueue queue);
|
||||
unsafe public delegate VkResult PFN_vkQueueWaitIdle(VkQueue queue);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo);
|
||||
unsafe public delegate VkResult PFN_vkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, ulong timeout, VkSemaphore semaphore, VkFence fence, uint* pImageIndex);
|
||||
unsafe public delegate VkResult PFN_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, ulong timeout, VkSemaphore semaphore, VkFence fence, uint* pImageIndex);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateSemaphore(VkDevice device, VkSemaphoreCreateInfo* pCreateInfo, void* pAllocator, VkSemaphore* pSemaphore);
|
||||
unsafe public delegate VkResult PFN_vkCreateSemaphore(VkDevice device, VkSemaphoreCreateInfo* pCreateInfo, void* pAllocator, VkSemaphore* pSemaphore);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateFence(VkDevice device, VkFenceCreateInfo* pCreateInfo, void* pAllocator, VkFence* pFence);
|
||||
unsafe public delegate VkResult PFN_vkCreateFence(VkDevice device, VkFenceCreateInfo* pCreateInfo, void* pAllocator, VkFence* pFence);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroyFence(VkDevice device, VkFence fence, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroyFence(VkDevice device, VkFence fence, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkWaitForFences(VkDevice device, uint fenceCount, VkFence* pFences, uint waitAll, ulong timeout);
|
||||
unsafe public delegate VkResult PFN_vkWaitForFences(VkDevice device, uint fenceCount, VkFence* pFences, uint waitAll, ulong timeout);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkResetFences(VkDevice device, uint fenceCount, VkFence* pFences);
|
||||
unsafe public delegate VkResult PFN_vkResetFences(VkDevice device, uint fenceCount, VkFence* pFences);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents);
|
||||
unsafe public delegate void PFN_vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdEndRenderPass(VkCommandBuffer commandBuffer);
|
||||
unsafe public delegate void PFN_vkCmdEndRenderPass(VkCommandBuffer commandBuffer);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdBindPipeline(VkCommandBuffer commandBuffer, int pipelineBindPoint, VkPipeline pipeline);
|
||||
unsafe public delegate void PFN_vkCmdBindPipeline(VkCommandBuffer commandBuffer, int pipelineBindPoint, VkPipeline pipeline);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, int pipelineBindPoint, VkPipelineLayout layout, uint firstSet, uint descriptorSetCount, VkDescriptorSet* pDescriptorSets, uint dynamicOffsetCount, uint* pDynamicOffsets);
|
||||
unsafe public delegate void PFN_vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, int pipelineBindPoint, VkPipelineLayout layout, uint firstSet, uint descriptorSetCount, VkDescriptorSet* pDescriptorSets, uint dynamicOffsetCount, uint* pDynamicOffsets);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint firstBinding, uint bindingCount, VkBuffer* pBuffers, ulong* pOffsets);
|
||||
unsafe public delegate void PFN_vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint firstBinding, uint bindingCount, VkBuffer* pBuffers, ulong* pOffsets);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, ulong offset, VkIndexType indexType);
|
||||
unsafe public delegate void PFN_vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, ulong offset, VkIndexType indexType);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint indexCount, uint instanceCount, uint firstIndex, int vertexOffset, uint firstInstance);
|
||||
unsafe public delegate void PFN_vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint indexCount, uint instanceCount, uint firstIndex, int vertexOffset, uint firstInstance);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdDraw(VkCommandBuffer commandBuffer, uint vertexCount, uint instanceCount, uint firstVertex, uint firstInstance);
|
||||
unsafe public delegate void PFN_vkCmdDraw(VkCommandBuffer commandBuffer, uint vertexCount, uint instanceCount, uint firstVertex, uint firstInstance);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdSetViewport(VkCommandBuffer commandBuffer, uint firstViewport, uint viewportCount, VkViewport* pViewports);
|
||||
unsafe public delegate void PFN_vkCmdSetViewport(VkCommandBuffer commandBuffer, uint firstViewport, uint viewportCount, VkViewport* pViewports);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdSetScissor(VkCommandBuffer commandBuffer, uint firstScissor, uint scissorCount, VkRect2D* pScissors);
|
||||
unsafe public delegate void PFN_vkCmdSetScissor(VkCommandBuffer commandBuffer, uint firstScissor, uint scissorCount, VkRect2D* pScissors);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, int dependencyFlags, uint memoryBarrierCount, void* pMemoryBarriers, uint bufferMemoryBarrierCount, VkBufferMemoryBarrier* pBufferMemoryBarriers, uint imageMemoryBarrierCount, VkImageMemoryBarrier* pImageMemoryBarriers);
|
||||
unsafe public delegate void PFN_vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, int dependencyFlags, uint memoryBarrierCount, void* pMemoryBarriers, uint bufferMemoryBarrierCount, VkBufferMemoryBarrier* pBufferMemoryBarriers, uint imageMemoryBarrierCount, VkImageMemoryBarrier* pImageMemoryBarriers);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint regionCount, VkBufferCopy* pRegions);
|
||||
unsafe public delegate void PFN_vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint regionCount, VkBufferCopy* pRegions);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, int dstImageLayout, uint regionCount, VkBufferImageCopy* pRegions);
|
||||
unsafe public delegate void PFN_vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, int dstImageLayout, uint regionCount, VkBufferImageCopy* pRegions);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, int srcImageLayout, VkBuffer dstBuffer, uint regionCount, VkBufferImageCopy* pRegions);
|
||||
unsafe public delegate void PFN_vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, int srcImageLayout, VkBuffer dstBuffer, uint regionCount, VkBufferImageCopy* pRegions);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, int imageLayout, VkClearColorValue* pColor, uint rangeCount, VkImageSubresourceRange* pRanges);
|
||||
unsafe public delegate void PFN_vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, int imageLayout, VkClearColorValue* pColor, uint rangeCount, VkImageSubresourceRange* pRanges);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint offset, uint size, void* pValues);
|
||||
unsafe public delegate void PFN_vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint offset, uint size, void* pValues);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkCreateSampler(VkDevice device, VkSamplerCreateInfo* pCreateInfo, void* pAllocator, void* pSampler);
|
||||
unsafe public delegate VkResult PFN_vkCreateSampler(VkDevice device, VkSamplerCreateInfo* pCreateInfo, void* pAllocator, void* pSampler);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroySampler(VkDevice device, void* sampler, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroySampler(VkDevice device, void* sampler, void* pAllocator);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint queueFamilyIndex, VkSurfaceKHR surface, uint* pSupported);
|
||||
unsafe public delegate VkResult PFN_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint queueFamilyIndex, VkSurfaceKHR surface, uint* pSupported);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
|
||||
unsafe public delegate VkResult PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats);
|
||||
unsafe public delegate VkResult PFN_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate VkResult PFN_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint* pPresentModeCount, VkPresentModeKHR* pPresentModes);
|
||||
unsafe public delegate VkResult PFN_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint* pPresentModeCount, VkPresentModeKHR* pPresentModes);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
unsafe internal delegate void PFN_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, void* pAllocator);
|
||||
unsafe public delegate void PFN_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, void* pAllocator);
|
||||
|
||||
@@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Engine.Graphics.Vulkan;
|
||||
|
||||
internal sealed unsafe class VulkanBuffer : IDisposable
|
||||
public sealed unsafe class VulkanBuffer : IDisposable
|
||||
{
|
||||
public VkBuffer Buffer;
|
||||
public VkDeviceMemory Memory;
|
||||
|
||||
@@ -5,7 +5,7 @@ using SDL;
|
||||
|
||||
namespace Engine.Graphics.Vulkan;
|
||||
|
||||
internal sealed unsafe class VulkanContext : IDisposable
|
||||
public sealed unsafe class VulkanContext : IDisposable
|
||||
{
|
||||
public VkInstance Instance;
|
||||
public VkPhysicalDevice PhysicalDevice;
|
||||
|
||||
@@ -0,0 +1,521 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Numerics;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Engine.Graphics.Vulkan;
|
||||
|
||||
public sealed unsafe class VulkanImGui : IDisposable
|
||||
{
|
||||
private readonly VulkanContext _ctx;
|
||||
private readonly VulkanSwapchain _swapchain;
|
||||
private VkCommandPool _initCommandPool;
|
||||
private VkPipeline _pipeline;
|
||||
private VkPipelineLayout _pipelineLayout;
|
||||
private VkDescriptorSetLayout _descriptorSetLayout;
|
||||
private VkDescriptorPool _descriptorPool;
|
||||
private VkDescriptorSet _descriptorSet;
|
||||
private VkShaderModule _vertexShader;
|
||||
private VkShaderModule _fragmentShader;
|
||||
private VkImage _fontImage;
|
||||
private VkDeviceMemory _fontImageMemory;
|
||||
private VkImageView _fontImageView;
|
||||
private VkSampler _fontSampler;
|
||||
private VulkanBuffer? _vertexBuffer;
|
||||
private VulkanBuffer? _indexBuffer;
|
||||
|
||||
private static readonly byte[] VkDescriptorWriteDummy = new byte[1];
|
||||
|
||||
public VulkanImGui(VulkanContext ctx, VulkanSwapchain swapchain)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_swapchain = swapchain;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private unsafe void Initialize()
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
io.Fonts.AddFontDefault();
|
||||
io.Fonts.Build();
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo = default;
|
||||
poolInfo.sType = VkStructureType.CommandPoolCreateInfo;
|
||||
poolInfo.flags = 0x00000002;
|
||||
poolInfo.queueFamilyIndex = _ctx.GraphicsFamily;
|
||||
VkCommandPool pool;
|
||||
Vk.CheckResult(Vk.vkCreateCommandPool(_ctx.Device, &poolInfo, null, &pool), "vkCreateCommandPool (ImGui init)");
|
||||
_initCommandPool = pool;
|
||||
|
||||
CreateFontTexture();
|
||||
CreateShaders();
|
||||
CreateDescriptorSetLayout();
|
||||
CreatePipelineLayout();
|
||||
CreatePipeline();
|
||||
CreateDescriptorPoolAndSet();
|
||||
|
||||
Vk.vkDestroyCommandPool(_ctx.Device, _initCommandPool, null);
|
||||
}
|
||||
|
||||
private unsafe void CreateFontTexture()
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
int width, height, bpp;
|
||||
byte* pixels;
|
||||
io.Fonts.GetTexDataAsRGBA32(out pixels, out width, out height, out bpp);
|
||||
|
||||
VkImageCreateInfo imageInfo = default;
|
||||
imageInfo.sType = VkStructureType.ImageCreateInfo;
|
||||
imageInfo.imageType = VkImageType._2D;
|
||||
imageInfo.format = VkFormat.R8G8B8A8Unorm;
|
||||
imageInfo.extent = new VkExtent3D { width = width, height = height, depth = 1 };
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.samples = VkSampleCountFlags.One;
|
||||
imageInfo.tiling = 0;
|
||||
imageInfo.usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst;
|
||||
imageInfo.sharingMode = VkSharingMode.Exclusive;
|
||||
imageInfo.initialLayout = 0;
|
||||
|
||||
VkImage fontImage;
|
||||
Vk.CheckResult(Vk.vkCreateImage(_ctx.Device, &imageInfo, null, &fontImage), "vkCreateImage (font)");
|
||||
_fontImage = fontImage;
|
||||
|
||||
VkMemoryRequirements2 memReq;
|
||||
Vk.vkGetImageMemoryRequirements(_ctx.Device, _fontImage, &memReq);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = default;
|
||||
allocInfo.sType = VkStructureType.MemoryAllocateInfo;
|
||||
allocInfo.allocationSize = memReq.size;
|
||||
allocInfo.memoryTypeIndex = _ctx.FindMemoryType(memReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);
|
||||
|
||||
VkDeviceMemory fontMem;
|
||||
Vk.CheckResult(Vk.vkAllocateMemory(_ctx.Device, &allocInfo, null, &fontMem), "vkAllocateMemory (font)");
|
||||
_fontImageMemory = fontMem;
|
||||
Vk.CheckResult(Vk.vkBindImageMemory(_ctx.Device, _fontImage, _fontImageMemory, 0), "vkBindImageMemory (font)");
|
||||
|
||||
var imageSize = (ulong)(width * height * 4);
|
||||
var staging = new VulkanBuffer(_ctx, imageSize,
|
||||
VkBufferUsageFlags.TransferSrc,
|
||||
VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
|
||||
|
||||
Buffer.MemoryCopy(pixels, staging.MappedData, imageSize, imageSize);
|
||||
|
||||
var cmd = VulkanBuffer.BeginSingleTimeCommands(_ctx, _initCommandPool);
|
||||
|
||||
var barrier = new VkImageMemoryBarrier
|
||||
{
|
||||
sType = VkStructureType.ImageMemoryBarrier,
|
||||
srcAccessMask = 0,
|
||||
dstAccessMask = VkAccessFlags.TransferWrite,
|
||||
oldLayout = VkImageLayout.Undefined,
|
||||
newLayout = VkImageLayout.TransferDstOptimal,
|
||||
srcQueueFamilyIndex = ~0u,
|
||||
dstQueueFamilyIndex = ~0u,
|
||||
image = _fontImage,
|
||||
subresourceRange = new VkImageSubresourceRange
|
||||
{
|
||||
aspectMask = VkImageAspectFlags.Color,
|
||||
baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1
|
||||
}
|
||||
};
|
||||
|
||||
Vk.vkCmdPipelineBarrier(cmd, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer,
|
||||
0, 0, null, 0, null, 1, &barrier);
|
||||
|
||||
var region = new VkBufferImageCopy
|
||||
{
|
||||
bufferOffset = 0,
|
||||
bufferRowLength = (uint)width,
|
||||
bufferImageHeight = (uint)height,
|
||||
imageSubresource = new VkImageSubresourceLayers
|
||||
{
|
||||
aspectMask = VkImageAspectFlags.Color,
|
||||
mipLevel = 0, baseArrayLayer = 0, layerCount = 1
|
||||
},
|
||||
imageOffset = new VkOffset3D { x = 0, y = 0, z = 0 },
|
||||
imageExtent = new VkExtent3D { width = width, height = height, depth = 1 }
|
||||
};
|
||||
|
||||
Vk.vkCmdCopyBufferToImage(cmd, staging.Buffer, _fontImage,
|
||||
(int)VkImageLayout.TransferDstOptimal, 1, ®ion);
|
||||
|
||||
var barrier2 = new VkImageMemoryBarrier
|
||||
{
|
||||
sType = VkStructureType.ImageMemoryBarrier,
|
||||
srcAccessMask = VkAccessFlags.TransferWrite,
|
||||
dstAccessMask = VkAccessFlags.ShaderRead,
|
||||
oldLayout = VkImageLayout.TransferDstOptimal,
|
||||
newLayout = VkImageLayout.ShaderReadOnlyOptimal,
|
||||
srcQueueFamilyIndex = ~0u,
|
||||
dstQueueFamilyIndex = ~0u,
|
||||
image = _fontImage,
|
||||
subresourceRange = new VkImageSubresourceRange
|
||||
{
|
||||
aspectMask = VkImageAspectFlags.Color,
|
||||
baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1
|
||||
}
|
||||
};
|
||||
|
||||
Vk.vkCmdPipelineBarrier(cmd, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader,
|
||||
0, 0, null, 0, null, 1, &barrier2);
|
||||
|
||||
VulkanBuffer.EndSingleTimeCommands(_ctx, _initCommandPool, cmd);
|
||||
staging.Dispose();
|
||||
|
||||
VkImageViewCreateInfo viewInfo = default;
|
||||
viewInfo.sType = VkStructureType.ImageViewCreateInfo;
|
||||
viewInfo.image = _fontImage;
|
||||
viewInfo.viewType = VkImageViewType._2D;
|
||||
viewInfo.format = VkFormat.R8G8B8A8Unorm;
|
||||
viewInfo.subresourceRange = new VkImageSubresourceRange
|
||||
{
|
||||
aspectMask = VkImageAspectFlags.Color,
|
||||
baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1
|
||||
};
|
||||
|
||||
VkImageView fontView;
|
||||
Vk.CheckResult(Vk.vkCreateImageView(_ctx.Device, &viewInfo, null, &fontView), "vkCreateImageView (font)");
|
||||
_fontImageView = fontView;
|
||||
|
||||
VkSamplerCreateInfo samplerInfo = default;
|
||||
samplerInfo.sType = VkStructureType.SamplerCreateInfo;
|
||||
samplerInfo.magFilter = VkFilter.Linear;
|
||||
samplerInfo.minFilter = VkFilter.Linear;
|
||||
samplerInfo.mipmapMode = VkSamplerMipmapMode.Linear;
|
||||
samplerInfo.addressModeU = VkSamplerAddressMode.Repeat;
|
||||
samplerInfo.addressModeV = VkSamplerAddressMode.Repeat;
|
||||
samplerInfo.addressModeW = VkSamplerAddressMode.Repeat;
|
||||
samplerInfo.minLod = -1000;
|
||||
samplerInfo.maxLod = 1000;
|
||||
|
||||
VkSampler fontSampler;
|
||||
Vk.CheckResult(Vk.vkCreateSampler(_ctx.Device, &samplerInfo, null, (void*)&fontSampler), "vkCreateSampler (font)");
|
||||
_fontSampler = fontSampler;
|
||||
}
|
||||
|
||||
private unsafe VkShaderModule LoadShader(string path)
|
||||
{
|
||||
var fullPath = Path.Combine(AppContext.BaseDirectory, path);
|
||||
if (!File.Exists(fullPath))
|
||||
throw new FileNotFoundException($"ImGui SPIR-V shader not found: {fullPath}");
|
||||
|
||||
var code = File.ReadAllBytes(fullPath);
|
||||
fixed (byte* pCode = code)
|
||||
{
|
||||
VkShaderModuleCreateInfo createInfo = default;
|
||||
createInfo.sType = VkStructureType.ShaderModuleCreateInfo;
|
||||
createInfo.codeSize = (ulong)code.Length;
|
||||
createInfo.pCode = (uint*)pCode;
|
||||
|
||||
VkShaderModule module;
|
||||
Vk.CheckResult(Vk.vkCreateShaderModule(_ctx.Device, &createInfo, null, &module), $"vkCreateShaderModule ({path})");
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateShaders()
|
||||
{
|
||||
_vertexShader = LoadShader("Shaders/imgui.vert.spv");
|
||||
_fragmentShader = LoadShader("Shaders/imgui.frag.spv");
|
||||
}
|
||||
|
||||
private unsafe void CreateDescriptorSetLayout()
|
||||
{
|
||||
var binding = new VkDescriptorSetLayoutBinding
|
||||
{
|
||||
binding = 0,
|
||||
descriptorType = VkDescriptorType.CombinedImageSampler,
|
||||
descriptorCount = 1,
|
||||
stageFlags = VkShaderStageFlags.Fragment,
|
||||
pImmutableSamplers = null
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo createInfo = default;
|
||||
createInfo.sType = VkStructureType.DescriptorSetLayoutCreateInfo;
|
||||
createInfo.bindingCount = 1;
|
||||
createInfo.pBindings = &binding;
|
||||
|
||||
VkDescriptorSetLayout dsLayout;
|
||||
Vk.CheckResult(Vk.vkCreateDescriptorSetLayout(_ctx.Device, &createInfo, null, &dsLayout), "vkCreateDescriptorSetLayout (ImGui)");
|
||||
_descriptorSetLayout = dsLayout;
|
||||
}
|
||||
|
||||
private unsafe void CreatePipelineLayout()
|
||||
{
|
||||
var pushConstantRange = new VkPushConstantRange
|
||||
{
|
||||
stageFlags = VkShaderStageFlags.Vertex,
|
||||
offset = 0,
|
||||
size = 16
|
||||
};
|
||||
|
||||
var dsLayout = _descriptorSetLayout;
|
||||
VkPipelineLayoutCreateInfo createInfo = default;
|
||||
createInfo.sType = VkStructureType.PipelineLayoutCreateInfo;
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &dsLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &pushConstantRange;
|
||||
|
||||
VkPipelineLayout pipeLayout;
|
||||
Vk.CheckResult(Vk.vkCreatePipelineLayout(_ctx.Device, &createInfo, null, &pipeLayout), "vkCreatePipelineLayout (ImGui)");
|
||||
_pipelineLayout = pipeLayout;
|
||||
}
|
||||
|
||||
private unsafe void CreatePipeline()
|
||||
{
|
||||
var mainName = Vk.AllocUtf8("main");
|
||||
|
||||
var stages = stackalloc VkPipelineShaderStageCreateInfo[2];
|
||||
stages[0] = new VkPipelineShaderStageCreateInfo
|
||||
{
|
||||
sType = VkStructureType.PipelineShaderStageCreateInfo,
|
||||
stage = VkShaderStageFlags.Vertex,
|
||||
module = _vertexShader,
|
||||
pName = mainName
|
||||
};
|
||||
stages[1] = new VkPipelineShaderStageCreateInfo
|
||||
{
|
||||
sType = VkStructureType.PipelineShaderStageCreateInfo,
|
||||
stage = VkShaderStageFlags.Fragment,
|
||||
module = _fragmentShader,
|
||||
pName = mainName
|
||||
};
|
||||
|
||||
var bindingDesc = new VkVertexInputBindingDescription
|
||||
{
|
||||
binding = 0,
|
||||
stride = (uint)Marshal.SizeOf<ImDrawVert>(),
|
||||
inputRate = 0
|
||||
};
|
||||
|
||||
var attrDescs = stackalloc VkVertexInputAttributeDescription[3];
|
||||
attrDescs[0] = new VkVertexInputAttributeDescription { location = 0, binding = 0, format = VkFormat.R32G32Sfloat, offset = 0 };
|
||||
attrDescs[1] = new VkVertexInputAttributeDescription { location = 1, binding = 0, format = VkFormat.R32G32Sfloat, offset = 8 };
|
||||
attrDescs[2] = new VkVertexInputAttributeDescription { location = 2, binding = 0, format = VkFormat.R8G8B8A8Unorm, offset = 16 };
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputState = default;
|
||||
vertexInputState.sType = VkStructureType.PipelineVertexInputStateCreateInfo;
|
||||
vertexInputState.vertexBindingDescriptionCount = 1;
|
||||
vertexInputState.pVertexBindingDescriptions = &bindingDesc;
|
||||
vertexInputState.vertexAttributeDescriptionCount = 3;
|
||||
vertexInputState.pVertexAttributeDescriptions = attrDescs;
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = default;
|
||||
inputAssemblyState.sType = VkStructureType.PipelineInputAssemblyStateCreateInfo;
|
||||
inputAssemblyState.topology = VkPrimitiveTopology.TriangleList;
|
||||
|
||||
var viewport = new VkViewport();
|
||||
var scissor = new VkRect2D();
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState = default;
|
||||
viewportState.sType = VkStructureType.PipelineViewportStateCreateInfo;
|
||||
viewportState.viewportCount = 1;
|
||||
viewportState.pViewports = &viewport;
|
||||
viewportState.scissorCount = 1;
|
||||
viewportState.pScissors = &scissor;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterState = default;
|
||||
rasterState.sType = VkStructureType.PipelineRasterizationStateCreateInfo;
|
||||
rasterState.polygonMode = VkPolygonMode.Fill;
|
||||
rasterState.cullMode = VkCullModeFlags.None;
|
||||
rasterState.frontFace = VkFrontFace.Clockwise;
|
||||
rasterState.lineWidth = 1.0f;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo msState = default;
|
||||
msState.sType = VkStructureType.PipelineMultisampleStateCreateInfo;
|
||||
msState.rasterizationSamples = VkSampleCountFlags.One;
|
||||
|
||||
VkPipelineColorBlendAttachmentState blendAttachment = default;
|
||||
blendAttachment.blendEnable = 1;
|
||||
blendAttachment.srcColorBlendFactor = VkBlendFactor.SrcAlpha;
|
||||
blendAttachment.dstColorBlendFactor = VkBlendFactor.OneMinusSrcAlpha;
|
||||
blendAttachment.colorBlendOp = VkBlendOp.Add;
|
||||
blendAttachment.srcAlphaBlendFactor = VkBlendFactor.OneMinusSrcAlpha;
|
||||
blendAttachment.dstAlphaBlendFactor = VkBlendFactor.Zero;
|
||||
blendAttachment.alphaBlendOp = VkBlendOp.Add;
|
||||
blendAttachment.colorWriteMask = VkColorComponentFlags.R | VkColorComponentFlags.G | VkColorComponentFlags.B | VkColorComponentFlags.A;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo blendState = default;
|
||||
blendState.sType = VkStructureType.PipelineColorBlendStateCreateInfo;
|
||||
blendState.attachmentCount = 1;
|
||||
blendState.pAttachments = &blendAttachment;
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = default;
|
||||
pipelineInfo.sType = VkStructureType.GraphicsPipelineCreateInfo;
|
||||
pipelineInfo.stageCount = 2;
|
||||
pipelineInfo.pStages = stages;
|
||||
pipelineInfo.pVertexInputState = &vertexInputState;
|
||||
pipelineInfo.pInputAssemblyState = &inputAssemblyState;
|
||||
pipelineInfo.pViewportState = &viewportState;
|
||||
pipelineInfo.pRasterizationState = &rasterState;
|
||||
pipelineInfo.pMultisampleState = &msState;
|
||||
pipelineInfo.pColorBlendState = &blendState;
|
||||
pipelineInfo.layout = _pipelineLayout;
|
||||
pipelineInfo.renderPass = _swapchain.RenderPass;
|
||||
pipelineInfo.subpass = 0;
|
||||
|
||||
VkPipeline pipe;
|
||||
Vk.CheckResult(Vk.vkCreateGraphicsPipelines(_ctx.Device, 0, 1, &pipelineInfo, null, &pipe), "vkCreateGraphicsPipelines (ImGui)");
|
||||
_pipeline = pipe;
|
||||
|
||||
Vk.FreeUtf8(mainName);
|
||||
Console.WriteLine("[Vulkan] ImGui pipeline created.");
|
||||
}
|
||||
|
||||
private unsafe void CreateDescriptorPoolAndSet()
|
||||
{
|
||||
var poolSize = new VkDescriptorPoolSize
|
||||
{
|
||||
type = VkDescriptorType.CombinedImageSampler,
|
||||
descriptorCount = 1
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo = default;
|
||||
poolInfo.sType = VkStructureType.DescriptorPoolCreateInfo;
|
||||
poolInfo.flags = VkDescriptorPoolCreateFlags.FreeDescriptorSet;
|
||||
poolInfo.maxSets = 1;
|
||||
poolInfo.poolSizeCount = 1;
|
||||
poolInfo.pPoolSizes = &poolSize;
|
||||
|
||||
VkDescriptorPool descPool;
|
||||
Vk.CheckResult(Vk.vkCreateDescriptorPool(_ctx.Device, &poolInfo, null, &descPool), "vkCreateDescriptorPool (ImGui)");
|
||||
_descriptorPool = descPool;
|
||||
|
||||
VkDescriptorSetAllocateInfo allocInfo = default;
|
||||
allocInfo.sType = VkStructureType.DescriptorSetAllocateInfo;
|
||||
allocInfo.descriptorPool = _descriptorPool;
|
||||
allocInfo.descriptorSetCount = 1;
|
||||
var dsLayout = _descriptorSetLayout;
|
||||
allocInfo.pSetLayouts = &dsLayout;
|
||||
|
||||
VkDescriptorSet descSet;
|
||||
Vk.CheckResult(Vk.vkAllocateDescriptorSets(_ctx.Device, &allocInfo, &descSet), "vkAllocateDescriptorSets (ImGui)");
|
||||
_descriptorSet = descSet;
|
||||
|
||||
var imageInfo = new VkDescriptorImageInfo
|
||||
{
|
||||
sampler = _fontSampler,
|
||||
imageView = _fontImageView,
|
||||
imageLayout = VkImageLayout.ShaderReadOnlyOptimal
|
||||
};
|
||||
|
||||
VkWriteDescriptorSet writeInfo = default;
|
||||
writeInfo.sType = VkStructureType.WriteDescriptorSet;
|
||||
writeInfo.dstSet = _descriptorSet;
|
||||
writeInfo.dstBinding = 0;
|
||||
writeInfo.descriptorCount = 1;
|
||||
writeInfo.descriptorType = VkDescriptorType.CombinedImageSampler;
|
||||
writeInfo.pImageInfo = &imageInfo;
|
||||
|
||||
Vk.vkUpdateDescriptorSets(_ctx.Device, 1, &writeInfo, 0, null);
|
||||
}
|
||||
|
||||
public unsafe void Render(VkCommandBuffer cmd)
|
||||
{
|
||||
var drawData = ImGui.GetDrawData();
|
||||
if (drawData.CmdListsCount == 0) return;
|
||||
|
||||
drawData.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale);
|
||||
UpdateBuffers(drawData);
|
||||
|
||||
Vk.vkCmdBindPipeline(cmd, 0, _pipeline);
|
||||
|
||||
var set = _descriptorSet;
|
||||
Vk.vkCmdBindDescriptorSets(cmd, 0, _pipelineLayout, 0, 1, &set, 0, null);
|
||||
|
||||
var displaySize = ImGui.GetIO().DisplaySize;
|
||||
var scale = new Vector2(2.0f / displaySize.X, 2.0f / displaySize.Y);
|
||||
var pushData = stackalloc float[2];
|
||||
pushData[0] = scale.X;
|
||||
pushData[1] = -scale.Y;
|
||||
|
||||
Vk.vkCmdPushConstants(cmd, _pipelineLayout, VkShaderStageFlags.Vertex, 0, 8, pushData);
|
||||
|
||||
var vb = _vertexBuffer!.Buffer;
|
||||
var offset = 0ul;
|
||||
Vk.vkCmdBindVertexBuffers(cmd, 0, 1, &vb, &offset);
|
||||
Vk.vkCmdBindIndexBuffer(cmd, _indexBuffer!.Buffer, 0, VkIndexType.Uint16);
|
||||
|
||||
var indexOffset = 0u;
|
||||
var vtxOffset = 0u;
|
||||
for (var n = 0; n < drawData.CmdListsCount; n++)
|
||||
{
|
||||
var cmdList = new ImDrawListPtr(((ImDrawList**)drawData.CmdLists.Data)[n]);
|
||||
for (var i = 0; i < cmdList.CmdBuffer.Size; i++)
|
||||
{
|
||||
var imCmd = cmdList.CmdBuffer[i];
|
||||
Vk.vkCmdDrawIndexed(cmd, (uint)imCmd.ElemCount, 1, indexOffset, (int)vtxOffset, 0);
|
||||
indexOffset += (uint)imCmd.ElemCount;
|
||||
}
|
||||
vtxOffset += (uint)cmdList.VtxBuffer.Size;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void UpdateBuffers(ImDrawDataPtr drawData)
|
||||
{
|
||||
var vertexSize = (ulong)(drawData.TotalVtxCount * Marshal.SizeOf<ImDrawVert>());
|
||||
var indexSize = (ulong)(drawData.TotalIdxCount * sizeof(ushort));
|
||||
|
||||
if (vertexSize == 0 || indexSize == 0) return;
|
||||
|
||||
if (_vertexBuffer == null || _vertexBuffer.Size < vertexSize)
|
||||
{
|
||||
_vertexBuffer?.Dispose();
|
||||
_vertexBuffer = new VulkanBuffer(_ctx, vertexSize,
|
||||
VkBufferUsageFlags.VertexBuffer,
|
||||
VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
|
||||
}
|
||||
|
||||
if (_indexBuffer == null || _indexBuffer.Size < indexSize)
|
||||
{
|
||||
_indexBuffer?.Dispose();
|
||||
_indexBuffer = new VulkanBuffer(_ctx, indexSize,
|
||||
VkBufferUsageFlags.IndexBuffer,
|
||||
VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
|
||||
}
|
||||
|
||||
var vtxDst = (byte*)_vertexBuffer.MappedData;
|
||||
var idxDst = (ushort*)_indexBuffer.MappedData;
|
||||
|
||||
for (var n = 0; n < drawData.CmdListsCount; n++)
|
||||
{
|
||||
var cmdList = new ImDrawListPtr(((ImDrawList**)drawData.CmdLists.Data)[n]);
|
||||
var vtxSize = cmdList.VtxBuffer.Size * Marshal.SizeOf<ImDrawVert>();
|
||||
var idxSize = cmdList.IdxBuffer.Size * sizeof(ushort);
|
||||
|
||||
Buffer.MemoryCopy((void*)cmdList.VtxBuffer.Data, vtxDst, vtxSize, vtxSize);
|
||||
Buffer.MemoryCopy((void*)cmdList.IdxBuffer.Data, idxDst, idxSize, idxSize);
|
||||
|
||||
vtxDst += vtxSize;
|
||||
idxDst += cmdList.IdxBuffer.Size;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Vk.vkQueueWaitIdle(_ctx.GraphicsQueue);
|
||||
|
||||
_vertexBuffer?.Dispose();
|
||||
_indexBuffer?.Dispose();
|
||||
|
||||
if (_fontSampler.Value != 0) Vk.vkDestroySampler(_ctx.Device, (void*)_fontSampler.Value, null);
|
||||
if (_fontImageView.Value != 0) Vk.vkDestroyImageView(_ctx.Device, _fontImageView, null);
|
||||
if (_fontImage.Value != 0) Vk.vkDestroyImage(_ctx.Device, _fontImage, null);
|
||||
if (_fontImageMemory.Value != 0) Vk.vkFreeMemory(_ctx.Device, _fontImageMemory, null);
|
||||
if (_descriptorPool.Value != 0) Vk.vkDestroyDescriptorPool(_ctx.Device, _descriptorPool, null);
|
||||
if (_pipeline.Value != 0) Vk.vkDestroyPipeline(_ctx.Device, _pipeline, null);
|
||||
if (_pipelineLayout.Value != 0) Vk.vkDestroyPipelineLayout(_ctx.Device, _pipelineLayout, null);
|
||||
if (_descriptorSetLayout.Value != 0) Vk.vkDestroyDescriptorSetLayout(_ctx.Device, _descriptorSetLayout, null);
|
||||
if (_vertexShader.Value != 0) Vk.vkDestroyShaderModule(_ctx.Device, _vertexShader, null);
|
||||
if (_fragmentShader.Value != 0) Vk.vkDestroyShaderModule(_ctx.Device, _fragmentShader, null);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct VkDescriptorImageInfo
|
||||
{
|
||||
public VkSampler sampler;
|
||||
public VkImageView imageView;
|
||||
public VkImageLayout imageLayout;
|
||||
}
|
||||
@@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Engine.Graphics.Vulkan;
|
||||
|
||||
internal static unsafe partial class VulkanNative
|
||||
public static unsafe partial class VulkanNative
|
||||
{
|
||||
private const string VulkanLib = "vulkan-1.dll";
|
||||
private const string VulkanLibLinux = "libvulkan.so.1";
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
|
||||
namespace Engine.Graphics.Vulkan;
|
||||
|
||||
internal sealed unsafe class VulkanPipeline : IDisposable
|
||||
public sealed unsafe class VulkanPipeline : IDisposable
|
||||
{
|
||||
public VkPipelineLayout PipelineLayout;
|
||||
public VkPipeline Pipeline;
|
||||
|
||||
@@ -7,11 +7,12 @@ using Flecs.NET.Core;
|
||||
|
||||
namespace Engine.Graphics.Vulkan;
|
||||
|
||||
internal sealed unsafe class VulkanRenderer : IRenderer, IScreenshotProvider
|
||||
public sealed unsafe class VulkanRenderer : IRenderer, IScreenshotProvider
|
||||
{
|
||||
private readonly VulkanContext _ctx;
|
||||
private readonly VulkanSwapchain _swapchain;
|
||||
public readonly VulkanContext _ctx;
|
||||
public readonly VulkanSwapchain _swapchain;
|
||||
private readonly VulkanPipeline _pipeline;
|
||||
public VulkanImGui? ImGuiLayer;
|
||||
|
||||
private VkCommandPool _commandPool;
|
||||
private VkCommandBuffer[] _commandBuffers = Array.Empty<VkCommandBuffer>();
|
||||
@@ -536,6 +537,11 @@ internal sealed unsafe class VulkanRenderer : IRenderer, IScreenshotProvider
|
||||
}
|
||||
});
|
||||
|
||||
if (ImGuiLayer != null)
|
||||
{
|
||||
ImGuiLayer.Render(cmd);
|
||||
}
|
||||
|
||||
Vk.vkCmdEndRenderPass(cmd);
|
||||
|
||||
if (_screenshotRequested)
|
||||
|
||||
@@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Engine.Graphics.Vulkan;
|
||||
|
||||
internal sealed unsafe class VulkanSwapchain : IDisposable
|
||||
public sealed unsafe class VulkanSwapchain : IDisposable
|
||||
{
|
||||
public VkSwapchainKHR Swapchain;
|
||||
public VkImage[] SwapchainImages = Array.Empty<VkImage>();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user