feat: push constants + UBO descriptor sets — rotating triangle with VP matrix

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