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;
// +3: linear sampler, shadow sampled image, scene sampled image (array)
static constexpr uint32_t bindingCount = uniformBufferDescriptorCount + 3;
static constexpr int shaderVariantCount = 3;
// externally initialized, opaque handle
VkInstance instance;

View File

@ -169,6 +169,57 @@ float4 PSMain(VSOutput input) : SV_TARGET
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")]
VSShadowOutput VSShadowMain(VSInput input)
{

View File

@ -327,13 +327,13 @@ namespace collada::scene {
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.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]{
{
.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,
.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]{
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
@ -788,13 +809,12 @@ namespace collada::scene {
vertexInputStates,
vertexBindingDescriptions);
// piplineCount must match destroy_all
int pipelineCount = descriptor->inputs_list_count * 2;
int pipelineCount = descriptor->inputs_list_count * shaderVariantCount;
VkGraphicsPipelineCreateInfo * pipelineCreateInfos = NewM<VkGraphicsPipelineCreateInfo>(pipelineCount);
for (int i = 0; i < descriptor->inputs_list_count; i++) {
// shadow
pipelineCreateInfos[i * 2 + 0] = {
pipelineCreateInfos[i * shaderVariantCount + 0] = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = &shadowRenderingCreateInfo,
.stageCount = 2,
@ -811,7 +831,7 @@ namespace collada::scene {
};
// non-shadow
pipelineCreateInfos[i * 2 + 1] = {
pipelineCreateInfos[i * shaderVariantCount + 1] = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = &renderingCreateInfo,
.stageCount = 2,
@ -826,6 +846,23 @@ namespace collada::scene {
.pDynamicState = &dynamicState,
.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);
@ -860,13 +897,13 @@ namespace collada::scene {
}
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)) };
vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &materialIndex);
VkDeviceSize vertexOffset{ (VkDeviceSize)mesh.vertex_buffer_offset };
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;
vkCmdDrawIndexed(commandBuffer, indexCount, 1, triangles.index_offset, 0, 0);
@ -935,7 +972,7 @@ namespace collada::scene {
types::node const & node,
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)) };
vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &node_index);
@ -983,8 +1020,7 @@ namespace collada::scene {
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts[1], nullptr);
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
// pipelineCount must match create_pipelines
int pipelineCount = descriptor->inputs_list_count * 2;
int pipelineCount = descriptor->inputs_list_count * shaderVariantCount;
for (int i = 0; i < pipelineCount; i++) {
vkDestroyPipeline(device, pipelines[i], nullptr);
}

View File

@ -154,6 +154,19 @@ void createDepth(VkDeviceSize nonCoherentAtomSize,
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,
VkFormat depthFormat,
VkDeviceSize nonCoherentAtomSize,
@ -402,7 +415,8 @@ int main()
.dynamicRendering = true,
};
VkPhysicalDeviceFeatures enabledFeatures{
.samplerAnisotropy = VK_TRUE
.geometryShader = true,
.samplerAnisotropy = true,
};
constexpr uint32_t enabledExtensionCount = 1;
char const * enabledExtensionNames[enabledExtensionCount]{ VK_KHR_SWAPCHAIN_EXTENSION_NAME };
@ -867,7 +881,7 @@ int main()
VkViewport viewport{
.x = 0,
.y = 0,//static_cast<float>(windowSize.y),
.y = 0,
.width = static_cast<float>(windowSize.x),
.height = static_cast<float>(windowSize.y),
.minDepth = 0.0f,
@ -882,6 +896,8 @@ int main()
collada_state.vulkan.excludeMaterialIndex = -1;
collada_state.vulkan.pipelineIndex = 1; // non-shadow pipeline
collada_state.draw();
collada_state.vulkan.pipelineIndex = 2; // geometry shader pipeline
collada_state.draw();
vkCmdEndRendering(commandBuffer);