Added a basic mesh shader example
This commit is contained in:
parent
c79333e085
commit
89fc84bf14
7 changed files with 298 additions and 0 deletions
|
|
@ -439,6 +439,10 @@ Shows usage of the VK_KHR_dynamic_rendering extension, which simplifies the rend
|
|||
#### [Graphics pipeline library (VK_EXT_graphics_pipeline_library)](./examples/graphicspipelinelibrary)<br/>
|
||||
Uses the graphics pipeline library extensions to improve run-time pipeline creation. Instead of creating the whole pipeline at once, this sample pre builds shared pipeline parts like like vertex input state and fragment output state. These are then used to create full pipelines at runtime, reducing build times and possible hick-ups.
|
||||
|
||||
#### [Mesh shaders (VK_EXT_mesh_shader)](./examples/meshshaders)<br/>
|
||||
|
||||
Basic sample demonstrating how to use the mesh shading pipeline as a replacement for the traditional vertex pipeline.
|
||||
|
||||
### Misc
|
||||
|
||||
#### [Vulkan Gears](examples/gears/)
|
||||
|
|
|
|||
19
data/shaders/glsl/meshshader/meshshader.frag
Normal file
19
data/shaders/glsl/meshshader/meshshader.frag
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* Copyright (c) 2021, Sascha Willems
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#version 450
|
||||
|
||||
layout (location = 0) in VertexInput {
|
||||
vec4 color;
|
||||
} vertexInput;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vertexInput.color;
|
||||
}
|
||||
BIN
data/shaders/glsl/meshshader/meshshader.frag.spv
Normal file
BIN
data/shaders/glsl/meshshader/meshshader.frag.spv
Normal file
Binary file not shown.
36
data/shaders/glsl/meshshader/meshshader.mesh
Normal file
36
data/shaders/glsl/meshshader/meshshader.mesh
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* Copyright (c) 2021, Sascha Willems
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#version 450
|
||||
#extension GL_EXT_mesh_shader : require
|
||||
|
||||
layout (binding = 0) uniform UBO
|
||||
{
|
||||
mat4 projection;
|
||||
mat4 model;
|
||||
mat4 view;
|
||||
} ubo;
|
||||
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
layout(triangles, max_vertices = 3, max_primitives = 1) out;
|
||||
|
||||
layout(location = 0) out VertexOutput
|
||||
{
|
||||
vec4 color;
|
||||
} vertexOutput[];
|
||||
|
||||
void main()
|
||||
{
|
||||
SetMeshOutputsEXT(3, 1);
|
||||
mat4 mvp = ubo.projection * ubo.view * ubo.model;
|
||||
gl_MeshVerticesEXT[0].gl_Position = mvp * vec4( 0.0, -1.0, 0.0, 1.0);
|
||||
gl_MeshVerticesEXT[1].gl_Position = mvp * vec4(-1.0, 1.0, 0.0, 1.0);
|
||||
gl_MeshVerticesEXT[2].gl_Position = mvp * vec4( 1.0, 1.0, 0.0, 1.0);
|
||||
vertexOutput[0].color = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
vertexOutput[1].color = vec4(0.0, 0.0, 1.0, 1.0);
|
||||
vertexOutput[2].color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0, 1, 2);
|
||||
}
|
||||
BIN
data/shaders/glsl/meshshader/meshshader.mesh.spv
Normal file
BIN
data/shaders/glsl/meshshader/meshshader.mesh.spv
Normal file
Binary file not shown.
|
|
@ -111,6 +111,7 @@ set(EXAMPLES
|
|||
inlineuniformblocks
|
||||
inputattachments
|
||||
instancing
|
||||
meshshader
|
||||
multisampling
|
||||
multithreading
|
||||
multiview
|
||||
|
|
|
|||
238
examples/meshshader/meshshader.cpp
Normal file
238
examples/meshshader/meshshader.cpp
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Vulkan Example - Using mesh shaders
|
||||
*
|
||||
* Copyright (C) 2022 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "vulkanexamplebase.h"
|
||||
#include "VulkanglTFModel.h"
|
||||
#include "meshoptimizer/meshoptimizer.h"
|
||||
|
||||
#define ENABLE_VALIDATION false
|
||||
|
||||
class VulkanExample : public VulkanExampleBase
|
||||
{
|
||||
public:
|
||||
struct UniformData {
|
||||
glm::mat4 projection;
|
||||
glm::mat4 model;
|
||||
glm::mat4 view;
|
||||
} uniformData;
|
||||
vks::Buffer uniformBuffer;
|
||||
|
||||
uint32_t indexCount;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkDescriptorSet descriptorSet;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
|
||||
PFN_vkCmdDrawMeshTasksEXT vkCmdDrawMeshTasksEXT;
|
||||
|
||||
VkPhysicalDeviceMeshShaderFeaturesEXT enabledMeshShaderFeatures{};
|
||||
|
||||
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||
{
|
||||
title = "Mesh shaders";
|
||||
timerSpeed *= 0.25f;
|
||||
camera.type = Camera::CameraType::lookat;
|
||||
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
|
||||
camera.setRotation(glm::vec3(0.0f));
|
||||
camera.setTranslation(glm::vec3(0.0f, 0.0f, -2.0f));
|
||||
|
||||
// Extension require at least Vulkan 1.1
|
||||
apiVersion = VK_API_VERSION_1_1;
|
||||
|
||||
// Extensions required by mesh shading
|
||||
enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||
enabledDeviceExtensions.push_back(VK_EXT_MESH_SHADER_EXTENSION_NAME);
|
||||
enabledDeviceExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME);
|
||||
|
||||
// Required by VK_KHR_spirv_1_4
|
||||
enabledDeviceExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
~VulkanExample()
|
||||
{
|
||||
vkDestroyPipeline(device, pipeline, nullptr);
|
||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||
uniformBuffer.destroy();
|
||||
}
|
||||
|
||||
void getEnabledFeatures()
|
||||
{
|
||||
enabledMeshShaderFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV;
|
||||
enabledMeshShaderFeatures.meshShader = VK_TRUE;
|
||||
enabledMeshShaderFeatures.taskShader = VK_FALSE;
|
||||
|
||||
deviceCreatepNextChain = &enabledMeshShaderFeatures;
|
||||
}
|
||||
|
||||
|
||||
void buildCommandBuffers()
|
||||
{
|
||||
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
|
||||
|
||||
VkClearValue clearValues[2];
|
||||
clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 1.0f } };;
|
||||
clearValues[1].depthStencil = { 1.0f, 0 };
|
||||
|
||||
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
|
||||
renderPassBeginInfo.renderPass = renderPass;
|
||||
renderPassBeginInfo.renderArea.offset.x = 0;
|
||||
renderPassBeginInfo.renderArea.offset.y = 0;
|
||||
renderPassBeginInfo.renderArea.extent.width = width;
|
||||
renderPassBeginInfo.renderArea.extent.height = height;
|
||||
renderPassBeginInfo.clearValueCount = 2;
|
||||
renderPassBeginInfo.pClearValues = clearValues;
|
||||
|
||||
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
|
||||
{
|
||||
renderPassBeginInfo.framebuffer = frameBuffers[i];
|
||||
|
||||
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
||||
|
||||
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
|
||||
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
|
||||
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
|
||||
|
||||
VkDeviceSize offsets[1] = { 0 };
|
||||
|
||||
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
|
||||
|
||||
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
vkCmdDrawMeshTasksEXT(drawCmdBuffers[i], 1, 1, 1);
|
||||
|
||||
drawUI(drawCmdBuffers[i]);
|
||||
|
||||
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
||||
|
||||
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void setupDescriptors()
|
||||
{
|
||||
// Pool
|
||||
std::vector<VkDescriptorPoolSize> poolSizes = {
|
||||
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
||||
};
|
||||
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(static_cast<uint32_t>(poolSizes.size()), poolSizes.data(), 1);
|
||||
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
|
||||
|
||||
// Layout
|
||||
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
|
||||
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_MESH_BIT_EXT, 0),
|
||||
};
|
||||
VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
|
||||
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutInfo, nullptr, &descriptorSetLayout));
|
||||
|
||||
// Set
|
||||
VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
|
||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
|
||||
std::vector<VkWriteDescriptorSet> modelWriteDescriptorSets = {
|
||||
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor),
|
||||
};
|
||||
vkUpdateDescriptorSets(device, static_cast<uint32_t>(modelWriteDescriptorSets.size()), modelWriteDescriptorSets.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
void preparePipelines()
|
||||
{
|
||||
// Layout
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1);
|
||||
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout));
|
||||
|
||||
// Pipeline
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
|
||||
VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE, 0);
|
||||
VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
|
||||
VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState);
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL);
|
||||
VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
|
||||
VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0);
|
||||
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
|
||||
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0);
|
||||
|
||||
// Mesh shading doesn't require vertex input state
|
||||
pipelineCI.pInputAssemblyState = nullptr;
|
||||
pipelineCI.pVertexInputState = nullptr;
|
||||
|
||||
pipelineCI.pRasterizationState = &rasterizationState;
|
||||
pipelineCI.pColorBlendState = &colorBlendState;
|
||||
pipelineCI.pMultisampleState = &multisampleState;
|
||||
pipelineCI.pViewportState = &viewportState;
|
||||
pipelineCI.pDepthStencilState = &depthStencilState;
|
||||
pipelineCI.pDynamicState = &dynamicState;
|
||||
pipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size());
|
||||
pipelineCI.pStages = shaderStages.data();
|
||||
|
||||
shaderStages[0] = loadShader(getShadersPath() + "meshshader/meshshader.mesh.spv", VK_SHADER_STAGE_MESH_BIT_EXT);
|
||||
shaderStages[1] = loadShader(getShadersPath() + "meshshader/meshshader.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
|
||||
}
|
||||
|
||||
// Prepare and initialize uniform buffer containing shader uniforms
|
||||
void prepareUniformBuffers()
|
||||
{
|
||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(UniformData)));
|
||||
VK_CHECK_RESULT(uniformBuffer.map());
|
||||
updateUniformBuffers();
|
||||
}
|
||||
|
||||
void updateUniformBuffers()
|
||||
{
|
||||
uniformData.projection = camera.matrices.perspective;
|
||||
uniformData.view = camera.matrices.view;
|
||||
uniformData.model = glm::mat4(1.0f);
|
||||
memcpy(uniformBuffer.mapped, &uniformData, sizeof(UniformData));
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
VulkanExampleBase::prepareFrame();
|
||||
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||
|
||||
VulkanExampleBase::submitFrame();
|
||||
}
|
||||
|
||||
void prepare()
|
||||
{
|
||||
VulkanExampleBase::prepare();
|
||||
|
||||
// Get the function pointer of the mesh shader drawing funtion
|
||||
vkCmdDrawMeshTasksEXT = reinterpret_cast<PFN_vkCmdDrawMeshTasksEXT>(vkGetDeviceProcAddr(device, "vkCmdDrawMeshTasksEXT"));
|
||||
|
||||
prepareUniformBuffers();
|
||||
setupDescriptors();
|
||||
preparePipelines();
|
||||
buildCommandBuffers();
|
||||
prepared = true;
|
||||
}
|
||||
|
||||
virtual void render()
|
||||
{
|
||||
if (!prepared)
|
||||
return;
|
||||
draw();
|
||||
}
|
||||
|
||||
virtual void viewChanged()
|
||||
{
|
||||
updateUniformBuffers();
|
||||
}
|
||||
};
|
||||
|
||||
VULKAN_EXAMPLE_MAIN()
|
||||
Loading…
Add table
Add a link
Reference in a new issue