fix: single push constant range (0-160, Vertex|Fragment) — fixes validation errors

- Vulkan spec: each stage can only appear in ONE push constant range
- Merged 3 ranges into 1: offset=0, size=160, stageFlags=Vertex|Fragment
- Both main and shadow pipelines use same single range
- Push constants packed into 160-byte buffer and sent in one call
- Shadow pass: restored vertex/index buffer binding + push constants
- Fixes: device lost, validation errors, missing shadow geometry
This commit is contained in:
emil28092005
2026-06-18 20:21:54 +03:00
parent dd86f6e9ad
commit c32c75cd69
3 changed files with 33 additions and 32 deletions
+5 -18
View File
@@ -150,24 +150,11 @@ internal sealed unsafe class VulkanPipeline : IDisposable
pDynamicStates = dynamicStates, pDynamicStates = dynamicStates,
}; };
var pushConstantRanges = stackalloc VkPushConstantRange[3]; var pushConstantRange = new VkPushConstantRange
pushConstantRanges[0] = new VkPushConstantRange
{
stageFlags = VkShaderStageFlags.Vertex,
offset = 0,
size = 64,
};
pushConstantRanges[1] = new VkPushConstantRange
{
stageFlags = VkShaderStageFlags.Fragment,
offset = 64,
size = 32,
};
pushConstantRanges[2] = new VkPushConstantRange
{ {
stageFlags = VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, stageFlags = VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment,
offset = 96, offset = 0,
size = 64, size = 160,
}; };
var descLayout = DescriptorSetLayout; var descLayout = DescriptorSetLayout;
@@ -176,8 +163,8 @@ internal sealed unsafe class VulkanPipeline : IDisposable
sType = VkStructureType.PipelineLayoutCreateInfo, sType = VkStructureType.PipelineLayoutCreateInfo,
setLayoutCount = 1, setLayoutCount = 1,
pSetLayouts = &descLayout, pSetLayouts = &descLayout,
pushConstantRangeCount = 3, pushConstantRangeCount = 1,
pPushConstantRanges = (nint)pushConstantRanges, pPushConstantRanges = (nint)(&pushConstantRange),
}; };
fixed (VkPipelineLayout* layoutPtr = &PipelineLayout) fixed (VkPipelineLayout* layoutPtr = &PipelineLayout)
+25 -9
View File
@@ -235,6 +235,22 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen
if (!dc.castShadow) continue; if (!dc.castShadow) continue;
var vertexBuf = dc.vertexBuf; var vertexBuf = dc.vertexBuf;
ulong offset = 0;
Vk.vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBuf, &offset);
Vk.vkCmdBindIndexBuffer(cmd, dc.indexBuf, 0, 1);
// Pack all push constants for shadow pass
var pcData = stackalloc byte[160];
var modelCopy = dc.model;
System.Buffer.MemoryCopy(&modelCopy, pcData, 64, 64);
var lpCopy = lightPos;
System.Buffer.MemoryCopy(&lpCopy, pcData + 64, 16, 16);
var lcCopy = lightColor;
System.Buffer.MemoryCopy(&lcCopy, pcData + 80, 16, 16);
var lvpCopy = lightViewProj;
System.Buffer.MemoryCopy(&lvpCopy, pcData + 96, 64, 64);
Vk.vkCmdPushConstants(cmd, _shadowMap.PipelineLayout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, 0, 160, pcData);
Vk.vkCmdDrawIndexed(cmd, dc.indexCount, 1, 0, 0, 0); Vk.vkCmdDrawIndexed(cmd, dc.indexCount, 1, 0, 0, 0);
} }
@@ -332,18 +348,18 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen
Vk.vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBuf, &offset); Vk.vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBuf, &offset);
Vk.vkCmdBindIndexBuffer(cmd, dc.indexBuf, 0, 1); Vk.vkCmdBindIndexBuffer(cmd, dc.indexBuf, 0, 1);
var model = dc.model; // Pack all push constants: model(64) + lightPos(16) + lightColor(16) + lightViewProj(64) = 160
Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Vertex, 0, 64, &model); var pcData = stackalloc byte[160];
var modelCopy = dc.model;
// Light data as push constants at offset 64 (fragment stage) System.Buffer.MemoryCopy(&modelCopy, pcData, 64, 64);
var lpCopy = lightPos; var lpCopy = lightPos;
Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Fragment, 64, 16, &lpCopy); System.Buffer.MemoryCopy(&lpCopy, pcData + 64, 16, 16);
var lcCopy = lightColor; var lcCopy = lightColor;
Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Fragment, 80, 16, &lcCopy); System.Buffer.MemoryCopy(&lcCopy, pcData + 80, 16, 16);
// Light view-proj at offset 96 (vertex + fragment)
var lvpCopy = lightViewProj; var lvpCopy = lightViewProj;
Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, 96, 64, &lvpCopy); System.Buffer.MemoryCopy(&lvpCopy, pcData + 96, 64, 64);
Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, 0, 160, pcData);
Vk.vkCmdDrawIndexed(cmd, dc.indexCount, 1, 0, 0, 0); Vk.vkCmdDrawIndexed(cmd, dc.indexCount, 1, 0, 0, 0);
} }
@@ -205,16 +205,14 @@ internal sealed unsafe class VulkanShadowMap : IDisposable
pDynamicStates = dynamicStates, pDynamicStates = dynamicStates,
}; };
var pushConstantRanges = stackalloc VkPushConstantRange[2]; var pushConstantRange = new VkPushConstantRange { stageFlags = VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, offset = 0, size = 160 };
pushConstantRanges[0] = new VkPushConstantRange { stageFlags = VkShaderStageFlags.Vertex, offset = 0, size = 64 };
pushConstantRanges[1] = new VkPushConstantRange { stageFlags = VkShaderStageFlags.Fragment, offset = 64, size = 96 };
var layoutInfo = new VkPipelineLayoutCreateInfo var layoutInfo = new VkPipelineLayoutCreateInfo
{ {
sType = VkStructureType.PipelineLayoutCreateInfo, sType = VkStructureType.PipelineLayoutCreateInfo,
setLayoutCount = 0, setLayoutCount = 0,
pushConstantRangeCount = 2, pushConstantRangeCount = 1,
pPushConstantRanges = (nint)pushConstantRanges, pPushConstantRanges = (nint)(&pushConstantRange),
}; };
var pl = VkPipelineLayout.Null; var pl = VkPipelineLayout.Null;