2019-06-10 13:07:48 +02:00
/*
* Vulkan Example - Descriptor indexing ( VK_EXT_descriptor_indexing )
*
2023-12-29 19:00:35 +01:00
* Demonstrates use of descriptor indexing to dynamically index into a variable sized array of images
2024-05-18 10:01:01 +02:00
*
2024-01-16 19:32:34 +01:00
* The sample renders multiple objects with the index of the texture ( descriptor ) to use passed as a vertex attribute ( aka " descriptor indexing " )
2024-05-18 10:01:01 +02:00
*
2019-06-10 13:07:48 +02:00
* Relevant code parts are marked with [ POI ]
*
2023-12-29 19:00:35 +01:00
* Copyright ( C ) 2021 - 2023 Sascha Willems - www . saschawillems . de
2019-06-10 13:07:48 +02:00
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
2021-01-28 22:04:25 +01:00
2019-06-10 13:07:48 +02:00
# include "vulkanexamplebase.h"
class VulkanExample : public VulkanExampleBase
{
public :
2023-12-29 19:00:35 +01:00
// We will be dynamically indexing into an array of images
2019-06-10 13:07:48 +02:00
std : : vector < vks : : Texture2D > textures ;
vks : : Buffer vertexBuffer ;
vks : : Buffer indexBuffer ;
2023-12-29 19:00:35 +01:00
uint32_t indexCount { 0 } ;
2019-06-10 13:07:48 +02:00
2024-01-16 19:32:34 +01:00
struct UniformData {
2019-06-10 13:07:48 +02:00
glm : : mat4 projection ;
glm : : mat4 view ;
glm : : mat4 model ;
2024-01-16 19:32:34 +01:00
} uniformData ;
vks : : Buffer uniformBuffer ;
2019-06-10 13:07:48 +02:00
2023-12-29 19:00:35 +01:00
VkPipeline pipeline { VK_NULL_HANDLE } ;
VkPipelineLayout pipelineLayout { VK_NULL_HANDLE } ;
VkDescriptorSet descriptorSet { VK_NULL_HANDLE } ;
VkDescriptorSetLayout descriptorSetLayout { VK_NULL_HANDLE } ;
2019-06-10 13:07:48 +02:00
VkPhysicalDeviceDescriptorIndexingFeaturesEXT physicalDeviceDescriptorIndexingFeatures { } ;
2021-01-28 22:04:25 +01:00
struct Vertex {
float pos [ 3 ] ;
float uv [ 2 ] ;
int32_t textureIndex ;
} ;
2023-12-30 13:15:37 +01:00
VulkanExample ( ) : VulkanExampleBase ( )
2019-06-10 13:07:48 +02:00
{
title = " Descriptor indexing " ;
camera . type = Camera : : CameraType : : lookat ;
2021-01-28 22:04:25 +01:00
camera . setPosition ( glm : : vec3 ( 0.0f , 0.0f , - 10.0f ) ) ;
2019-06-10 13:07:48 +02:00
camera . setRotation ( glm : : vec3 ( - 35.0f , 0.0f , 0.0f ) ) ;
camera . setPerspective ( 45.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
2020-05-29 16:08:53 +01:00
2021-01-28 22:04:25 +01:00
// [POI] Enable required extensions
2019-06-10 13:07:48 +02:00
enabledInstanceExtensions . push_back ( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) ;
2024-05-04 07:53:08 -04:00
enabledDeviceExtensions . push_back ( VK_KHR_MAINTENANCE1_EXTENSION_NAME ) ;
2019-06-10 13:07:48 +02:00
enabledDeviceExtensions . push_back ( VK_KHR_MAINTENANCE3_EXTENSION_NAME ) ;
enabledDeviceExtensions . push_back ( VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME ) ;
2021-01-28 22:04:25 +01:00
// [POI] Enable required extension features
2019-06-10 13:07:48 +02:00
physicalDeviceDescriptorIndexingFeatures . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT ;
physicalDeviceDescriptorIndexingFeatures . shaderSampledImageArrayNonUniformIndexing = VK_TRUE ;
physicalDeviceDescriptorIndexingFeatures . runtimeDescriptorArray = VK_TRUE ;
physicalDeviceDescriptorIndexingFeatures . descriptorBindingVariableDescriptorCount = VK_TRUE ;
deviceCreatepNextChain = & physicalDeviceDescriptorIndexingFeatures ;
2024-05-18 10:01:01 +02:00
2025-03-29 11:21:37 -04:00
# if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT))
// Use layer settings extension to configure MoltenVK
enabledInstanceExtensions . push_back ( VK_EXT_LAYER_SETTINGS_EXTENSION_NAME ) ;
// Configure MoltenVK to use Metal argument buffers (needed for descriptor indexing)
VkLayerSettingEXT layerSetting ;
layerSetting . pLayerName = " MoltenVK " ;
layerSetting . pSettingName = " MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS " ;
layerSetting . type = VK_LAYER_SETTING_TYPE_BOOL32_EXT ;
layerSetting . valueCount = 1 ;
// Make this static so layer setting reference remains valid after leaving constructor scope
static const VkBool32 layerSettingOn = VK_TRUE ;
layerSetting . pValues = & layerSettingOn ;
enabledLayerSettings . push_back ( layerSetting ) ;
2022-08-05 00:27:58 -04:00
# endif
2019-06-10 13:07:48 +02:00
}
~ VulkanExample ( )
{
2024-01-16 19:32:34 +01:00
if ( device ) {
for ( auto & texture : textures ) {
texture . destroy ( ) ;
}
vkDestroyPipeline ( device , pipeline , nullptr ) ;
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
vertexBuffer . destroy ( ) ;
indexBuffer . destroy ( ) ;
uniformBuffer . destroy ( ) ;
2021-01-28 22:04:25 +01:00
}
2019-06-10 13:07:48 +02:00
}
2021-01-28 22:04:25 +01:00
// Generate some random textures
void generateTextures ( )
2019-06-10 13:07:48 +02:00
{
2021-01-28 22:04:25 +01:00
textures . resize ( 32 ) ;
for ( size_t i = 0 ; i < textures . size ( ) ; i + + ) {
std : : random_device rndDevice ;
2024-05-18 10:01:01 +02:00
std : : default_random_engine rndEngine ( benchmark . active ? 0 : rndDevice ( ) ) ;
2023-12-27 19:58:33 +01:00
std : : uniform_int_distribution < > rndDist ( 50 , UCHAR_MAX ) ;
2021-01-28 22:04:25 +01:00
const int32_t dim = 3 ;
const size_t bufferSize = dim * dim * 4 ;
std : : vector < uint8_t > texture ( bufferSize ) ;
for ( size_t i = 0 ; i < dim * dim ; i + + ) {
texture [ i * 4 ] = rndDist ( rndEngine ) ;
texture [ i * 4 + 1 ] = rndDist ( rndEngine ) ;
texture [ i * 4 + 2 ] = rndDist ( rndEngine ) ;
texture [ i * 4 + 3 ] = 255 ;
}
textures [ i ] . fromBuffer ( texture . data ( ) , bufferSize , VK_FORMAT_R8G8B8A8_UNORM , dim , dim , vulkanDevice , queue , VK_FILTER_NEAREST ) ;
2019-06-10 13:07:48 +02:00
}
}
2024-01-16 19:32:34 +01:00
// Generates a line of cubes with randomized per-face texture indices and uploads them to the GPU
2021-01-28 22:04:25 +01:00
void generateCubes ( )
2019-06-10 13:07:48 +02:00
{
std : : vector < Vertex > vertices ;
std : : vector < uint32_t > indices ;
2021-01-28 22:04:25 +01:00
// Generate random per-face texture indices
std : : random_device rndDevice ;
2024-05-18 10:01:01 +02:00
std : : default_random_engine rndEngine ( benchmark . active ? 0 : rndDevice ( ) ) ;
2021-01-28 22:04:25 +01:00
std : : uniform_int_distribution < int32_t > rndDist ( 0 , static_cast < uint32_t > ( textures . size ( ) ) - 1 ) ;
// Generate cubes with random per-face texture indices
2022-08-08 02:15:03 -04:00
const uint32_t count = 5 ;
2021-01-28 22:04:25 +01:00
for ( uint32_t i = 0 ; i < count ; i + + ) {
2022-08-08 02:15:03 -04:00
// Push indices to buffer
const std : : vector < uint32_t > cubeIndices = {
0 , 1 , 2 , 0 , 2 , 3 ,
4 , 5 , 6 , 4 , 6 , 7 ,
8 , 9 , 10 , 8 , 10 , 11 ,
12 , 13 , 14 , 12 , 14 , 15 ,
16 , 17 , 18 , 16 , 18 , 19 ,
20 , 21 , 22 , 20 , 22 , 23
} ;
for ( auto & index : cubeIndices ) {
indices . push_back ( index + static_cast < uint32_t > ( vertices . size ( ) ) ) ;
}
2021-01-28 22:04:25 +01:00
// Get random per-Face texture indices that the shader will sample from
int32_t textureIndices [ 6 ] ;
for ( uint32_t j = 0 ; j < 6 ; j + + ) {
textureIndices [ j ] = rndDist ( rndEngine ) ;
}
// Push vertices to buffer
2022-08-08 02:15:03 -04:00
float pos = 2.5f * i - ( count * 2.5f / 2.0f ) + 1.25f ;
2021-01-28 22:04:25 +01:00
const std : : vector < Vertex > cube = {
{ { - 1.0f + pos , - 1.0f , 1.0f } , { 0.0f , 0.0f } , textureIndices [ 0 ] } ,
{ { 1.0f + pos , - 1.0f , 1.0f } , { 1.0f , 0.0f } , textureIndices [ 0 ] } ,
{ { 1.0f + pos , 1.0f , 1.0f } , { 1.0f , 1.0f } , textureIndices [ 0 ] } ,
{ { - 1.0f + pos , 1.0f , 1.0f } , { 0.0f , 1.0f } , textureIndices [ 0 ] } ,
{ { 1.0f + pos , 1.0f , 1.0f } , { 0.0f , 0.0f } , textureIndices [ 1 ] } ,
{ { 1.0f + pos , 1.0f , - 1.0f } , { 1.0f , 0.0f } , textureIndices [ 1 ] } ,
{ { 1.0f + pos , - 1.0f , - 1.0f } , { 1.0f , 1.0f } , textureIndices [ 1 ] } ,
{ { 1.0f + pos , - 1.0f , 1.0f } , { 0.0f , 1.0f } , textureIndices [ 1 ] } ,
{ { - 1.0f + pos , - 1.0f , - 1.0f } , { 0.0f , 0.0f } , textureIndices [ 2 ] } ,
{ { 1.0f + pos , - 1.0f , - 1.0f } , { 1.0f , 0.0f } , textureIndices [ 2 ] } ,
{ { 1.0f + pos , 1.0f , - 1.0f } , { 1.0f , 1.0f } , textureIndices [ 2 ] } ,
{ { - 1.0f + pos , 1.0f , - 1.0f } , { 0.0f , 1.0f } , textureIndices [ 2 ] } ,
{ { - 1.0f + pos , - 1.0f , - 1.0f } , { 0.0f , 0.0f } , textureIndices [ 3 ] } ,
{ { - 1.0f + pos , - 1.0f , 1.0f } , { 1.0f , 0.0f } , textureIndices [ 3 ] } ,
{ { - 1.0f + pos , 1.0f , 1.0f } , { 1.0f , 1.0f } , textureIndices [ 3 ] } ,
{ { - 1.0f + pos , 1.0f , - 1.0f } , { 0.0f , 1.0f } , textureIndices [ 3 ] } ,
{ { 1.0f + pos , 1.0f , 1.0f } , { 0.0f , 0.0f } , textureIndices [ 4 ] } ,
{ { - 1.0f + pos , 1.0f , 1.0f } , { 1.0f , 0.0f } , textureIndices [ 4 ] } ,
{ { - 1.0f + pos , 1.0f , - 1.0f } , { 1.0f , 1.0f } , textureIndices [ 4 ] } ,
{ { 1.0f + pos , 1.0f , - 1.0f } , { 0.0f , 1.0f } , textureIndices [ 4 ] } ,
{ { - 1.0f + pos , - 1.0f , - 1.0f } , { 0.0f , 0.0f } , textureIndices [ 5 ] } ,
{ { 1.0f + pos , - 1.0f , - 1.0f } , { 1.0f , 0.0f } , textureIndices [ 5 ] } ,
{ { 1.0f + pos , - 1.0f , 1.0f } , { 1.0f , 1.0f } , textureIndices [ 5 ] } ,
{ { - 1.0f + pos , - 1.0f , 1.0f } , { 0.0f , 1.0f } , textureIndices [ 5 ] } ,
} ;
for ( auto & vertex : cube ) {
vertices . push_back ( vertex ) ;
}
}
2019-06-10 13:07:48 +02:00
indexCount = static_cast < uint32_t > ( indices . size ( ) ) ;
2024-01-16 19:32:34 +01:00
// Create buffers and upload data to the GPU
struct StagingBuffers {
vks : : Buffer vertices ;
vks : : Buffer indices ;
} stagingBuffers ;
// Host visible source buffers (staging)
VK_CHECK_RESULT ( vulkanDevice - > createBuffer ( VK_BUFFER_USAGE_TRANSFER_SRC_BIT , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT , & stagingBuffers . vertices , vertices . size ( ) * sizeof ( Vertex ) , vertices . data ( ) ) ) ;
VK_CHECK_RESULT ( vulkanDevice - > createBuffer ( VK_BUFFER_USAGE_TRANSFER_SRC_BIT , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT , & stagingBuffers . indices , indices . size ( ) * sizeof ( uint32_t ) , indices . data ( ) ) ) ;
// Device local destination buffers
VK_CHECK_RESULT ( vulkanDevice - > createBuffer ( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , & vertexBuffer , vertices . size ( ) * sizeof ( Vertex ) ) ) ;
VK_CHECK_RESULT ( vulkanDevice - > createBuffer ( VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , & indexBuffer , indices . size ( ) * sizeof ( uint32_t ) ) ) ;
// Copy from host do device
vulkanDevice - > copyBuffer ( & stagingBuffers . vertices , & vertexBuffer , queue ) ;
vulkanDevice - > copyBuffer ( & stagingBuffers . indices , & indexBuffer , queue ) ;
// Clean up
stagingBuffers . vertices . destroy ( ) ;
stagingBuffers . indices . destroy ( ) ;
2019-06-10 13:07:48 +02:00
}
2021-01-28 22:04:25 +01:00
// [POI] Set up descriptor sets and set layout
2024-01-21 13:19:40 +01:00
void setupDescriptors ( )
2019-06-10 13:07:48 +02:00
{
2021-01-28 22:04:25 +01:00
// Descriptor pool
std : : vector < VkDescriptorPoolSize > poolSizes = {
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 ) ,
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , static_cast < uint32_t > ( textures . size ( ) ) )
} ;
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , 2 ) ;
2025-03-29 11:21:37 -04:00
# if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT))
// Increase the per-stage descriptor samplers limit on macOS/iOS (maxPerStageDescriptorUpdateAfterBindSamplers > maxPerStageDescriptorSamplers)
2022-08-05 00:27:58 -04:00
descriptorPoolInfo . flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT ;
# endif
2021-01-28 22:04:25 +01:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2019-06-10 13:07:48 +02:00
2021-01-28 22:04:25 +01:00
// Descriptor set layout
2019-06-10 13:07:48 +02:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
// Binding 0 : Vertex shader uniform buffer
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_VERTEX_BIT , 0 ) ,
2024-01-16 19:32:34 +01:00
// [POI] Binding 1 contains a texture array that is dynamically non-uniform sampled from in the fragment shader:
2021-01-28 22:04:25 +01:00
// outFragColor = texture(textures[nonuniformEXT(inTexIndex)], inUV);
2019-06-10 13:07:48 +02:00
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 1 , static_cast < uint32_t > ( textures . size ( ) ) )
} ;
2021-01-28 22:04:25 +01:00
// [POI] The fragment shader will be using an unsized array of samplers, which has to be marked with the VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT
2019-06-10 13:07:48 +02:00
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT setLayoutBindingFlags { } ;
setLayoutBindingFlags . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT ;
setLayoutBindingFlags . bindingCount = 2 ;
2023-12-29 19:00:35 +01:00
// Binding 0 is the vertex shader uniform buffer, which does not use indexing
// Binding 1 are the fragment shader images, which use indexing
// In the fragment shader:
// layout (set = 0, binding = 1) uniform sampler2D textures[];
2025-03-29 11:21:37 -04:00
# if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT))
// Disable variable descriptor count feature on macOS/iOS until MoltenVK supports this feature when using combined image sampler textures
// Note we are using only 1 descriptor set with a fixed descriptor count/pool size, so we can simply turn off the capability for now
2019-06-10 13:07:48 +02:00
std : : vector < VkDescriptorBindingFlagsEXT > descriptorBindingFlags = {
2020-05-29 16:08:53 +01:00
0 ,
2025-03-29 11:21:37 -04:00
0
2019-06-10 13:07:48 +02:00
} ;
setLayoutBindingFlags . pBindingFlags = descriptorBindingFlags . data ( ) ;
2021-01-28 22:04:25 +01:00
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
2025-03-29 11:21:37 -04:00
// Increase the per-stage descriptor samplers limit on macOS/iOS (maxPerStageDescriptorUpdateAfterBindSamplers > maxPerStageDescriptorSamplers)
2022-08-05 00:27:58 -04:00
descriptorSetLayoutCI . flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT ;
2025-03-29 11:21:37 -04:00
descriptorSetLayoutCI . pNext = & setLayoutBindingFlags ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayout ) ) ;
// [POI] Descriptor sets
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayout , 1 ) ;
allocInfo . pNext = nullptr ;
# else
// Enable variable descriptor count feature on platforms other than macOS/iOS
std : : vector < VkDescriptorBindingFlagsEXT > descriptorBindingFlags = {
0 ,
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT
} ;
setLayoutBindingFlags . pBindingFlags = descriptorBindingFlags . data ( ) ;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
2019-06-10 13:07:48 +02:00
descriptorSetLayoutCI . pNext = & setLayoutBindingFlags ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayout ) ) ;
2023-12-29 19:00:35 +01:00
// [POI] Descriptor sets
// We need to provide the descriptor counts for bindings with variable counts using a new structure
2024-05-18 10:01:01 +02:00
std : : vector < uint32_t > variableDesciptorCounts = {
2023-12-29 19:00:35 +01:00
static_cast < uint32_t > ( textures . size ( ) )
} ;
2020-12-16 10:40:23 +00:00
2023-12-29 19:00:35 +01:00
VkDescriptorSetVariableDescriptorCountAllocateInfoEXT variableDescriptorCountAllocInfo = { } ;
2020-12-16 10:51:27 +00:00
variableDescriptorCountAllocInfo . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT ;
2023-12-29 19:00:35 +01:00
variableDescriptorCountAllocInfo . descriptorSetCount = static_cast < uint32_t > ( variableDesciptorCounts . size ( ) ) ;
variableDescriptorCountAllocInfo . pDescriptorCounts = variableDesciptorCounts . data ( ) ;
2020-12-16 10:40:23 +00:00
2019-06-10 13:07:48 +02:00
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayout , 1 ) ;
2020-12-16 10:40:23 +00:00
allocInfo . pNext = & variableDescriptorCountAllocInfo ;
2025-03-29 11:21:37 -04:00
# endif
2024-05-18 10:01:01 +02:00
2019-06-10 13:07:48 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
std : : vector < VkWriteDescriptorSet > writeDescriptorSets ( 2 ) ;
2024-01-16 19:32:34 +01:00
writeDescriptorSets [ 0 ] = vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 0 , & uniformBuffer . descriptor ) ;
2019-06-10 13:07:48 +02:00
// Image descriptors for the texture array
std : : vector < VkDescriptorImageInfo > textureDescriptors ( textures . size ( ) ) ;
for ( size_t i = 0 ; i < textures . size ( ) ; i + + ) {
textureDescriptors [ i ] . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
textureDescriptors [ i ] . sampler = textures [ i ] . sampler ; ;
textureDescriptors [ i ] . imageView = textures [ i ] . view ;
}
2021-01-28 22:04:25 +01:00
// [POI] Second and final descriptor is a texture array
// Unlike an array texture, these are adressed like typical arrays
2019-06-10 13:07:48 +02:00
writeDescriptorSets [ 1 ] = { } ;
writeDescriptorSets [ 1 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 1 ] . dstBinding = 1 ;
writeDescriptorSets [ 1 ] . dstArrayElement = 0 ;
writeDescriptorSets [ 1 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
writeDescriptorSets [ 1 ] . descriptorCount = static_cast < uint32_t > ( textures . size ( ) ) ;
writeDescriptorSets [ 1 ] . pBufferInfo = 0 ;
writeDescriptorSets [ 1 ] . dstSet = descriptorSet ;
writeDescriptorSets [ 1 ] . pImageInfo = textureDescriptors . data ( ) ;
2021-01-28 22:04:25 +01:00
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , nullptr ) ;
2019-06-10 13:07:48 +02:00
}
void preparePipelines ( )
{
2024-01-16 19:32:34 +01:00
// Layout
2019-06-10 13:07:48 +02:00
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks : : initializers : : pipelineLayoutCreateInfo ( & descriptorSetLayout , 1 ) ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCreateInfo , nullptr , & pipelineLayout ) ) ;
2024-01-16 19:32:34 +01:00
// Pipeline
2019-06-10 13:07:48 +02:00
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks : : initializers : : pipelineInputAssemblyStateCreateInfo ( VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST , 0 , VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks : : initializers : : pipelineRasterizationStateCreateInfo ( VK_POLYGON_MODE_FILL , VK_CULL_MODE_NONE , VK_FRONT_FACE_COUNTER_CLOCKWISE , 0 ) ;
2020-05-29 16:08:53 +01:00
VkPipelineColorBlendAttachmentState blendAttachmentState = vks : : initializers : : pipelineColorBlendAttachmentState ( 0xf , VK_FALSE ) ;
2019-06-10 13:07:48 +02:00
VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks : : initializers : : pipelineColorBlendStateCreateInfo ( 1 , & blendAttachmentState ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks : : initializers : : pipelineDepthStencilStateCreateInfo ( VK_TRUE , VK_TRUE , VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportStateCI = vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 , 0 ) ;
VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks : : initializers : : pipelineMultisampleStateCreateInfo ( VK_SAMPLE_COUNT_1_BIT , 0 ) ;
std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
2021-01-28 22:04:25 +01:00
VkPipelineDynamicStateCreateInfo dynamicStateCI = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables ) ;
2019-06-10 13:07:48 +02:00
// Vertex bindings and attributes
VkVertexInputBindingDescription vertexInputBinding = { 0 , sizeof ( Vertex ) , VK_VERTEX_INPUT_RATE_VERTEX } ;
std : : vector < VkVertexInputAttributeDescription > vertexInputAttributes = {
{ 0 , 0 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( Vertex , pos ) } ,
{ 1 , 0 , VK_FORMAT_R32G32_SFLOAT , offsetof ( Vertex , uv ) } ,
{ 2 , 0 , VK_FORMAT_R32_SINT , offsetof ( Vertex , textureIndex ) }
} ;
VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
vertexInputStateCI . vertexBindingDescriptionCount = 1 ;
vertexInputStateCI . pVertexBindingDescriptions = & vertexInputBinding ;
vertexInputStateCI . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertexInputAttributes . size ( ) ) ;
vertexInputStateCI . pVertexAttributeDescriptions = vertexInputAttributes . data ( ) ;
// Instacing pipeline
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2020-05-29 16:08:53 +01:00
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " descriptorindexing/descriptorindexing.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
2023-12-29 19:00:35 +01:00
// [POI] The fragment shader does non-uniform access into our sampler array, so we need to use nonuniformEXT: texture(textures[nonuniformEXT(inTexIndex)], inUV) in it (see descriptorindexing.frag)
2020-05-29 16:08:53 +01:00
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " descriptorindexing/descriptorindexing.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2019-06-10 13:07:48 +02:00
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelineLayout , renderPass , 0 ) ;
pipelineCI . pVertexInputState = & vertexInputStateCI ;
pipelineCI . pInputAssemblyState = & inputAssemblyStateCI ;
pipelineCI . pRasterizationState = & rasterizationStateCI ;
pipelineCI . pColorBlendState = & colorBlendStateCI ;
pipelineCI . pMultisampleState = & multisampleStateCI ;
pipelineCI . pViewportState = & viewportStateCI ;
pipelineCI . pDepthStencilState = & depthStencilStateCI ;
pipelineCI . pDynamicState = & dynamicStateCI ;
2021-01-28 22:04:25 +01:00
pipelineCI . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
2019-06-10 13:07:48 +02:00
pipelineCI . pStages = shaderStages . data ( ) ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipeline ) ) ;
}
void prepareUniformBuffers ( )
{
2024-01-16 19:32:34 +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 ) ) ) ;
VK_CHECK_RESULT ( uniformBuffer . map ( ) ) ;
2019-06-10 13:07:48 +02:00
updateUniformBuffersCamera ( ) ;
}
void updateUniformBuffersCamera ( )
{
2024-01-16 19:32:34 +01:00
uniformData . projection = camera . matrices . perspective ;
uniformData . view = camera . matrices . view ;
uniformData . model = glm : : mat4 ( 1.0f ) ;
memcpy ( uniformBuffer . mapped , & uniformData , sizeof ( UniformData ) ) ;
2019-06-10 13:07:48 +02:00
}
2021-01-28 22:04:25 +01:00
void buildCommandBuffers ( )
{
VkClearValue clearValues [ 2 ] ;
clearValues [ 0 ] . color = defaultClearColor ;
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 ] ;
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
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 ) ;
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSet , 0 , NULL ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
VkDeviceSize offsets [ 1 ] = { 0 } ;
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , 0 , 1 , & vertexBuffer . buffer , offsets ) ;
vkCmdBindIndexBuffer ( drawCmdBuffers [ i ] , indexBuffer . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
vkCmdDrawIndexed ( drawCmdBuffers [ i ] , indexCount , 1 , 0 , 0 , 0 ) ;
drawUI ( drawCmdBuffers [ i ] ) ;
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
}
}
2019-06-10 13:07:48 +02:00
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2021-01-28 22:04:25 +01:00
generateTextures ( ) ;
generateCubes ( ) ;
2019-06-10 13:07:48 +02:00
prepareUniformBuffers ( ) ;
2024-01-21 13:19:40 +01:00
setupDescriptors ( ) ;
2019-06-10 13:07:48 +02:00
preparePipelines ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
2024-01-16 19:32:34 +01:00
void draw ( )
2019-06-10 13:07:48 +02:00
{
2024-01-16 19:32:34 +01:00
VulkanExampleBase : : prepareFrame ( ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
2019-06-10 13:07:48 +02:00
}
2024-01-16 19:32:34 +01:00
virtual void render ( )
2022-06-13 23:04:53 -04:00
{
2024-01-16 19:32:34 +01:00
if ( ! prepared )
return ;
2022-06-13 23:04:53 -04:00
updateUniformBuffersCamera ( ) ;
2024-01-16 19:32:34 +01:00
draw ( ) ;
2022-06-13 23:04:53 -04:00
}
2019-06-10 13:07:48 +02:00
} ;
2022-08-05 00:27:58 -04:00
VULKAN_EXAMPLE_MAIN ( )