geometry shader

This commit is contained in:
Zack Buhman 2026-04-16 18:23:46 -05:00
parent b7c25fc41f
commit 1ae766c648
4 changed files with 118 additions and 14 deletions

View File

@ -46,6 +46,7 @@ namespace collada::scene {
static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount + constantDescriptorCount; static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount + constantDescriptorCount;
// +3: linear sampler, shadow sampled image, scene sampled image (array) // +3: linear sampler, shadow sampled image, scene sampled image (array)
static constexpr uint32_t bindingCount = uniformBufferDescriptorCount + 3; static constexpr uint32_t bindingCount = uniformBufferDescriptorCount + 3;
static constexpr int shaderVariantCount = 3;
// externally initialized, opaque handle // externally initialized, opaque handle
VkInstance instance; VkInstance instance;

View File

@ -169,6 +169,57 @@ float4 PSMain(VSOutput input) : SV_TARGET
return float4(diffuseSpecular * shadowIntensity + emissionColor.xyz, 1.0); return float4(diffuseSpecular * shadowIntensity + emissionColor.xyz, 1.0);
} }
struct VSGeometryOutput
{
float4 Position : SV_POSITION;
float3 Normal : Normal;
};
[shader("vertex")]
VSGeometryOutput VSGeometryMain(VSInput input)
{
VSGeometryOutput output = (VSGeometryOutput)0;
output.Position = float4(input.Position, 1.0);
output.Normal = input.Normal;
return output;
}
struct GSGeometryOutput
{
float4 Position : SV_POSITION;
float3 Color : Color;
};
[shader("geometry")]
[maxvertexcount(6)]
void GSGeometryMain(triangle VSGeometryOutput input[3], inout LineStream<GSGeometryOutput> outputStream)
{
float normalLength = 2.0;
for (int i = 0; i < 3; i++) {
float3 position = input[i].Position.xyz;
float3 normal = input[i].Normal;
float3 positionNormal = position + normal * normalLength;
GSGeometryOutput output = (GSGeometryOutput)0;
output.Position = getProjection(Scene.Projection, getView(Scene.View, position));
output.Color = float3(1, 0, 0);
outputStream.Append(output);
output.Position = getProjection(Scene.Projection, getView(Scene.View, positionNormal));
output.Color = float3(0, 1, 0);
outputStream.Append(output);
outputStream.RestartStrip();
}
}
[shader("pixel")]
float4 PSGeometryMain(GSGeometryOutput input) : SV_TARGET
{
return float4(input.Color, 1.0);
}
[shader("vertex")] [shader("vertex")]
VSShadowOutput VSShadowMain(VSInput input) VSShadowOutput VSShadowMain(VSInput input)
{ {

View File

@ -327,13 +327,13 @@ namespace collada::scene {
.binding = 0, .binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT
}, },
{ {
.binding = 1, .binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT
} }
}; };
@ -655,7 +655,7 @@ namespace collada::scene {
{ {
VkPushConstantRange pushConstantRanges[1]{ VkPushConstantRange pushConstantRanges[1]{
{ {
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_GEOMETRY_BIT,
.offset = 0, .offset = 0,
.size = (sizeof (PushConstant)) .size = (sizeof (PushConstant))
} }
@ -690,6 +690,27 @@ namespace collada::scene {
} }
}; };
VkPipelineShaderStageCreateInfo geometryShaderStages[3]{
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = shaderModule,
.pName = "VSGeometryMain"
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_GEOMETRY_BIT,
.module = shaderModule,
.pName = "GSGeometryMain"
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = shaderModule,
.pName = "PSGeometryMain"
}
};
VkPipelineShaderStageCreateInfo shadowShaderStages[2]{ VkPipelineShaderStageCreateInfo shadowShaderStages[2]{
{ {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
@ -788,13 +809,12 @@ namespace collada::scene {
vertexInputStates, vertexInputStates,
vertexBindingDescriptions); vertexBindingDescriptions);
// piplineCount must match destroy_all int pipelineCount = descriptor->inputs_list_count * shaderVariantCount;
int pipelineCount = descriptor->inputs_list_count * 2;
VkGraphicsPipelineCreateInfo * pipelineCreateInfos = NewM<VkGraphicsPipelineCreateInfo>(pipelineCount); VkGraphicsPipelineCreateInfo * pipelineCreateInfos = NewM<VkGraphicsPipelineCreateInfo>(pipelineCount);
for (int i = 0; i < descriptor->inputs_list_count; i++) { for (int i = 0; i < descriptor->inputs_list_count; i++) {
// shadow // shadow
pipelineCreateInfos[i * 2 + 0] = { pipelineCreateInfos[i * shaderVariantCount + 0] = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = &shadowRenderingCreateInfo, .pNext = &shadowRenderingCreateInfo,
.stageCount = 2, .stageCount = 2,
@ -811,7 +831,7 @@ namespace collada::scene {
}; };
// non-shadow // non-shadow
pipelineCreateInfos[i * 2 + 1] = { pipelineCreateInfos[i * shaderVariantCount + 1] = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = &renderingCreateInfo, .pNext = &renderingCreateInfo,
.stageCount = 2, .stageCount = 2,
@ -826,6 +846,23 @@ namespace collada::scene {
.pDynamicState = &dynamicState, .pDynamicState = &dynamicState,
.layout = pipelineLayout .layout = pipelineLayout
}; };
// geometry
pipelineCreateInfos[i * shaderVariantCount + 2] = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = &renderingCreateInfo,
.stageCount = 3,
.pStages = geometryShaderStages,
.pVertexInputState = &vertexInputStates[i],
.pInputAssemblyState = &inputAssemblyState,
.pViewportState = &viewportState,
.pRasterizationState = &rasterizationState,
.pMultisampleState = &multisampleState,
.pDepthStencilState = &depthStencilState,
.pColorBlendState = &colorBlendState,
.pDynamicState = &dynamicState,
.layout = pipelineLayout
};
}; };
pipelines = NewM<VkPipeline>(pipelineCount); pipelines = NewM<VkPipeline>(pipelineCount);
@ -860,13 +897,13 @@ namespace collada::scene {
} }
types::triangles const& triangles = mesh.triangles[instance_material.element_index]; types::triangles const& triangles = mesh.triangles[instance_material.element_index];
VkShaderStageFlags stageFlags{ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT }; VkShaderStageFlags stageFlags{ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_GEOMETRY_BIT };
constexpr uint32_t offset{ (offsetof (PushConstant, materialIndex)) }; constexpr uint32_t offset{ (offsetof (PushConstant, materialIndex)) };
vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &materialIndex); vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &materialIndex);
VkDeviceSize vertexOffset{ (VkDeviceSize)mesh.vertex_buffer_offset }; VkDeviceSize vertexOffset{ (VkDeviceSize)mesh.vertex_buffer_offset };
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexIndex.buffer, &vertexOffset); vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexIndex.buffer, &vertexOffset);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[triangles.inputs_index * 2 + pipelineIndex]); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[triangles.inputs_index * shaderVariantCount + pipelineIndex]);
uint32_t indexCount = triangles.count * 3; uint32_t indexCount = triangles.count * 3;
vkCmdDrawIndexed(commandBuffer, indexCount, 1, triangles.index_offset, 0, 0); vkCmdDrawIndexed(commandBuffer, indexCount, 1, triangles.index_offset, 0, 0);
@ -935,7 +972,7 @@ namespace collada::scene {
types::node const & node, types::node const & node,
instance_types::node const & node_instance) instance_types::node const & node_instance)
{ {
VkShaderStageFlags stageFlags{ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT }; VkShaderStageFlags stageFlags{ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_GEOMETRY_BIT };
constexpr uint32_t offset{ (offsetof (PushConstant, nodeIndex)) }; constexpr uint32_t offset{ (offsetof (PushConstant, nodeIndex)) };
vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &node_index); vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &node_index);
@ -983,8 +1020,7 @@ namespace collada::scene {
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts[1], nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts[1], nullptr);
vkDestroyDescriptorPool(device, descriptorPool, nullptr); vkDestroyDescriptorPool(device, descriptorPool, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
// pipelineCount must match create_pipelines int pipelineCount = descriptor->inputs_list_count * shaderVariantCount;
int pipelineCount = descriptor->inputs_list_count * 2;
for (int i = 0; i < pipelineCount; i++) { for (int i = 0; i < pipelineCount; i++) {
vkDestroyPipeline(device, pipelines[i], nullptr); vkDestroyPipeline(device, pipelines[i], nullptr);
} }

View File

@ -154,6 +154,19 @@ void createDepth(VkDeviceSize nonCoherentAtomSize,
VK_CHECK(vkCreateImageView(device, &imageViewCreateInfo, nullptr, imageView)); VK_CHECK(vkCreateImageView(device, &imageViewCreateInfo, nullptr, imageView));
} }
void createCubeDepth(VkDeviceSize nonCoherentAtomSize,
VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties,
uint32_t width,
uint32_t height,
VkFormat format,
VkImageUsageFlags usage,
VkImage * image,
VkDeviceMemory * memory,
VkImageView * imageView)
{
}
void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat, void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat,
VkFormat depthFormat, VkFormat depthFormat,
VkDeviceSize nonCoherentAtomSize, VkDeviceSize nonCoherentAtomSize,
@ -402,7 +415,8 @@ int main()
.dynamicRendering = true, .dynamicRendering = true,
}; };
VkPhysicalDeviceFeatures enabledFeatures{ VkPhysicalDeviceFeatures enabledFeatures{
.samplerAnisotropy = VK_TRUE .geometryShader = true,
.samplerAnisotropy = true,
}; };
constexpr uint32_t enabledExtensionCount = 1; constexpr uint32_t enabledExtensionCount = 1;
char const * enabledExtensionNames[enabledExtensionCount]{ VK_KHR_SWAPCHAIN_EXTENSION_NAME }; char const * enabledExtensionNames[enabledExtensionCount]{ VK_KHR_SWAPCHAIN_EXTENSION_NAME };
@ -867,7 +881,7 @@ int main()
VkViewport viewport{ VkViewport viewport{
.x = 0, .x = 0,
.y = 0,//static_cast<float>(windowSize.y), .y = 0,
.width = static_cast<float>(windowSize.x), .width = static_cast<float>(windowSize.x),
.height = static_cast<float>(windowSize.y), .height = static_cast<float>(windowSize.y),
.minDepth = 0.0f, .minDepth = 0.0f,
@ -882,6 +896,8 @@ int main()
collada_state.vulkan.excludeMaterialIndex = -1; collada_state.vulkan.excludeMaterialIndex = -1;
collada_state.vulkan.pipelineIndex = 1; // non-shadow pipeline collada_state.vulkan.pipelineIndex = 1; // non-shadow pipeline
collada_state.draw(); collada_state.draw();
collada_state.vulkan.pipelineIndex = 2; // geometry shader pipeline
collada_state.draw();
vkCmdEndRendering(commandBuffer); vkCmdEndRendering(commandBuffer);