2022-10-02 15:46:26 +02:00
/*
* Vulkan Example - Using dynamic state
2024-01-08 19:59:28 +01:00
*
* This sample demonstrates the use of some of the VK_EXT_dynamic_state extensions
* These allow an application to set some pipeline related state dynamically at drawtime
* instead of having to pre - bake the state into a pipeline
* This can help reduce the number of pipelines required
2022-10-02 15:46:26 +02:00
*
2023-02-24 16:13:31 +01:00
* Copyright ( C ) 2022 - 2023 by Sascha Willems - www . saschawillems . de
2022-10-02 15:46:26 +02:00
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
# include "vulkanexamplebase.h"
# include "VulkanglTFModel.h"
class VulkanExample : public VulkanExampleBase
{
public :
vkglTF : : Model scene ;
2024-01-08 19:59:28 +01:00
struct UniformData {
2022-10-02 15:46:26 +02:00
glm : : mat4 projection ;
glm : : mat4 modelView ;
2024-01-08 19:59:28 +01:00
glm : : vec4 lightPos { 0.0f , 2.0f , 1.0f , 0.0f } ;
} uniformData ;
vks : : Buffer uniformBuffer ;
2022-10-02 15:46:26 +02:00
2023-02-24 16:13:31 +01:00
float clearColor [ 4 ] = { 0.0f , 0.0f , 0.2f , 1.0f } ;
2024-01-08 19:59:28 +01:00
VkPipelineLayout pipelineLayout { VK_NULL_HANDLE } ;
VkPipeline pipeline { VK_NULL_HANDLE } ;
VkDescriptorSet descriptorSet { VK_NULL_HANDLE } ;
VkDescriptorSetLayout descriptorSetLayout { VK_NULL_HANDLE } ;
2022-10-02 15:46:26 +02:00
// This sample demonstrates different dynamic states, so we check and store what extension is available
2024-01-08 19:59:28 +01:00
bool hasDynamicState { false } ;
bool hasDynamicState2 { false } ;
bool hasDynamicState3 { false } ;
bool hasDynamicVertexState { false } ;
2022-10-02 15:46:26 +02:00
VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeaturesEXT { } ;
2022-10-02 19:16:40 +02:00
VkPhysicalDeviceExtendedDynamicState2FeaturesEXT extendedDynamicState2FeaturesEXT { } ;
2022-10-03 18:52:25 +02:00
VkPhysicalDeviceExtendedDynamicState3FeaturesEXT extendedDynamicState3FeaturesEXT { } ;
2022-10-02 15:46:26 +02:00
// Function pointers for dynamic states used in this sample
// VK_EXT_dynamic_stte
2024-01-08 19:59:28 +01:00
PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT { nullptr } ;
PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT { nullptr } ;
PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT { nullptr } ;
PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT { nullptr } ;
2022-10-02 19:16:40 +02:00
// VK_EXT_dynamic_state_2
2024-01-08 19:59:28 +01:00
PFN_vkCmdSetRasterizerDiscardEnable vkCmdSetRasterizerDiscardEnableEXT { nullptr } ;
2022-10-03 18:52:25 +02:00
// VK_EXT_dynamic_state_3
2024-01-08 19:59:28 +01:00
PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT { nullptr } ;
PFN_vkCmdSetColorBlendEquationEXT vkCmdSetColorBlendEquationEXT { nullptr } ;
2022-10-02 15:46:26 +02:00
// Dynamic state UI toggles
struct DynamicState {
int32_t cullMode = VK_CULL_MODE_BACK_BIT ;
int32_t frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE ;
2022-10-03 18:52:25 +02:00
bool depthTest = true ;
bool depthWrite = true ;
2022-10-02 15:46:26 +02:00
} dynamicState ;
2022-10-02 19:16:40 +02:00
struct DynamicState2 {
bool rasterizerDiscardEnable = false ;
} dynamicState2 ;
2022-10-03 18:52:25 +02:00
struct DynamicState3 {
bool colorBlendEnable = false ;
} dynamicState3 ;
2022-10-02 15:46:26 +02:00
2023-12-30 13:15:37 +01:00
VulkanExample ( ) : VulkanExampleBase ( )
2022-10-02 15:46:26 +02:00
{
title = " Dynamic state " ;
camera . type = Camera : : CameraType : : lookat ;
camera . setPosition ( glm : : vec3 ( 0.0f , 0.0f , - 10.5f ) ) ;
camera . setRotation ( glm : : vec3 ( - 25.0f , 15.0f , 0.0f ) ) ;
camera . setRotationSpeed ( 0.5f ) ;
camera . setPerspective ( 60.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
2024-01-08 19:59:28 +01:00
// Note: We enable the dynamic state extensions dynamically, based on which ones the device supports see getEnabledExtensions
2023-11-02 19:57:56 +01:00
enabledInstanceExtensions . push_back ( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) ;
2022-10-02 15:46:26 +02:00
}
~ VulkanExample ( )
{
2024-01-08 19:59:28 +01:00
if ( device ) {
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyPipeline ( device , pipeline , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
uniformBuffer . destroy ( ) ;
}
}
void getEnabledExtensions ( )
{
2024-05-04 07:53:08 -04:00
// Get the full list of extended dynamic state features supported by the device
extendedDynamicStateFeaturesEXT . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT ;
extendedDynamicStateFeaturesEXT . pNext = & extendedDynamicState2FeaturesEXT ;
extendedDynamicState2FeaturesEXT . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT ;
extendedDynamicState2FeaturesEXT . pNext = & extendedDynamicState3FeaturesEXT ;
extendedDynamicState3FeaturesEXT . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT ;
extendedDynamicState3FeaturesEXT . pNext = nullptr ;
VkPhysicalDeviceFeatures2 physicalDeviceFeatures2 ;
physicalDeviceFeatures2 . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 ;
physicalDeviceFeatures2 . pNext = & extendedDynamicStateFeaturesEXT ;
vkGetPhysicalDeviceFeatures2 ( physicalDevice , & physicalDeviceFeatures2 ) ;
2024-01-08 19:59:28 +01:00
// Check what dynamic states are supported by the current implementation
2024-05-04 07:53:08 -04:00
// Checking for available features is probably sufficient, but retained redundant extension checks for clarity and consistency
hasDynamicState = vulkanDevice - > extensionSupported ( VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME ) & & extendedDynamicStateFeaturesEXT . extendedDynamicState ;
hasDynamicState2 = vulkanDevice - > extensionSupported ( VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME ) & & extendedDynamicState2FeaturesEXT . extendedDynamicState2 ;
hasDynamicState3 = vulkanDevice - > extensionSupported ( VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME ) & & extendedDynamicState3FeaturesEXT . extendedDynamicState3ColorBlendEnable & & extendedDynamicState3FeaturesEXT . extendedDynamicState3ColorBlendEquation ;
2024-01-08 19:59:28 +01:00
hasDynamicVertexState = vulkanDevice - > extensionSupported ( VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME ) ;
// Enable dynamic state extensions if present. This function is called after physical and before logical device creation, so we can enabled extensions based on a list of supported extensions
2024-05-04 07:53:08 -04:00
if ( hasDynamicState ) {
2024-01-08 19:59:28 +01:00
enabledDeviceExtensions . push_back ( VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME ) ;
2024-05-04 07:53:08 -04:00
extendedDynamicStateFeaturesEXT . pNext = nullptr ;
2024-01-08 19:59:28 +01:00
deviceCreatepNextChain = & extendedDynamicStateFeaturesEXT ;
}
2024-05-04 07:53:08 -04:00
if ( hasDynamicState2 ) {
2024-01-08 19:59:28 +01:00
enabledDeviceExtensions . push_back ( VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME ) ;
2024-05-04 07:53:08 -04:00
extendedDynamicState2FeaturesEXT . pNext = nullptr ;
2024-01-08 19:59:28 +01:00
if ( hasDynamicState ) {
extendedDynamicStateFeaturesEXT . pNext = & extendedDynamicState2FeaturesEXT ;
}
else {
deviceCreatepNextChain = & extendedDynamicState2FeaturesEXT ;
}
}
2024-05-04 07:53:08 -04:00
if ( hasDynamicState3 ) {
2024-01-08 19:59:28 +01:00
enabledDeviceExtensions . push_back ( VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME ) ;
if ( hasDynamicState2 ) {
extendedDynamicState2FeaturesEXT . pNext = & extendedDynamicState3FeaturesEXT ;
}
else {
deviceCreatepNextChain = & extendedDynamicState3FeaturesEXT ;
}
2022-10-02 15:46:26 +02:00
2024-01-08 19:59:28 +01:00
}
2024-05-04 07:53:08 -04:00
if ( hasDynamicVertexState ) {
2024-01-08 19:59:28 +01:00
enabledDeviceExtensions . push_back ( VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME ) ;
}
2022-10-02 15:46:26 +02:00
}
void buildCommandBuffers ( )
{
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
VkClearValue clearValues [ 2 ] ;
2023-02-24 16:13:31 +01:00
clearValues [ 0 ] . color = { { clearColor [ 0 ] , clearColor [ 1 ] , clearColor [ 2 ] , clearColor [ 3 ] } } ;
2022-10-02 15:46:26 +02:00
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 )
{
// Set target frame buffer
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 ) ;
// Apply dynamic states
2022-10-03 18:52:25 +02:00
2022-10-02 15:46:26 +02:00
if ( vkCmdSetCullModeEXT ) {
vkCmdSetCullModeEXT ( drawCmdBuffers [ i ] , VkCullModeFlagBits ( dynamicState . cullMode ) ) ;
}
if ( vkCmdSetFrontFaceEXT ) {
vkCmdSetFrontFaceEXT ( drawCmdBuffers [ i ] , VkFrontFace ( dynamicState . frontFace ) ) ;
}
2022-10-03 18:52:25 +02:00
if ( vkCmdSetDepthTestEnableEXT ) {
vkCmdSetDepthTestEnableEXT ( drawCmdBuffers [ i ] , VkFrontFace ( dynamicState . depthTest ) ) ;
}
if ( vkCmdSetDepthWriteEnableEXT ) {
vkCmdSetDepthWriteEnableEXT ( drawCmdBuffers [ i ] , VkFrontFace ( dynamicState . depthWrite ) ) ;
}
2022-10-02 19:16:40 +02:00
if ( vkCmdSetRasterizerDiscardEnableEXT ) {
vkCmdSetRasterizerDiscardEnableEXT ( drawCmdBuffers [ i ] , VkBool32 ( dynamicState2 . rasterizerDiscardEnable ) ) ;
}
2022-10-02 15:46:26 +02:00
2022-10-03 18:52:25 +02:00
if ( vkCmdSetColorBlendEnableEXT ) {
const std : : vector < VkBool32 > blendEnables = { dynamicState3 . colorBlendEnable } ;
vkCmdSetColorBlendEnableEXT ( drawCmdBuffers [ i ] , 0 , 1 , blendEnables . data ( ) ) ;
2023-02-24 16:13:31 +01:00
VkColorBlendEquationEXT colorBlendEquation { } ;
2022-10-03 18:52:25 +02:00
if ( dynamicState3 . colorBlendEnable ) {
colorBlendEquation . colorBlendOp = VK_BLEND_OP_ADD ;
2023-02-24 16:13:31 +01:00
colorBlendEquation . srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR ;
colorBlendEquation . dstColorBlendFactor = VK_BLEND_FACTOR_DST_COLOR ;
2022-10-03 18:52:25 +02:00
colorBlendEquation . alphaBlendOp = VK_BLEND_OP_ADD ;
colorBlendEquation . srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA ;
colorBlendEquation . dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO ;
}
2023-02-24 16:13:31 +01:00
vkCmdSetColorBlendEquationEXT ( drawCmdBuffers [ i ] , 0 , 1 , & colorBlendEquation ) ;
2022-10-03 18:52:25 +02:00
}
2022-10-02 15:46:26 +02:00
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSet , 0 , NULL ) ;
scene . bindBuffers ( drawCmdBuffers [ i ] ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
scene . draw ( drawCmdBuffers [ i ] ) ;
drawUI ( drawCmdBuffers [ i ] ) ;
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
}
}
void loadAssets ( )
{
const uint32_t glTFLoadingFlags = vkglTF : : FileLoadingFlags : : PreTransformVertices | vkglTF : : FileLoadingFlags : : PreMultiplyVertexColors | vkglTF : : FileLoadingFlags : : FlipY ;
scene . loadFromFile ( getAssetPath ( ) + " models/treasure_smooth.gltf " , vulkanDevice , queue , glTFLoadingFlags ) ;
}
2024-01-08 19:59:28 +01:00
void setupDescriptors ( )
2022-10-02 15:46:26 +02:00
{
2024-01-08 19:59:28 +01:00
// Pool
std : : vector < VkDescriptorPoolSize > poolSizes = {
2022-10-02 15:46:26 +02:00
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 )
} ;
2023-12-20 20:14:36 +01:00
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , 2 ) ;
2022-10-02 15:46:26 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2024-01-08 19:59:28 +01:00
// Layout
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
2022-10-02 15:46:26 +02:00
// Binding 0 : Vertex shader uniform buffer
2024-01-08 19:59:28 +01:00
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_VERTEX_BIT , 0 )
2022-10-02 15:46:26 +02:00
} ;
2023-12-20 20:14:36 +01:00
VkDescriptorSetLayoutCreateInfo descriptorLayout = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
2022-10-02 15:46:26 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & descriptorSetLayout ) ) ;
2024-01-08 19:59:28 +01:00
// Set
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayout , 1 ) ;
2022-10-02 15:46:26 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
2024-01-08 19:59:28 +01:00
std : : vector < VkWriteDescriptorSet > writeDescriptorSets = {
2022-10-02 15:46:26 +02:00
// Binding 0 : Vertex shader uniform buffer
2024-01-08 19:59:28 +01:00
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 0 , & uniformBuffer . descriptor )
2022-10-02 15:46:26 +02:00
} ;
2023-12-22 14:30:18 +01:00
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , nullptr ) ;
2022-10-02 15:46:26 +02:00
}
void preparePipelines ( )
{
2024-01-08 19:59:28 +01:00
// Layout
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks : : initializers : : pipelineLayoutCreateInfo ( & descriptorSetLayout , 1 ) ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCreateInfo , nullptr , & pipelineLayout ) ) ;
// Pipeline
// Instead of having to create a pipeline for each state combination, we only create one pipeline and toggle the new dynamic states during command buffer creation
2022-10-02 15:46:26 +02:00
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_BACK_BIT , VK_FRONT_FACE_COUNTER_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 ) ;
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2024-01-08 19:59:28 +01:00
// All dynamic states we want to use need to be enabled at pipeline creation
2022-10-02 15:46:26 +02:00
std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR , VK_DYNAMIC_STATE_LINE_WIDTH , } ;
if ( hasDynamicState ) {
dynamicStateEnables . push_back ( VK_DYNAMIC_STATE_CULL_MODE_EXT ) ;
2022-10-03 18:52:25 +02:00
dynamicStateEnables . push_back ( VK_DYNAMIC_STATE_FRONT_FACE_EXT ) ;
dynamicStateEnables . push_back ( VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT ) ;
dynamicStateEnables . push_back ( VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT ) ;
2022-10-02 15:46:26 +02:00
}
2022-10-02 19:16:40 +02:00
if ( hasDynamicState2 ) {
2022-10-03 18:52:25 +02:00
dynamicStateEnables . push_back ( VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT ) ;
}
if ( hasDynamicState3 ) {
dynamicStateEnables . push_back ( VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT ) ;
dynamicStateEnables . push_back ( VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT ) ;
2022-10-02 19:16:40 +02:00
}
2022-10-02 15:46:26 +02:00
VkPipelineDynamicStateCreateInfo dynamicState = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables ) ;
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelineLayout , renderPass ) ;
pipelineCI . pInputAssemblyState = & inputAssemblyState ;
pipelineCI . pRasterizationState = & rasterizationState ;
pipelineCI . pColorBlendState = & colorBlendState ;
pipelineCI . pMultisampleState = & multisampleState ;
pipelineCI . pViewportState = & viewportState ;
pipelineCI . pDepthStencilState = & depthStencilState ;
pipelineCI . pDynamicState = & dynamicState ;
2023-12-20 20:14:36 +01:00
pipelineCI . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
2022-10-02 15:46:26 +02:00
pipelineCI . pStages = shaderStages . data ( ) ;
pipelineCI . pVertexInputState = vkglTF : : Vertex : : getPipelineVertexInputState ( { vkglTF : : VertexComponent : : Position , vkglTF : : VertexComponent : : Normal , vkglTF : : VertexComponent : : Color } ) ;
// Create the graphics pipeline state objects
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " pipelines/phong.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " pipelines/phong.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 ( )
{
// Create the vertex shader uniform buffer block
2024-01-08 19:59:28 +01:00
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 ) ) ) ;
2022-10-02 15:46:26 +02:00
VK_CHECK_RESULT ( uniformBuffer . map ( ) ) ;
}
void updateUniformBuffers ( )
{
2024-01-08 19:59:28 +01:00
uniformData . projection = camera . matrices . perspective ;
uniformData . modelView = camera . matrices . view ;
memcpy ( uniformBuffer . mapped , & uniformData , sizeof ( uniformData ) ) ;
2022-10-02 15:46:26 +02:00
}
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2024-01-08 19:59:28 +01:00
// Dynamic states are set with vkCmd* calls in the command buffer, so we need to load the function pointers depending on extension supports
2022-10-02 15:46:26 +02:00
if ( hasDynamicState ) {
vkCmdSetCullModeEXT = reinterpret_cast < PFN_vkCmdSetCullModeEXT > ( vkGetDeviceProcAddr ( device , " vkCmdSetCullModeEXT " ) ) ;
vkCmdSetFrontFaceEXT = reinterpret_cast < PFN_vkCmdSetFrontFaceEXT > ( vkGetDeviceProcAddr ( device , " vkCmdSetFrontFaceEXT " ) ) ;
2022-10-03 18:52:25 +02:00
vkCmdSetDepthWriteEnableEXT = reinterpret_cast < PFN_vkCmdSetDepthWriteEnableEXT > ( vkGetDeviceProcAddr ( device , " vkCmdSetDepthWriteEnableEXT " ) ) ;
vkCmdSetDepthTestEnableEXT = reinterpret_cast < PFN_vkCmdSetDepthTestEnable > ( vkGetDeviceProcAddr ( device , " vkCmdSetDepthTestEnableEXT " ) ) ;
2022-10-02 15:46:26 +02:00
}
2022-10-02 19:16:40 +02:00
if ( hasDynamicState2 ) {
vkCmdSetRasterizerDiscardEnableEXT = reinterpret_cast < PFN_vkCmdSetRasterizerDiscardEnableEXT > ( vkGetDeviceProcAddr ( device , " vkCmdSetRasterizerDiscardEnableEXT " ) ) ;
}
2022-10-03 18:52:25 +02:00
if ( hasDynamicState3 ) {
vkCmdSetColorBlendEnableEXT = reinterpret_cast < PFN_vkCmdSetColorBlendEnableEXT > ( vkGetDeviceProcAddr ( device , " vkCmdSetColorBlendEnableEXT " ) ) ;
vkCmdSetColorBlendEquationEXT = reinterpret_cast < PFN_vkCmdSetColorBlendEquationEXT > ( vkGetDeviceProcAddr ( device , " vkCmdSetColorBlendEquationEXT " ) ) ;
}
2022-10-02 15:46:26 +02:00
loadAssets ( ) ;
prepareUniformBuffers ( ) ;
2024-01-08 19:59:28 +01:00
setupDescriptors ( ) ;
2022-10-02 15:46:26 +02:00
preparePipelines ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
2024-01-08 19:59:28 +01:00
void draw ( )
2022-10-02 15:46:26 +02:00
{
2024-01-08 19:59:28 +01:00
VulkanExampleBase : : prepareFrame ( ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
2022-10-02 15:46:26 +02:00
}
2024-01-08 19:59:28 +01:00
virtual void render ( )
2022-10-02 15:46:26 +02:00
{
2024-01-08 19:59:28 +01:00
if ( ! prepared )
return ;
2022-10-02 15:46:26 +02:00
updateUniformBuffers ( ) ;
2024-01-08 19:59:28 +01:00
draw ( ) ;
2022-10-02 15:46:26 +02:00
}
virtual void OnUpdateUIOverlay ( vks : : UIOverlay * overlay )
{
2022-10-02 19:16:40 +02:00
bool rebuildCB = false ;
2022-10-02 15:46:26 +02:00
if ( overlay - > header ( " Dynamic state " ) ) {
2022-10-02 19:16:40 +02:00
if ( hasDynamicState ) {
rebuildCB = overlay - > comboBox ( " Cull mode " , & dynamicState . cullMode , { " none " , " front " , " back " } ) ;
rebuildCB | = overlay - > comboBox ( " Front face " , & dynamicState . frontFace , { " Counter clockwise " , " Clockwise " } ) ;
2022-10-03 18:52:25 +02:00
rebuildCB | = overlay - > checkBox ( " Depth test " , & dynamicState . depthTest ) ;
rebuildCB | = overlay - > checkBox ( " Depth write " , & dynamicState . depthWrite ) ;
2022-10-02 19:16:40 +02:00
} else {
2024-05-04 07:53:08 -04:00
overlay - > text ( " Extension or features not supported " ) ;
2022-10-02 19:16:40 +02:00
}
}
if ( overlay - > header ( " Dynamic state 2 " ) ) {
2023-02-24 16:13:31 +01:00
if ( hasDynamicState2 ) {
2022-10-02 19:16:40 +02:00
rebuildCB | = overlay - > checkBox ( " Rasterizer discard " , & dynamicState2 . rasterizerDiscardEnable ) ;
}
else {
2024-05-04 07:53:08 -04:00
overlay - > text ( " Extension or features not supported " ) ;
2022-10-02 19:16:40 +02:00
}
2022-10-02 15:46:26 +02:00
}
2022-10-03 18:52:25 +02:00
if ( overlay - > header ( " Dynamic state 3 " ) ) {
2023-02-24 16:13:31 +01:00
if ( hasDynamicState3 ) {
2022-10-03 18:52:25 +02:00
rebuildCB | = overlay - > checkBox ( " Color blend " , & dynamicState3 . colorBlendEnable ) ;
2023-02-24 16:13:31 +01:00
rebuildCB | = overlay - > colorPicker ( " Clear color " , clearColor ) ;
2022-10-03 18:52:25 +02:00
}
else {
2024-05-04 07:53:08 -04:00
overlay - > text ( " Extension or features not supported " ) ;
2022-10-03 18:52:25 +02:00
}
}
2022-10-02 15:46:26 +02:00
if ( rebuildCB ) {
buildCommandBuffers ( ) ;
}
}
} ;
VULKAN_EXAMPLE_MAIN ( )