2016-02-16 15:07:25 +01:00
/*
* Vulkan Example - Texture arrays and instanced rendering
*
2019-04-13 13:38:17 +02:00
* Copyright ( C ) Sascha Willems - www . saschawillems . de
2016-02-16 15:07:25 +01:00
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
# include "vulkanexamplebase.h"
2019-08-03 09:56:58 +02:00
# include <ktx.h>
# include <ktxvulkan.h>
2016-02-16 15:07:25 +01:00
# define ENABLE_VALIDATION false
2022-08-08 13:46:30 -04:00
# define MAX_LAYERS 8
2016-02-16 15:07:25 +01:00
// Vertex layout for this example
struct Vertex {
float pos [ 3 ] ;
float uv [ 2 ] ;
} ;
class VulkanExample : public VulkanExampleBase
{
public :
// Number of array layers in texture array
// Also used as instance count
uint32_t layerCount ;
2017-02-09 21:55:35 +01:00
vks : : Texture textureArray ;
2016-02-16 15:07:25 +01:00
2017-02-12 10:44:51 +01:00
vks : : Buffer vertexBuffer ;
vks : : Buffer indexBuffer ;
2017-01-07 19:37:36 +01:00
uint32_t indexCount ;
2016-02-16 15:07:25 +01:00
2017-02-12 10:44:51 +01:00
vks : : Buffer uniformBufferVS ;
2016-02-16 15:07:25 +01:00
struct UboInstanceData {
// Model matrix
glm : : mat4 model ;
// Texture array index
// Vec4 due to padding
glm : : vec4 arrayIndex ;
} ;
struct {
// Global matrices
struct {
glm : : mat4 projection ;
glm : : mat4 view ;
} matrices ;
2020-08-08 18:22:10 +02:00
// Separate data for each instance
2020-01-10 13:28:56 +01:00
UboInstanceData * instance ;
2016-02-16 15:07:25 +01:00
} uboVS ;
2016-12-24 12:48:01 +01:00
VkPipeline pipeline ;
2016-02-16 15:07:25 +01:00
VkPipelineLayout pipelineLayout ;
VkDescriptorSet descriptorSet ;
VkDescriptorSetLayout descriptorSetLayout ;
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
{
2017-11-01 14:22:10 +01:00
title = " Texture arrays " ;
2019-04-13 13:38:17 +02:00
camera . type = Camera : : CameraType : : lookat ;
camera . setPosition ( glm : : vec3 ( 0.0f , 0.0f , - 7.5f ) ) ;
camera . setRotation ( glm : : vec3 ( - 35.0f , 0.0f , 0.0f ) ) ;
camera . setPerspective ( 45.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
2016-02-16 15:07:25 +01:00
}
~ VulkanExample ( )
{
2020-01-10 13:28:56 +01:00
// Clean up used Vulkan resources
2016-02-16 15:07:25 +01:00
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyImageView ( device , textureArray . view , nullptr ) ;
vkDestroyImage ( device , textureArray . image , nullptr ) ;
vkDestroySampler ( device , textureArray . sampler , nullptr ) ;
vkFreeMemory ( device , textureArray . deviceMemory , nullptr ) ;
2016-12-24 12:48:01 +01:00
vkDestroyPipeline ( device , pipeline , nullptr ) ;
2016-02-16 15:07:25 +01:00
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
2017-01-07 19:37:36 +01:00
vertexBuffer . destroy ( ) ;
indexBuffer . destroy ( ) ;
2016-02-16 15:07:25 +01:00
2017-01-07 19:37:36 +01:00
uniformBufferVS . destroy ( ) ;
2016-02-16 15:07:25 +01:00
delete [ ] uboVS . instance ;
}
2016-03-25 15:29:38 +01:00
void loadTextureArray ( std : : string filename , VkFormat format )
2016-02-16 15:07:25 +01:00
{
2019-08-03 09:55:46 +02:00
ktxResult result ;
ktxTexture * ktxTexture ;
2016-03-25 15:29:38 +01:00
# if defined(__ANDROID__)
// Textures are stored inside the apk on Android (compressed)
// So they need to be loaded via the asset manager
AAsset * asset = AAssetManager_open ( androidApp - > activity - > assetManager , filename . c_str ( ) , AASSET_MODE_STREAMING ) ;
2019-08-03 09:55:46 +02:00
if ( ! asset ) {
vks : : tools : : exitFatal ( " Could not load texture from " + filename + " \n \n The file may be part of the additional asset pack. \n \n Run \" download_assets.py \" in the repository root to download the latest version. " , - 1 ) ;
}
2016-03-25 15:29:38 +01:00
size_t size = AAsset_getLength ( asset ) ;
assert ( size > 0 ) ;
2019-08-03 18:20:27 +02:00
ktx_uint8_t * textureData = new ktx_uint8_t [ size ] ;
2016-03-25 15:29:38 +01:00
AAsset_read ( asset , textureData , size ) ;
AAsset_close ( asset ) ;
2019-08-03 18:20:27 +02:00
result = ktxTexture_CreateFromMemory ( textureData , size , KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT , & ktxTexture ) ;
delete [ ] textureData ;
2019-08-03 09:55:46 +02:00
# else
if ( ! vks : : tools : : fileExists ( filename ) ) {
vks : : tools : : exitFatal ( " Could not load texture from " + filename + " \n \n The file may be part of the additional asset pack. \n \n Run \" download_assets.py \" in the repository root to download the latest version. " , - 1 ) ;
}
result = ktxTexture_CreateFromNamedFile ( filename . c_str ( ) , KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT , & ktxTexture ) ;
2020-01-10 13:28:56 +01:00
# endif
2019-08-03 09:55:46 +02:00
assert ( result = = KTX_SUCCESS ) ;
2016-02-16 15:07:25 +01:00
2019-08-03 09:55:46 +02:00
// Get properties required for using and upload texture data from the ktx texture object
textureArray . width = ktxTexture - > baseWidth ;
textureArray . height = ktxTexture - > baseHeight ;
layerCount = ktxTexture - > numLayers ;
2022-08-08 13:46:30 -04:00
assert ( layerCount < = MAX_LAYERS ) ;
2019-08-03 09:55:46 +02:00
ktx_uint8_t * ktxTextureData = ktxTexture_GetData ( ktxTexture ) ;
ktx_size_t ktxTextureSize = ktxTexture_GetSize ( ktxTexture ) ;
2016-02-16 15:07:25 +01:00
2017-02-12 11:12:42 +01:00
VkMemoryAllocateInfo memAllocInfo = vks : : initializers : : memoryAllocateInfo ( ) ;
2016-02-16 15:07:25 +01:00
VkMemoryRequirements memReqs ;
2016-05-14 12:19:18 +02:00
// Create a host-visible staging buffer that contains the raw image data
VkBuffer stagingBuffer ;
VkDeviceMemory stagingMemory ;
2016-02-16 15:07:25 +01:00
2017-02-12 11:12:42 +01:00
VkBufferCreateInfo bufferCreateInfo = vks : : initializers : : bufferCreateInfo ( ) ;
2019-08-03 09:55:46 +02:00
bufferCreateInfo . size = ktxTextureSize ;
2016-05-14 12:19:18 +02:00
// This buffer is used as a transfer source for the buffer copy
bufferCreateInfo . usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT ;
bufferCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
2016-02-16 15:07:25 +01:00
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkCreateBuffer ( device , & bufferCreateInfo , nullptr , & stagingBuffer ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 12:19:18 +02:00
// Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements ( device , stagingBuffer , & memReqs ) ;
memAllocInfo . allocationSize = memReqs . size ;
// Get memory type index for a host visible buffer
2017-03-04 13:56:09 +01:00
memAllocInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ) ;
2016-05-14 12:19:18 +02:00
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & stagingMemory ) ) ;
VK_CHECK_RESULT ( vkBindBufferMemory ( device , stagingBuffer , stagingMemory , 0 ) ) ;
2016-05-14 12:19:18 +02:00
// Copy texture data into staging buffer
uint8_t * data ;
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkMapMemory ( device , stagingMemory , 0 , memReqs . size , 0 , ( void * * ) & data ) ) ;
2019-08-03 09:55:46 +02:00
memcpy ( data , ktxTextureData , ktxTextureSize ) ;
2016-05-14 12:19:18 +02:00
vkUnmapMemory ( device , stagingMemory ) ;
// Setup buffer copy regions for array layers
std : : vector < VkBufferImageCopy > bufferCopyRegions ;
2019-08-03 09:55:46 +02:00
// To keep this simple, we will only load layers and no mip level
2016-05-14 12:19:18 +02:00
for ( uint32_t layer = 0 ; layer < layerCount ; layer + + )
{
2019-08-03 09:55:46 +02:00
// Calculate offset into staging buffer for the current array layer
ktx_size_t offset ;
2020-01-10 13:28:56 +01:00
KTX_error_code ret = ktxTexture_GetImageOffset ( ktxTexture , 0 , layer , 0 , & offset ) ;
assert ( ret = = KTX_SUCCESS ) ;
2019-08-03 09:55:46 +02:00
// Setup a buffer image copy structure for the current array layer
2016-05-14 12:19:18 +02:00
VkBufferImageCopy bufferCopyRegion = { } ;
bufferCopyRegion . imageSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
bufferCopyRegion . imageSubresource . mipLevel = 0 ;
2017-03-23 20:16:41 +01:00
bufferCopyRegion . imageSubresource . baseArrayLayer = layer ;
bufferCopyRegion . imageSubresource . layerCount = 1 ;
2019-08-03 09:55:46 +02:00
bufferCopyRegion . imageExtent . width = ktxTexture - > baseWidth ;
bufferCopyRegion . imageExtent . height = ktxTexture - > baseHeight ;
2016-05-14 12:19:18 +02:00
bufferCopyRegion . imageExtent . depth = 1 ;
bufferCopyRegion . bufferOffset = offset ;
bufferCopyRegions . push_back ( bufferCopyRegion ) ;
}
2016-02-16 15:07:25 +01:00
2016-05-14 12:19:18 +02:00
// Create optimal tiled target image
2017-02-12 11:12:42 +01:00
VkImageCreateInfo imageCreateInfo = vks : : initializers : : imageCreateInfo ( ) ;
2016-05-14 12:19:18 +02:00
imageCreateInfo . imageType = VK_IMAGE_TYPE_2D ;
imageCreateInfo . format = format ;
imageCreateInfo . mipLevels = 1 ;
imageCreateInfo . samples = VK_SAMPLE_COUNT_1_BIT ;
2016-02-16 15:07:25 +01:00
imageCreateInfo . tiling = VK_IMAGE_TILING_OPTIMAL ;
2016-05-14 12:19:18 +02:00
imageCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
2016-06-22 20:30:14 +02:00
imageCreateInfo . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
2016-05-14 12:19:18 +02:00
imageCreateInfo . extent = { textureArray . width , textureArray . height , 1 } ;
2016-02-16 15:07:25 +01:00
imageCreateInfo . usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ;
imageCreateInfo . arrayLayers = layerCount ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCreateInfo , nullptr , & textureArray . image ) ) ;
2016-02-16 15:07:25 +01:00
vkGetImageMemoryRequirements ( device , textureArray . image , & memReqs ) ;
memAllocInfo . allocationSize = memReqs . size ;
2016-07-23 20:42:03 +02:00
memAllocInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & textureArray . deviceMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , textureArray . image , textureArray . deviceMemory , 0 ) ) ;
2016-02-16 15:07:25 +01:00
2020-04-20 22:13:51 +02:00
VkCommandBuffer copyCmd = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
2016-02-16 15:07:25 +01:00
// Image barrier for optimal image (target)
2016-05-14 12:19:18 +02:00
// Set initial layout for all array layers (faces) of the optimal (target) tiled texture
2016-03-13 13:55:04 +01:00
VkImageSubresourceRange subresourceRange = { } ;
subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
subresourceRange . baseMipLevel = 0 ;
subresourceRange . levelCount = 1 ;
subresourceRange . layerCount = layerCount ;
2017-02-12 13:10:05 +01:00
vks : : tools : : setImageLayout (
2016-05-14 12:19:18 +02:00
copyCmd ,
2016-02-16 15:07:25 +01:00
textureArray . image ,
2016-06-22 20:30:14 +02:00
VK_IMAGE_LAYOUT_UNDEFINED ,
2016-03-13 13:55:04 +01:00
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
subresourceRange ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 12:19:18 +02:00
// Copy the cube map faces from the staging buffer to the optimal tiled image
vkCmdCopyBufferToImage (
copyCmd ,
stagingBuffer ,
textureArray . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
bufferCopyRegions . size ( ) ,
bufferCopyRegions . data ( )
) ;
2016-02-16 15:07:25 +01:00
2016-05-14 12:19:18 +02:00
// Change texture image layout to shader read after all faces have been copied
2016-03-13 13:55:04 +01:00
textureArray . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
2017-02-12 13:10:05 +01:00
vks : : tools : : setImageLayout (
2016-05-14 12:19:18 +02:00
copyCmd ,
2016-03-13 13:55:04 +01:00
textureArray . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
textureArray . imageLayout ,
subresourceRange ) ;
2020-04-20 22:13:51 +02:00
vulkanDevice - > flushCommandBuffer ( copyCmd , queue , true ) ;
2016-02-16 15:07:25 +01:00
// Create sampler
2017-02-12 11:12:42 +01:00
VkSamplerCreateInfo sampler = vks : : initializers : : samplerCreateInfo ( ) ;
2016-02-16 15:07:25 +01:00
sampler . magFilter = VK_FILTER_LINEAR ;
sampler . minFilter = VK_FILTER_LINEAR ;
sampler . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ;
sampler . addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
sampler . addressModeV = sampler . addressModeU ;
sampler . addressModeW = sampler . addressModeU ;
sampler . mipLodBias = 0.0f ;
sampler . maxAnisotropy = 8 ;
sampler . compareOp = VK_COMPARE_OP_NEVER ;
sampler . minLod = 0.0f ;
sampler . maxLod = 0.0f ;
sampler . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkCreateSampler ( device , & sampler , nullptr , & textureArray . sampler ) ) ;
2016-02-16 15:07:25 +01:00
// Create image view
2017-02-12 11:12:42 +01:00
VkImageViewCreateInfo view = vks : : initializers : : imageViewCreateInfo ( ) ;
2016-02-16 15:07:25 +01:00
view . viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY ;
view . format = format ;
view . subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT , 0 , 1 , 0 , 1 } ;
view . subresourceRange . layerCount = layerCount ;
2017-03-23 20:16:41 +01:00
view . subresourceRange . levelCount = 1 ;
2016-02-16 15:07:25 +01:00
view . image = textureArray . image ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkCreateImageView ( device , & view , nullptr , & textureArray . view ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 12:19:18 +02:00
// Clean up staging resources
vkFreeMemory ( device , stagingMemory , nullptr ) ;
vkDestroyBuffer ( device , stagingBuffer , nullptr ) ;
2019-08-03 09:55:46 +02:00
ktxTexture_Destroy ( ktxTexture ) ;
2016-02-16 15:07:25 +01:00
}
2020-07-28 20:20:38 +02:00
void loadAssets ( )
2016-02-16 15:07:25 +01:00
{
2020-07-28 20:20:38 +02:00
loadTextureArray ( getAssetPath ( ) + " textures/texturearray_rgba.ktx " , VK_FORMAT_R8G8B8A8_UNORM ) ;
2016-02-16 15:07:25 +01:00
}
void buildCommandBuffers ( )
{
2017-02-12 11:12:42 +01:00
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
2016-02-16 15:07:25 +01:00
VkClearValue clearValues [ 2 ] ;
clearValues [ 0 ] . color = defaultClearColor ;
clearValues [ 1 ] . depthStencil = { 1.0f , 0 } ;
2017-02-12 11:12:42 +01:00
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
2016-02-16 15:07:25 +01:00
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 ] ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
2016-02-16 15:07:25 +01:00
vkCmdBeginRenderPass ( drawCmdBuffers [ i ] , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
2017-02-12 11:12:42 +01:00
VkViewport viewport = vks : : initializers : : viewport ( ( float ) width , ( float ) height , 0.0f , 1.0f ) ;
2016-02-16 15:07:25 +01:00
vkCmdSetViewport ( drawCmdBuffers [ i ] , 0 , 1 , & viewport ) ;
2017-02-12 11:12:42 +01:00
VkRect2D scissor = vks : : initializers : : rect2D ( width , height , 0 , 0 ) ;
2016-02-16 15:07:25 +01:00
vkCmdSetScissor ( drawCmdBuffers [ i ] , 0 , 1 , & scissor ) ;
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSet , 0 , NULL ) ;
2017-01-07 19:37:36 +01:00
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
2016-02-16 15:07:25 +01:00
VkDeviceSize offsets [ 1 ] = { 0 } ;
2019-04-13 13:38:17 +02:00
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , 0 , 1 , & vertexBuffer . buffer , offsets ) ;
2017-01-07 19:37:36 +01:00
vkCmdBindIndexBuffer ( drawCmdBuffers [ i ] , indexBuffer . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
2016-02-16 15:07:25 +01:00
2017-01-07 19:37:36 +01:00
vkCmdDrawIndexed ( drawCmdBuffers [ i ] , indexCount , layerCount , 0 , 0 , 0 ) ;
2016-02-16 15:07:25 +01:00
2018-08-30 21:08:02 +02:00
drawUI ( drawCmdBuffers [ i ] ) ;
2016-02-16 15:07:25 +01:00
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2016-02-16 15:07:25 +01:00
}
}
2019-04-13 13:38:17 +02:00
void generateCube ( )
2016-02-16 15:07:25 +01:00
{
2019-04-13 13:38:17 +02:00
std : : vector < Vertex > vertices = {
{ { - 1.0f , - 1.0f , 1.0f } , { 0.0f , 0.0f } } ,
{ { 1.0f , - 1.0f , 1.0f } , { 1.0f , 0.0f } } ,
{ { 1.0f , 1.0f , 1.0f } , { 1.0f , 1.0f } } ,
{ { - 1.0f , 1.0f , 1.0f } , { 0.0f , 1.0f } } ,
{ { 1.0f , 1.0f , 1.0f } , { 0.0f , 0.0f } } ,
{ { 1.0f , 1.0f , - 1.0f } , { 1.0f , 0.0f } } ,
{ { 1.0f , - 1.0f , - 1.0f } , { 1.0f , 1.0f } } ,
{ { 1.0f , - 1.0f , 1.0f } , { 0.0f , 1.0f } } ,
{ { - 1.0f , - 1.0f , - 1.0f } , { 0.0f , 0.0f } } ,
{ { 1.0f , - 1.0f , - 1.0f } , { 1.0f , 0.0f } } ,
{ { 1.0f , 1.0f , - 1.0f } , { 1.0f , 1.0f } } ,
{ { - 1.0f , 1.0f , - 1.0f } , { 0.0f , 1.0f } } ,
{ { - 1.0f , - 1.0f , - 1.0f } , { 0.0f , 0.0f } } ,
{ { - 1.0f , - 1.0f , 1.0f } , { 1.0f , 0.0f } } ,
{ { - 1.0f , 1.0f , 1.0f } , { 1.0f , 1.0f } } ,
{ { - 1.0f , 1.0f , - 1.0f } , { 0.0f , 1.0f } } ,
{ { 1.0f , 1.0f , 1.0f } , { 0.0f , 0.0f } } ,
{ { - 1.0f , 1.0f , 1.0f } , { 1.0f , 0.0f } } ,
{ { - 1.0f , 1.0f , - 1.0f } , { 1.0f , 1.0f } } ,
{ { 1.0f , 1.0f , - 1.0f } , { 0.0f , 1.0f } } ,
{ { - 1.0f , - 1.0f , - 1.0f } , { 0.0f , 0.0f } } ,
{ { 1.0f , - 1.0f , - 1.0f } , { 1.0f , 0.0f } } ,
{ { 1.0f , - 1.0f , 1.0f } , { 1.0f , 1.0f } } ,
{ { - 1.0f , - 1.0f , 1.0f } , { 0.0f , 1.0f } } ,
} ;
std : : vector < uint32_t > indices = {
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
2016-02-16 15:07:25 +01:00
} ;
2017-01-07 19:37:36 +01:00
indexCount = static_cast < uint32_t > ( indices . size ( ) ) ;
2016-02-16 15:07:25 +01:00
2017-01-07 19:37:36 +01:00
// Create buffers
// For the sake of simplicity we won't stage the vertex data to the gpu memory
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& vertexBuffer ,
vertices . size ( ) * sizeof ( Vertex ) ,
vertices . data ( ) ) ) ;
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_INDEX_BUFFER_BIT ,
2017-01-07 19:37:36 +01:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& indexBuffer ,
indices . size ( ) * sizeof ( uint32_t ) ,
indices . data ( ) ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorPool ( )
{
2019-04-13 13:38:17 +02:00
std : : vector < VkDescriptorPoolSize > poolSizes = {
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 ) ,
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 )
2016-02-16 15:07:25 +01:00
} ;
2019-04-13 13:38:17 +02:00
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes . size ( ) , poolSizes . data ( ) , 2 ) ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSetLayout ( )
{
2019-04-13 13:38:17 +02:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
2016-02-16 15:07:25 +01:00
// Binding 0 : Vertex shader uniform buffer
2019-04-13 13:38:17 +02:00
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_VERTEX_BIT , 0 ) ,
2016-02-16 15:07:25 +01:00
// Binding 1 : Fragment shader image sampler (texture array)
2019-04-13 13:38:17 +02:00
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 1 )
2016-02-16 15:07:25 +01:00
} ;
2019-04-13 13:38:17 +02:00
VkDescriptorSetLayoutCreateInfo descriptorLayout = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings . data ( ) , setLayoutBindings . size ( ) ) ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & descriptorSetLayout ) ) ;
2016-02-16 15:07:25 +01:00
2019-04-13 13:38:17 +02:00
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks : : initializers : : pipelineLayoutCreateInfo ( & descriptorSetLayout , 1 ) ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCreateInfo , nullptr , & pipelineLayout ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSet ( )
{
2019-04-13 13:38:17 +02:00
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayout , 1 ) ;
2016-05-14 12:19:18 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
2016-02-16 15:07:25 +01:00
// Image descriptor for the texture array
2017-01-04 21:49:26 +01:00
VkDescriptorImageInfo textureDescriptor =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorImageInfo (
2016-02-16 15:07:25 +01:00
textureArray . sampler ,
textureArray . view ,
2017-01-04 21:49:26 +01:00
textureArray . imageLayout ) ;
2016-02-16 15:07:25 +01:00
2019-04-13 13:38:17 +02:00
std : : vector < VkWriteDescriptorSet > writeDescriptorSets = {
2016-02-16 15:07:25 +01:00
// Binding 0 : Vertex shader uniform buffer
2019-04-13 13:38:17 +02:00
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 0 , & uniformBufferVS . descriptor ) ,
2016-02-16 15:07:25 +01:00
// Binding 1 : Fragment shader cubemap sampler
2019-04-13 13:38:17 +02:00
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , & textureDescriptor )
2016-02-16 15:07:25 +01:00
} ;
vkUpdateDescriptorSets ( device , writeDescriptorSets . size ( ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
}
void preparePipelines ( )
{
2019-04-13 13:38:17 +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-01-10 13:28:56 +01:00
VkPipelineColorBlendAttachmentState blendAttachmentState = vks : : initializers : : pipelineColorBlendAttachmentState ( 0xf , VK_FALSE ) ;
2019-04-13 13:38:17 +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 } ;
VkPipelineDynamicStateCreateInfo dynamicStateCI = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables . data ( ) , dynamicStateEnables . size ( ) , 0 ) ;
// 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 ) } ,
2016-02-16 15:07:25 +01:00
} ;
2019-04-13 13:38:17 +02:00
VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
vertexInputStateCI . vertexBindingDescriptionCount = 1 ;
vertexInputStateCI . pVertexBindingDescriptions = & vertexInputBinding ;
vertexInputStateCI . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertexInputAttributes . size ( ) ) ;
vertexInputStateCI . pVertexAttributeDescriptions = vertexInputAttributes . data ( ) ;
2016-02-16 15:07:25 +01:00
2020-08-09 13:16:35 +02:00
// Instancing pipeline
2016-02-16 15:07:25 +01:00
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2020-05-29 16:08:53 +01:00
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " texturearray/instancing.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " texturearray/instancing.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2016-02-16 15:07:25 +01:00
2019-04-13 13:38:17 +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 ;
pipelineCI . stageCount = shaderStages . size ( ) ;
pipelineCI . pStages = shaderStages . data ( ) ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipeline ) ) ;
2016-02-16 15:07:25 +01:00
}
void prepareUniformBuffers ( )
{
uboVS . instance = new UboInstanceData [ layerCount ] ;
2022-08-08 13:46:30 -04:00
uint32_t uboSize = sizeof ( uboVS . matrices ) + ( MAX_LAYERS * sizeof ( UboInstanceData ) ) ;
2016-02-16 15:07:25 +01:00
// Vertex shader uniform buffer block
2016-12-24 12:48:01 +01:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-04 12:13:10 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2017-01-07 19:37:36 +01:00
& uniformBufferVS ,
2016-12-24 12:48:01 +01:00
uboSize ) ) ;
2016-02-16 15:07:25 +01:00
// Array indices and model matrices are fixed
float offset = - 1.5f ;
2019-04-13 13:38:17 +02:00
float center = ( layerCount * offset ) / 2.0f - ( offset * 0.5f ) ;
for ( uint32_t i = 0 ; i < layerCount ; i + + ) {
2016-02-16 15:07:25 +01:00
// Instance model matrix
2019-04-13 13:38:17 +02:00
uboVS . instance [ i ] . model = glm : : translate ( glm : : mat4 ( 1.0f ) , glm : : vec3 ( i * offset - center , 0.0f , 0.0f ) ) ;
uboVS . instance [ i ] . model = glm : : scale ( uboVS . instance [ i ] . model , glm : : vec3 ( 0.5f ) ) ;
2016-02-16 15:07:25 +01:00
// Instance texture array index
2019-04-13 13:38:17 +02:00
uboVS . instance [ i ] . arrayIndex . x = ( float ) i ;
2016-02-16 15:07:25 +01:00
}
// Update instanced part of the uniform buffer
uint8_t * pData ;
uint32_t dataOffset = sizeof ( uboVS . matrices ) ;
uint32_t dataSize = layerCount * sizeof ( UboInstanceData ) ;
2017-01-07 19:37:36 +01:00
VK_CHECK_RESULT ( vkMapMemory ( device , uniformBufferVS . memory , dataOffset , dataSize , 0 , ( void * * ) & pData ) ) ;
2016-02-16 15:07:25 +01:00
memcpy ( pData , uboVS . instance , dataSize ) ;
2017-01-07 19:37:36 +01:00
vkUnmapMemory ( device , uniformBufferVS . memory ) ;
2016-12-24 12:48:01 +01:00
// Map persistent
2017-01-07 19:37:36 +01:00
VK_CHECK_RESULT ( uniformBufferVS . map ( ) ) ;
2016-02-16 15:07:25 +01:00
2019-04-13 13:38:17 +02:00
updateUniformBuffersCamera ( ) ;
2016-02-16 15:07:25 +01:00
}
2019-04-13 13:38:17 +02:00
void updateUniformBuffersCamera ( )
2016-02-16 15:07:25 +01:00
{
2019-04-13 13:38:17 +02:00
uboVS . matrices . projection = camera . matrices . perspective ;
uboVS . matrices . view = camera . matrices . view ;
2017-01-07 19:37:36 +01:00
memcpy ( uniformBufferVS . mapped , & uboVS . matrices , sizeof ( uboVS . matrices ) ) ;
2016-02-16 15:07:25 +01:00
}
2016-06-04 12:13:10 +02:00
void draw ( )
{
VulkanExampleBase : : prepareFrame ( ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
}
2016-02-16 15:07:25 +01:00
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2020-07-28 20:20:38 +02:00
loadAssets ( ) ;
2019-04-13 13:38:17 +02:00
generateCube ( ) ;
2016-02-16 15:07:25 +01:00
prepareUniformBuffers ( ) ;
setupDescriptorSetLayout ( ) ;
preparePipelines ( ) ;
setupDescriptorPool ( ) ;
setupDescriptorSet ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
2019-04-13 13:38:17 +02:00
if ( camera . updated )
updateUniformBuffersCamera ( ) ;
2016-02-16 15:07:25 +01:00
}
2022-06-13 23:04:53 -04:00
virtual void viewChanged ( )
{
updateUniformBuffersCamera ( ) ;
}
2016-02-16 15:07:25 +01:00
} ;
2022-06-13 23:04:53 -04:00
VULKAN_EXAMPLE_MAIN ( )