2016-02-16 15:07:25 +01:00
/*
* Vulkan Example - Texture loading ( and display ) example ( including mip maps )
*
2017-05-17 21:28:05 +02:00
* Copyright ( C ) 2016 - 2017 by 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 <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# include <vector>
# define GLM_FORCE_RADIANS
2016-03-08 21:52:40 +01:00
# define GLM_FORCE_DEPTH_ZERO_TO_ONE
2016-02-16 15:07:25 +01:00
# include <glm/glm.hpp>
# include <vulkan/vulkan.h>
# include "vulkanexamplebase.h"
2017-02-12 10:16:07 +01:00
# include "VulkanDevice.hpp"
2017-02-12 10:44:51 +01:00
# include "VulkanBuffer.hpp"
2019-08-03 09:46:41 +02:00
# include <ktx.h>
# include <ktxvulkan.h>
2016-02-16 15:07:25 +01:00
# define VERTEX_BUFFER_BIND_ID 0
# define ENABLE_VALIDATION false
// Vertex layout for this example
struct Vertex {
float pos [ 3 ] ;
float uv [ 2 ] ;
2016-05-14 15:54:20 +02:00
float normal [ 3 ] ;
2016-02-16 15:07:25 +01:00
} ;
class VulkanExample : public VulkanExampleBase
{
public :
// Contains all Vulkan objects that are required to store and use a texture
2017-02-09 21:55:35 +01:00
// Note that this repository contains a texture class (VulkanTexture.hpp) that encapsulates texture loading functionality in a class that is used in subsequent demos
2016-02-16 15:07:25 +01:00
struct Texture {
VkSampler sampler ;
VkImage image ;
VkImageLayout imageLayout ;
VkDeviceMemory deviceMemory ;
VkImageView view ;
uint32_t width , height ;
uint32_t mipLevels ;
} texture ;
struct {
VkPipelineVertexInputStateCreateInfo inputState ;
std : : vector < VkVertexInputBindingDescription > bindingDescriptions ;
std : : vector < VkVertexInputAttributeDescription > attributeDescriptions ;
} vertices ;
2017-02-12 10:44:51 +01:00
vks : : Buffer vertexBuffer ;
vks : : Buffer indexBuffer ;
2016-07-24 21:19:28 +02: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 {
glm : : mat4 projection ;
glm : : mat4 model ;
2016-05-14 15:54:20 +02:00
glm : : vec4 viewPos ;
2016-02-16 15:07:25 +01:00
float lodBias = 0.0f ;
} uboVS ;
struct {
VkPipeline solid ;
} pipelines ;
VkPipelineLayout pipelineLayout ;
VkDescriptorSet descriptorSet ;
VkDescriptorSetLayout descriptorSetLayout ;
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
{
zoom = - 2.5f ;
2016-05-14 15:54:20 +02:00
rotation = { 0.0f , 15.0f , 0.0f } ;
2017-11-01 14:22:10 +01:00
title = " Texture loading " ;
settings . overlay = true ;
2016-02-16 15:07:25 +01:00
}
~ VulkanExample ( )
{
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
2016-07-24 21:19:28 +02:00
destroyTextureImage ( texture ) ;
2016-02-16 15:07:25 +01:00
vkDestroyPipeline ( device , pipelines . solid , nullptr ) ;
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
2016-07-24 21:19:28 +02:00
vertexBuffer . destroy ( ) ;
indexBuffer . destroy ( ) ;
uniformBufferVS . destroy ( ) ;
2016-02-16 15:07:25 +01:00
}
2017-05-17 21:28:05 +02:00
// Enable physical device features required for this example
virtual void getEnabledFeatures ( )
{
// Enable anisotropic filtering if supported
if ( deviceFeatures . samplerAnisotropy ) {
enabledFeatures . samplerAnisotropy = VK_TRUE ;
2017-06-01 21:51:43 +02:00
} ;
2017-05-17 21:28:05 +02:00
}
2018-06-30 16:48:27 +02:00
/*
Upload texture image data to the GPU
2016-02-16 15:07:25 +01:00
2018-06-30 16:48:27 +02:00
Vulkan offers two types of image tiling ( memory layout ) :
2016-02-16 15:07:25 +01:00
2018-06-30 16:48:27 +02:00
Linear tiled images :
These are stored as is and can be copied directly to . But due to the linear nature they ' re not a good match for GPUs and format and feature support is very limited .
It ' s not advised to use linear tiled images for anything else than copying from host to GPU if buffer copies are not an option .
Linear tiling is thus only implemented for learning purposes , one should always prefer optimal tiled image .
Optimal tiled images :
These are stored in an implementation specific layout matching the capability of the hardware . They usually support more formats and features and are much faster .
Optimal tiled images are stored on the device and not accessible by the host . So they can ' t be written directly to ( like liner tiled images ) and always require
some sort of data copy , either from a buffer or a linear tiled image .
In Short : Always use optimal tiled images for rendering .
*/
2017-05-17 21:28:05 +02:00
void loadTexture ( )
2016-02-16 15:07:25 +01:00
{
2017-05-17 21:28:05 +02:00
// We use the Khronos texture format (https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/)
2017-06-22 14:53:49 -04:00
std : : string filename = getAssetPath ( ) + " textures/metalplate01_rgba.ktx " ;
2017-05-17 21:28:05 +02:00
// Texture data contains 4 channels (RGBA) with unnormalized 8-bit values, this is the most commonly supported format
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM ;
2019-08-03 09:46:41 +02:00
ktxResult result ;
ktxTexture * ktxTexture ;
2016-03-21 22:41:27 +01:00
# if defined(__ANDROID__)
// Textures are stored inside the apk on Android (compressed)
// So they need to be loaded via the asset manager
2017-05-17 21:28:05 +02:00
AAsset * asset = AAssetManager_open ( androidApp - > activity - > assetManager , filename . c_str ( ) , AASSET_MODE_STREAMING ) ;
2019-08-03 09:46:41 +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-21 22:41:27 +01:00
size_t size = AAsset_getLength ( asset ) ;
assert ( size > 0 ) ;
2019-08-03 11:38:02 +02:00
ktx_uint8_t * textureData = new ktx_uint8_t [ size ] ;
2016-03-21 22:41:27 +01:00
AAsset_read ( asset , textureData , size ) ;
AAsset_close ( asset ) ;
2019-08-03 11:38:02 +02:00
result = ktxTexture_CreateFromMemory ( textureData , size , KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT , & ktxTexture ) ;
delete [ ] textureData ;
2019-08-03 09:46:41 +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 ) ;
# endif
assert ( result = = KTX_SUCCESS ) ;
2016-02-16 15:07:25 +01:00
2019-08-03 09:46:41 +02:00
// Get properties required for using and upload texture data from the ktx texture object
texture . width = ktxTexture - > baseWidth ;
texture . height = ktxTexture - > baseHeight ;
texture . mipLevels = ktxTexture - > numLevels ;
ktx_uint8_t * ktxTextureData = ktxTexture_GetData ( ktxTexture ) ;
ktx_size_t ktxTextureSize = ktxTexture_GetSize ( ktxTexture ) ;
2016-02-16 15:07:25 +01:00
2018-06-30 16:48:27 +02:00
// We prefer using staging to copy the texture data to a device local optimal image
2019-08-03 11:38:02 +02:00
VkBool32 useStaging = true ;
2016-02-16 15:07:25 +01:00
// Only use linear tiling if forced
2018-06-30 16:48:27 +02:00
bool forceLinearTiling = false ;
if ( forceLinearTiling ) {
2016-02-16 15:07:25 +01:00
// Don't use linear if format is not supported for (linear) shader sampling
2018-06-30 16:48:27 +02:00
// Get device properites for the requested texture format
VkFormatProperties formatProperties ;
vkGetPhysicalDeviceFormatProperties ( physicalDevice , format , & formatProperties ) ;
2016-02-16 15:07:25 +01:00
useStaging = ! ( formatProperties . linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT ) ;
}
2017-02-12 11:12:42 +01:00
VkMemoryAllocateInfo memAllocInfo = vks : : initializers : : memoryAllocateInfo ( ) ;
2016-04-29 21:49:37 +02:00
VkMemoryRequirements memReqs = { } ;
2016-02-16 15:07:25 +01:00
2018-06-30 16:48:27 +02:00
if ( useStaging ) {
// Copy data to an optimal tiled image
// This loads the texture data into a host local buffer that is copied to the optimal tiled image on the device
2016-04-29 21:49:37 +02:00
// Create a host-visible staging buffer that contains the raw image data
2018-06-30 16:48:27 +02:00
// This buffer will be the data source for copying texture data to the optimal tiled image on the device
2016-04-29 21:49:37 +02:00
VkBuffer stagingBuffer ;
VkDeviceMemory stagingMemory ;
2017-02-12 11:12:42 +01:00
VkBufferCreateInfo bufferCreateInfo = vks : : initializers : : bufferCreateInfo ( ) ;
2019-08-03 09:46:41 +02:00
bufferCreateInfo . size = ktxTextureSize ;
2016-04-29 21:49:37 +02:00
// This buffer is used as a transfer source for the buffer copy
bufferCreateInfo . usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT ;
2018-06-30 16:48:27 +02:00
bufferCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreateBuffer ( device , & bufferCreateInfo , nullptr , & stagingBuffer ) ) ;
2016-04-29 21:49:37 +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 13:50:10 +02:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & stagingMemory ) ) ;
VK_CHECK_RESULT ( vkBindBufferMemory ( device , stagingBuffer , stagingMemory , 0 ) ) ;
2016-04-29 21:49:37 +02:00
2018-06-30 16:48:27 +02:00
// Copy texture data into host local staging buffer
2016-04-29 21:49:37 +02:00
uint8_t * data ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkMapMemory ( device , stagingMemory , 0 , memReqs . size , 0 , ( void * * ) & data ) ) ;
2019-08-03 09:46:41 +02:00
memcpy ( data , ktxTextureData , ktxTextureSize ) ;
2016-04-29 21:49:37 +02:00
vkUnmapMemory ( device , stagingMemory ) ;
// Setup buffer copy regions for each mip level
std : : vector < VkBufferImageCopy > bufferCopyRegions ;
uint32_t offset = 0 ;
2018-06-30 16:48:27 +02:00
for ( uint32_t i = 0 ; i < texture . mipLevels ; i + + ) {
2019-08-03 10:00:29 +02:00
// Calculate offset into staging buffer for the current mip level
2019-08-03 09:46:41 +02:00
ktx_size_t offset ;
assert ( ktxTexture_GetImageOffset ( ktxTexture , i , 0 , 0 , & offset ) = = KTX_SUCCESS ) ;
2019-08-03 09:55:46 +02:00
// Setup a buffer image copy structure for the current mip level
2016-04-29 21:49:37 +02:00
VkBufferImageCopy bufferCopyRegion = { } ;
bufferCopyRegion . imageSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
bufferCopyRegion . imageSubresource . mipLevel = i ;
bufferCopyRegion . imageSubresource . baseArrayLayer = 0 ;
bufferCopyRegion . imageSubresource . layerCount = 1 ;
2019-08-03 09:46:41 +02:00
bufferCopyRegion . imageExtent . width = ktxTexture - > baseWidth > > i ;
bufferCopyRegion . imageExtent . height = ktxTexture - > baseHeight > > i ;
2016-04-29 21:49:37 +02:00
bufferCopyRegion . imageExtent . depth = 1 ;
bufferCopyRegion . bufferOffset = offset ;
bufferCopyRegions . push_back ( bufferCopyRegion ) ;
2016-02-16 15:07:25 +01:00
}
2018-06-30 16:48:27 +02:00
// Create optimal tiled target image on the device
2017-02-12 11:12:42 +01:00
VkImageCreateInfo imageCreateInfo = vks : : initializers : : imageCreateInfo ( ) ;
2016-04-29 21:49:37 +02:00
imageCreateInfo . imageType = VK_IMAGE_TYPE_2D ;
imageCreateInfo . format = format ;
2016-02-16 15:07:25 +01:00
imageCreateInfo . mipLevels = texture . mipLevels ;
2016-04-29 21:49:37 +02:00
imageCreateInfo . arrayLayers = 1 ;
imageCreateInfo . samples = VK_SAMPLE_COUNT_1_BIT ;
imageCreateInfo . tiling = VK_IMAGE_TILING_OPTIMAL ;
imageCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
2016-06-21 20:36:54 +02:00
// Set initial layout of the image to undefined
imageCreateInfo . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
2016-02-16 15:07:25 +01:00
imageCreateInfo . extent = { texture . width , texture . height , 1 } ;
2016-04-29 21:49:37 +02:00
imageCreateInfo . usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCreateInfo , nullptr , & texture . image ) ) ;
2016-02-16 15:07:25 +01:00
vkGetImageMemoryRequirements ( device , texture . 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 13:50:10 +02:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & texture . deviceMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , texture . image , texture . deviceMemory , 0 ) ) ;
2016-02-16 15:07:25 +01:00
2016-04-29 21:49:37 +02:00
VkCommandBuffer copyCmd = VulkanExampleBase : : createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
2018-06-30 16:48:27 +02:00
// Image memory barriers for the texture image
2016-06-21 20:36:54 +02:00
2018-06-30 16:48:27 +02:00
// The sub resource range describes the regions of the image that will be transitioned using the memory barriers below
2016-06-21 20:36:54 +02:00
VkImageSubresourceRange subresourceRange = { } ;
// Image only contains color data
subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
// Start at first mip level
subresourceRange . baseMipLevel = 0 ;
// We will transition on all mip levels
subresourceRange . levelCount = texture . mipLevels ;
// The 2D texture only has one layer
subresourceRange . layerCount = 1 ;
2018-06-30 16:48:27 +02:00
// Transition the texture image layout to transfer target, so we can safely copy our buffer data to it.
VkImageMemoryBarrier imageMemoryBarrier = vks : : initializers : : imageMemoryBarrier ( ) ; ;
imageMemoryBarrier . image = texture . image ;
imageMemoryBarrier . subresourceRange = subresourceRange ;
imageMemoryBarrier . srcAccessMask = 0 ;
imageMemoryBarrier . dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT ;
imageMemoryBarrier . oldLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
imageMemoryBarrier . newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ;
// Insert a memory dependency at the proper pipeline stages that will execute the image layout transition
// Source pipeline stage is host write/read exection (VK_PIPELINE_STAGE_HOST_BIT)
// Destination pipeline stage is copy command exection (VK_PIPELINE_STAGE_TRANSFER_BIT)
vkCmdPipelineBarrier (
2016-04-29 21:49:37 +02:00
copyCmd ,
2018-06-30 16:48:27 +02:00
VK_PIPELINE_STAGE_HOST_BIT ,
VK_PIPELINE_STAGE_TRANSFER_BIT ,
0 ,
0 , nullptr ,
0 , nullptr ,
1 , & imageMemoryBarrier ) ;
2016-02-16 15:07:25 +01:00
2016-04-29 21:49:37 +02:00
// Copy mip levels from staging buffer
vkCmdCopyBufferToImage (
copyCmd ,
stagingBuffer ,
texture . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
2016-07-24 21:19:28 +02:00
static_cast < uint32_t > ( bufferCopyRegions . size ( ) ) ,
2016-06-21 20:36:54 +02:00
bufferCopyRegions . data ( ) ) ;
2016-02-16 15:07:25 +01:00
2018-06-30 16:48:27 +02:00
// Once the data has been uploaded we transfer to the texture image to the shader read layout, so it can be sampled from
imageMemoryBarrier . srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT ;
imageMemoryBarrier . dstAccessMask = VK_ACCESS_SHADER_READ_BIT ;
imageMemoryBarrier . oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ;
imageMemoryBarrier . newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
// Insert a memory dependency at the proper pipeline stages that will execute the image layout transition
// Source pipeline stage stage is copy command exection (VK_PIPELINE_STAGE_TRANSFER_BIT)
// Destination pipeline stage fragment shader access (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
vkCmdPipelineBarrier (
2016-04-29 21:49:37 +02:00
copyCmd ,
2018-06-30 16:48:27 +02:00
VK_PIPELINE_STAGE_TRANSFER_BIT ,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT ,
0 ,
0 , nullptr ,
0 , nullptr ,
1 , & imageMemoryBarrier ) ;
// Store current layout for later reuse
texture . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
2016-03-13 13:03:04 +01:00
2016-04-29 21:49:37 +02:00
VulkanExampleBase : : flushCommandBuffer ( copyCmd , queue , true ) ;
2016-02-16 15:07:25 +01:00
2016-04-29 21:49:37 +02:00
// Clean up staging resources
vkFreeMemory ( device , stagingMemory , nullptr ) ;
vkDestroyBuffer ( device , stagingBuffer , nullptr ) ;
2018-06-30 16:48:27 +02:00
} else {
// Copy data to a linear tiled image
2016-02-16 15:07:25 +01:00
VkImage mappableImage ;
VkDeviceMemory mappableMemory ;
// Load mip map level 0 to linear tiling image
2017-02-12 11:12:42 +01:00
VkImageCreateInfo imageCreateInfo = vks : : initializers : : imageCreateInfo ( ) ;
2016-04-29 21:49:37 +02:00
imageCreateInfo . imageType = VK_IMAGE_TYPE_2D ;
imageCreateInfo . format = format ;
imageCreateInfo . mipLevels = 1 ;
imageCreateInfo . arrayLayers = 1 ;
imageCreateInfo . samples = VK_SAMPLE_COUNT_1_BIT ;
imageCreateInfo . tiling = VK_IMAGE_TILING_LINEAR ;
imageCreateInfo . usage = VK_IMAGE_USAGE_SAMPLED_BIT ;
imageCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
imageCreateInfo . initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED ;
imageCreateInfo . extent = { texture . width , texture . height , 1 } ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCreateInfo , nullptr , & mappableImage ) ) ;
2016-02-16 15:07:25 +01:00
2018-06-30 16:48:27 +02:00
// Get memory requirements for this image like size and alignment
2016-02-16 15:07:25 +01:00
vkGetImageMemoryRequirements ( device , mappableImage , & memReqs ) ;
// Set memory allocation size to required memory size
memAllocInfo . allocationSize = memReqs . size ;
// Get memory type that can be mapped to host memory
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 13:50:10 +02:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & mappableMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , mappableImage , mappableMemory , 0 ) ) ;
2016-02-16 15:07:25 +01:00
// Map image memory
2018-06-30 16:48:27 +02:00
void * data ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkMapMemory ( device , mappableMemory , 0 , memReqs . size , 0 , & data ) ) ;
2018-06-30 16:48:27 +02:00
// Copy image data of the first mip level into memory
2019-08-03 09:46:41 +02:00
memcpy ( data , ktxTextureData , memReqs . size ) ;
2016-02-16 15:07:25 +01:00
vkUnmapMemory ( device , mappableMemory ) ;
2018-06-30 16:48:27 +02:00
// Linear tiled images don't need to be staged and can be directly used as textures
2016-02-16 15:07:25 +01:00
texture . image = mappableImage ;
texture . deviceMemory = mappableMemory ;
texture . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
2016-04-29 21:49:37 +02:00
// Setup image memory barrier transfer image to shader read layout
2018-06-30 16:48:27 +02:00
VkCommandBuffer copyCmd = VulkanExampleBase : : createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
2016-06-21 20:36:54 +02:00
// The sub resource range describes the regions of the image we will be transition
VkImageSubresourceRange subresourceRange = { } ;
subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
subresourceRange . baseMipLevel = 0 ;
subresourceRange . levelCount = 1 ;
subresourceRange . layerCount = 1 ;
2018-06-30 16:48:27 +02:00
// Transition the texture image layout to shader read, so it can be sampled from
VkImageMemoryBarrier imageMemoryBarrier = vks : : initializers : : imageMemoryBarrier ( ) ; ;
imageMemoryBarrier . image = texture . image ;
imageMemoryBarrier . subresourceRange = subresourceRange ;
imageMemoryBarrier . srcAccessMask = VK_ACCESS_HOST_WRITE_BIT ;
imageMemoryBarrier . dstAccessMask = VK_ACCESS_SHADER_READ_BIT ;
imageMemoryBarrier . oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED ;
imageMemoryBarrier . newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
// Insert a memory dependency at the proper pipeline stages that will execute the image layout transition
// Source pipeline stage is host write/read exection (VK_PIPELINE_STAGE_HOST_BIT)
// Destination pipeline stage fragment shader access (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
vkCmdPipelineBarrier (
copyCmd ,
VK_PIPELINE_STAGE_HOST_BIT ,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT ,
0 ,
0 , nullptr ,
0 , nullptr ,
1 , & imageMemoryBarrier ) ;
2016-04-29 21:49:37 +02:00
VulkanExampleBase : : flushCommandBuffer ( copyCmd , queue , true ) ;
2016-02-16 15:07:25 +01:00
}
2019-08-03 09:46:41 +02:00
ktxTexture_Destroy ( ktxTexture ) ;
2017-05-17 21:28:05 +02:00
// Create a texture sampler
2016-02-16 15:07:25 +01:00
// In Vulkan textures are accessed by samplers
2017-05-17 21:28:05 +02:00
// This separates all the sampling information from the texture data. This means you could have multiple sampler objects for the same texture with different settings
// Note: Similar to the samplers available with OpenGL 3.3
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_REPEAT ;
sampler . addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
sampler . addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
sampler . mipLodBias = 0.0f ;
sampler . compareOp = VK_COMPARE_OP_NEVER ;
sampler . minLod = 0.0f ;
2016-07-24 21:19:28 +02:00
// Set max level-of-detail to mip level count of the texture
2016-02-16 15:07:25 +01:00
sampler . maxLod = ( useStaging ) ? ( float ) texture . mipLevels : 0.0f ;
// Enable anisotropic filtering
2016-07-24 21:19:28 +02:00
// This feature is optional, so we must check if it's supported on the device
2018-06-30 16:48:27 +02:00
if ( vulkanDevice - > features . samplerAnisotropy ) {
2016-07-24 21:19:28 +02:00
// Use max. level of anisotropy for this example
sampler . maxAnisotropy = vulkanDevice - > properties . limits . maxSamplerAnisotropy ;
sampler . anisotropyEnable = VK_TRUE ;
2018-06-30 16:48:27 +02:00
} else {
2016-07-24 21:19:28 +02:00
// The device does not support anisotropic filtering
sampler . maxAnisotropy = 1.0 ;
sampler . anisotropyEnable = VK_FALSE ;
}
2016-02-16 15:07:25 +01:00
sampler . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreateSampler ( device , & sampler , nullptr , & texture . sampler ) ) ;
2016-02-16 15:07:25 +01:00
// Create image view
// Textures are not directly accessed by the shaders and
// are abstracted by image views containing additional
// information and sub resource ranges
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 ;
view . format = format ;
view . components = { VK_COMPONENT_SWIZZLE_R , VK_COMPONENT_SWIZZLE_G , VK_COMPONENT_SWIZZLE_B , VK_COMPONENT_SWIZZLE_A } ;
2016-07-24 21:19:28 +02:00
// The subresource range describes the set of mip levels (and array layers) that can be accessed through this image view
// It's possible to create multiple image views for a single image referring to different (and/or overlapping) ranges of the image
2016-02-16 15:07:25 +01:00
view . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
view . subresourceRange . baseMipLevel = 0 ;
view . subresourceRange . baseArrayLayer = 0 ;
view . subresourceRange . layerCount = 1 ;
// Linear tiling usually won't support mip maps
// Only set mip map count if optimal tiling is used
view . subresourceRange . levelCount = ( useStaging ) ? texture . mipLevels : 1 ;
2017-01-04 21:49:26 +01:00
// The view will be based on the texture's image
2016-02-16 15:07:25 +01:00
view . image = texture . image ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreateImageView ( device , & view , nullptr , & texture . view ) ) ;
2016-02-16 15:07:25 +01:00
}
2017-05-17 21:28:05 +02:00
// Free all Vulkan resources used by a texture object
2016-02-16 15:07:25 +01:00
void destroyTextureImage ( Texture texture )
{
2016-07-24 21:19:28 +02:00
vkDestroyImageView ( device , texture . view , nullptr ) ;
2016-02-16 15:07:25 +01:00
vkDestroyImage ( device , texture . image , nullptr ) ;
2016-07-24 21:19:28 +02:00
vkDestroySampler ( device , texture . sampler , nullptr ) ;
2016-02-16 15:07:25 +01:00
vkFreeMemory ( device , texture . deviceMemory , nullptr ) ;
}
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 13:50:10 +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 ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelines . solid ) ;
VkDeviceSize offsets [ 1 ] = { 0 } ;
2016-07-24 21:19:28 +02:00
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , VERTEX_BUFFER_BIND_ID , 1 , & vertexBuffer . buffer , offsets ) ;
vkCmdBindIndexBuffer ( drawCmdBuffers [ i ] , indexBuffer . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
2016-02-16 15:07:25 +01:00
2016-07-24 21:19:28 +02:00
vkCmdDrawIndexed ( drawCmdBuffers [ i ] , indexCount , 1 , 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 13:50:10 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2016-02-16 15:07:25 +01:00
}
}
void draw ( )
{
2016-05-15 20:11:28 +02:00
VulkanExampleBase : : prepareFrame ( ) ;
2016-03-06 20:15:05 +01:00
// Command buffer to be sumitted to the queue
2016-02-16 15:07:25 +01:00
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
2016-03-06 20:15:05 +01:00
// Submit to queue
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-15 20:11:28 +02:00
VulkanExampleBase : : submitFrame ( ) ;
2016-02-16 15:07:25 +01:00
}
void generateQuad ( )
{
2016-07-24 21:19:28 +02:00
// Setup vertices for a single uv-mapped quad made from two triangles
std : : vector < Vertex > vertices =
2016-02-16 15:07:25 +01:00
{
2016-07-24 21:19:28 +02:00
{ { 1.0f , 1.0f , 0.0f } , { 1.0f , 1.0f } , { 0.0f , 0.0f , 1.0f } } ,
{ { - 1.0f , 1.0f , 0.0f } , { 0.0f , 1.0f } , { 0.0f , 0.0f , 1.0f } } ,
{ { - 1.0f , - 1.0f , 0.0f } , { 0.0f , 0.0f } , { 0.0f , 0.0f , 1.0f } } ,
{ { 1.0f , - 1.0f , 0.0f } , { 1.0f , 0.0f } , { 0.0f , 0.0f , 1.0f } }
2016-02-16 15:07:25 +01:00
} ;
// Setup indices
2016-07-24 21:19:28 +02:00
std : : vector < uint32_t > indices = { 0 , 1 , 2 , 2 , 3 , 0 } ;
indexCount = static_cast < uint32_t > ( indices . size ( ) ) ;
2016-02-16 15:07:25 +01:00
2016-07-24 21:19:28 +02:00
// Create buffers
// For the sake of simplicity we won't stage the vertex data to the gpu memory
// Vertex buffer
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 ( ) ) ) ;
// Index buffer
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_INDEX_BUFFER_BIT ,
2016-07-24 21:19:28 +02: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 setupVertexDescriptions ( )
{
// Binding description
vertices . bindingDescriptions . resize ( 1 ) ;
vertices . bindingDescriptions [ 0 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputBindingDescription (
2016-02-16 15:07:25 +01:00
VERTEX_BUFFER_BIND_ID ,
sizeof ( Vertex ) ,
VK_VERTEX_INPUT_RATE_VERTEX ) ;
// Attribute descriptions
// Describes memory layout and shader positions
2016-05-14 15:54:20 +02:00
vertices . attributeDescriptions . resize ( 3 ) ;
2016-02-16 15:07:25 +01:00
// Location 0 : Position
vertices . attributeDescriptions [ 0 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-02-16 15:07:25 +01:00
VERTEX_BUFFER_BIND_ID ,
0 ,
VK_FORMAT_R32G32B32_SFLOAT ,
2016-07-24 21:19:28 +02:00
offsetof ( Vertex , pos ) ) ;
2016-02-16 15:07:25 +01:00
// Location 1 : Texture coordinates
vertices . attributeDescriptions [ 1 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-02-16 15:07:25 +01:00
VERTEX_BUFFER_BIND_ID ,
1 ,
VK_FORMAT_R32G32_SFLOAT ,
2016-07-24 21:19:28 +02:00
offsetof ( Vertex , uv ) ) ;
2016-05-14 15:54:20 +02:00
// Location 1 : Vertex normal
vertices . attributeDescriptions [ 2 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-05-14 15:54:20 +02:00
VERTEX_BUFFER_BIND_ID ,
2 ,
VK_FORMAT_R32G32B32_SFLOAT ,
2016-07-24 21:19:28 +02:00
offsetof ( Vertex , normal ) ) ;
2016-02-16 15:07:25 +01:00
2017-02-12 11:12:42 +01:00
vertices . inputState = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
2016-07-24 21:19:28 +02:00
vertices . inputState . vertexBindingDescriptionCount = static_cast < uint32_t > ( vertices . bindingDescriptions . size ( ) ) ;
2016-02-16 15:07:25 +01:00
vertices . inputState . pVertexBindingDescriptions = vertices . bindingDescriptions . data ( ) ;
2016-07-24 21:19:28 +02:00
vertices . inputState . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertices . attributeDescriptions . size ( ) ) ;
2016-02-16 15:07:25 +01:00
vertices . inputState . pVertexAttributeDescriptions = vertices . attributeDescriptions . data ( ) ;
}
void setupDescriptorPool ( )
{
// Example uses one ubo and one image sampler
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
} ;
VkDescriptorPoolCreateInfo descriptorPoolInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolCreateInfo (
2016-07-24 21:19:28 +02:00
static_cast < uint32_t > ( poolSizes . size ( ) ) ,
2016-02-16 15:07:25 +01:00
poolSizes . data ( ) ,
2 ) ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSetLayout ( )
{
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings =
{
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2016-02-16 15:07:25 +01:00
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
VK_SHADER_STAGE_VERTEX_BIT ,
0 ) ,
// Binding 1 : Fragment shader image sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2016-02-16 15:07:25 +01:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
VK_SHADER_STAGE_FRAGMENT_BIT ,
1 )
} ;
VkDescriptorSetLayoutCreateInfo descriptorLayout =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutCreateInfo (
2016-02-16 15:07:25 +01:00
setLayoutBindings . data ( ) ,
2016-07-24 21:19:28 +02:00
static_cast < uint32_t > ( setLayoutBindings . size ( ) ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & descriptorSetLayout ) ) ;
2016-02-16 15:07:25 +01:00
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineLayoutCreateInfo (
2016-02-16 15:07:25 +01:00
& descriptorSetLayout ,
1 ) ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & pipelineLayout ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSet ( )
{
VkDescriptorSetAllocateInfo allocInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetAllocateInfo (
2016-02-16 15:07:25 +01:00
descriptorPool ,
& descriptorSetLayout ,
1 ) ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
2016-02-16 15:07:25 +01:00
2017-01-04 21:49:26 +01:00
// Setup a descriptor image info for the current texture to be used as a combined image sampler
VkDescriptorImageInfo textureDescriptor ;
textureDescriptor . imageView = texture . view ; // The image's view (images are never directly accessed by the shader, but rather through views defining subresources)
2017-05-17 21:28:05 +02:00
textureDescriptor . sampler = texture . sampler ; // The sampler (Telling the pipeline how to sample the texture, including repeat, border, etc.)
textureDescriptor . imageLayout = texture . imageLayout ; // The current layout of the image (Note: Should always fit the actual use, e.g. shader read)
2017-01-04 21:49:26 +01:00
2016-02-16 15:07:25 +01:00
std : : vector < VkWriteDescriptorSet > writeDescriptorSets =
{
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-02-16 15:07:25 +01:00
descriptorSet ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-07-24 21:19:28 +02:00
& uniformBufferVS . descriptor ) ,
2016-02-16 15:07:25 +01:00
// Binding 1 : Fragment shader texture sampler
2017-01-04 21:49:26 +01:00
// Fragment shader: layout (binding = 1) uniform sampler2D samplerColor;
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2017-01-04 21:49:26 +01:00
descriptorSet ,
2017-05-17 21:28:05 +02:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , // The descriptor set will use a combined image sampler (sampler and image could be split)
1 , // Shader binding point 1
2017-01-04 21:49:26 +01:00
& textureDescriptor ) // Pointer to the descriptor image for our texture
2016-02-16 15:07:25 +01:00
} ;
2016-07-24 21:19:28 +02:00
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
2016-02-16 15:07:25 +01:00
}
void preparePipelines ( )
{
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineInputAssemblyStateCreateInfo (
2016-02-16 15:07:25 +01:00
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ,
0 ,
VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineRasterizationStateCreateInfo (
2016-02-16 15:07:25 +01:00
VK_POLYGON_MODE_FILL ,
VK_CULL_MODE_NONE ,
VK_FRONT_FACE_COUNTER_CLOCKWISE ,
0 ) ;
VkPipelineColorBlendAttachmentState blendAttachmentState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineColorBlendAttachmentState (
2016-02-16 15:07:25 +01:00
0xf ,
VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineColorBlendStateCreateInfo (
2016-02-16 15:07:25 +01:00
1 ,
& blendAttachmentState ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineDepthStencilStateCreateInfo (
2016-02-16 15:07:25 +01:00
VK_TRUE ,
VK_TRUE ,
VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 , 0 ) ;
2016-02-16 15:07:25 +01:00
VkPipelineMultisampleStateCreateInfo multisampleState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineMultisampleStateCreateInfo (
2016-02-16 15:07:25 +01:00
VK_SAMPLE_COUNT_1_BIT ,
0 ) ;
std : : vector < VkDynamicState > dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT ,
VK_DYNAMIC_STATE_SCISSOR
} ;
VkPipelineDynamicStateCreateInfo dynamicState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineDynamicStateCreateInfo (
2016-02-16 15:07:25 +01:00
dynamicStateEnables . data ( ) ,
2016-07-24 21:19:28 +02:00
static_cast < uint32_t > ( dynamicStateEnables . size ( ) ) ,
2016-02-16 15:07:25 +01:00
0 ) ;
// Load shaders
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2016-05-14 15:54:20 +02:00
shaderStages [ 0 ] = loadShader ( getAssetPath ( ) + " shaders/texture/texture.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getAssetPath ( ) + " shaders/texture/texture.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2016-02-16 15:07:25 +01:00
VkGraphicsPipelineCreateInfo pipelineCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineCreateInfo (
2016-02-16 15:07:25 +01:00
pipelineLayout ,
renderPass ,
0 ) ;
pipelineCreateInfo . pVertexInputState = & vertices . inputState ;
pipelineCreateInfo . pInputAssemblyState = & inputAssemblyState ;
pipelineCreateInfo . pRasterizationState = & rasterizationState ;
pipelineCreateInfo . pColorBlendState = & colorBlendState ;
pipelineCreateInfo . pMultisampleState = & multisampleState ;
pipelineCreateInfo . pViewportState = & viewportState ;
pipelineCreateInfo . pDepthStencilState = & depthStencilState ;
pipelineCreateInfo . pDynamicState = & dynamicState ;
2016-07-24 21:19:28 +02:00
pipelineCreateInfo . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
2016-02-16 15:07:25 +01:00
pipelineCreateInfo . pStages = shaderStages . data ( ) ;
2016-05-14 13:50:10 +02:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & pipelines . solid ) ) ;
2016-02-16 15:07:25 +01:00
}
// Prepare and initialize uniform buffer containing shader uniforms
void prepareUniformBuffers ( )
{
// Vertex shader uniform buffer block
2016-07-24 21:19:28 +02:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-07-24 21:19:28 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& uniformBufferVS ,
2016-02-16 15:07:25 +01:00
sizeof ( uboVS ) ,
2016-07-24 21:19:28 +02:00
& uboVS ) ) ;
2016-02-16 15:07:25 +01:00
updateUniformBuffers ( ) ;
}
void updateUniformBuffers ( )
{
// Vertex shader
2016-03-08 20:59:25 +01:00
uboVS . projection = glm : : perspective ( glm : : radians ( 60.0f ) , ( float ) width / ( float ) height , 0.001f , 256.0f ) ;
2017-09-24 18:17:07 +02:00
glm : : mat4 viewMatrix = glm : : translate ( glm : : mat4 ( 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , zoom ) ) ;
2016-02-16 15:07:25 +01:00
2017-09-24 18:17:07 +02:00
uboVS . model = viewMatrix * glm : : translate ( glm : : mat4 ( 1.0f ) , cameraPos ) ;
2016-03-08 20:59:25 +01:00
uboVS . model = glm : : rotate ( uboVS . model , glm : : radians ( rotation . x ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ;
uboVS . model = glm : : rotate ( uboVS . model , glm : : radians ( rotation . y ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) ) ;
uboVS . model = glm : : rotate ( uboVS . model , glm : : radians ( rotation . z ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 15:54:20 +02:00
uboVS . viewPos = glm : : vec4 ( 0.0f , 0.0f , - zoom , 0.0f ) ;
2016-07-24 21:19:28 +02:00
VK_CHECK_RESULT ( uniformBufferVS . map ( ) ) ;
memcpy ( uniformBufferVS . mapped , & uboVS , sizeof ( uboVS ) ) ;
uniformBufferVS . unmap ( ) ;
2016-02-16 15:07:25 +01:00
}
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2017-05-17 21:28:05 +02:00
loadTexture ( ) ;
2016-02-16 15:07:25 +01:00
generateQuad ( ) ;
setupVertexDescriptions ( ) ;
prepareUniformBuffers ( ) ;
setupDescriptorSetLayout ( ) ;
preparePipelines ( ) ;
setupDescriptorPool ( ) ;
setupDescriptorSet ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
}
virtual void viewChanged ( )
{
updateUniformBuffers ( ) ;
}
2017-11-01 14:22:10 +01:00
virtual void OnUpdateUIOverlay ( vks : : UIOverlay * overlay )
2016-02-16 15:07:25 +01:00
{
2017-11-01 14:22:10 +01:00
if ( overlay - > header ( " Settings " ) ) {
if ( overlay - > sliderFloat ( " LOD bias " , & uboVS . lodBias , 0.0f , ( float ) texture . mipLevels ) ) {
updateUniformBuffers ( ) ;
}
2017-05-17 21:28:05 +02:00
}
2016-02-16 15:07:25 +01:00
}
} ;
2016-08-11 13:15:49 +02:00
VULKAN_EXAMPLE_MAIN ( )