2016-02-16 15:07:25 +01:00
/*
* Vulkan Example - Attraction based compute shader particle system
*
2016-05-14 23:09:17 +02:00
* Updated compute shader by Lukas Bergdoll ( https : //github.com/Voultapher)
*
2021-11-09 21:44:43 +01:00
* Copyright ( C ) 2016 - 2021 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 "vulkanexamplebase.h"
2016-04-21 22:02:22 +02:00
# if defined(__ANDROID__)
// Lower particle count on Android for performance reasons
2016-08-16 23:06:27 +02:00
# define PARTICLE_COUNT 128 * 1024
2016-04-21 22:02:22 +02:00
# else
2016-05-14 23:09:17 +02:00
# define PARTICLE_COUNT 256 * 1024
2016-04-21 22:02:22 +02:00
# endif
2016-02-16 15:07:25 +01:00
class VulkanExample : public VulkanExampleBase
{
public :
2016-05-15 09:14:10 +02:00
float timer = 0.0f ;
2016-04-21 11:21:48 +02:00
float animStart = 20.0f ;
2020-02-22 14:38:53 +01:00
bool attachToCursor = false ;
2016-02-16 15:07:25 +01:00
2016-05-14 23:09:17 +02:00
struct {
2017-02-09 21:55:35 +01:00
vks : : Texture2D particle ;
vks : : Texture2D gradient ;
2016-05-14 23:09:17 +02:00
} textures ;
2016-02-16 15:07:25 +01:00
struct {
VkPipelineVertexInputStateCreateInfo inputState ;
std : : vector < VkVertexInputBindingDescription > bindingDescriptions ;
std : : vector < VkVertexInputAttributeDescription > attributeDescriptions ;
} vertices ;
2016-08-16 23:06:27 +02:00
// Resources for the graphics part of the example
2016-02-16 15:07:25 +01:00
struct {
2020-02-22 14:38:53 +01:00
uint32_t queueFamilyIndex ; // Used to check if compute and graphics queue families differ and require additional barriers
2016-08-16 23:06:27 +02:00
VkDescriptorSetLayout descriptorSetLayout ; // Particle system rendering shader binding layout
VkDescriptorSet descriptorSet ; // Particle system rendering shader bindings
VkPipelineLayout pipelineLayout ; // Layout of the graphics pipeline
VkPipeline pipeline ; // Particle rendering pipeline
2020-02-22 14:38:53 +01:00
VkSemaphore semaphore ; // Execution dependency between compute & graphic submission
2016-08-16 23:06:27 +02:00
} graphics ;
2016-02-16 15:07:25 +01:00
2016-08-16 23:06:27 +02:00
// Resources for the compute part of the example
2016-02-16 15:07:25 +01:00
struct {
2020-02-22 14:38:53 +01:00
uint32_t queueFamilyIndex ; // Used to check if compute and graphics queue families differ and require additional barriers
2017-02-12 10:44:51 +01:00
vks : : Buffer storageBuffer ; // (Shader) storage buffer object containing the particles
vks : : Buffer uniformBuffer ; // Uniform buffer object containing particle system parameters
2016-08-16 23:06:27 +02:00
VkQueue queue ; // Separate queue for compute commands (queue family may differ from the one used for graphics)
VkCommandPool commandPool ; // Use a separate command pool (queue family may differ from the one used for graphics)
VkCommandBuffer commandBuffer ; // Command buffer storing the dispatch commands and barriers
2020-02-22 14:38:53 +01:00
VkSemaphore semaphore ; // Execution dependency between compute & graphic submission
2016-08-16 23:06:27 +02:00
VkDescriptorSetLayout descriptorSetLayout ; // Compute shader binding layout
VkDescriptorSet descriptorSet ; // Compute shader bindings
VkPipelineLayout pipelineLayout ; // Layout of the compute pipeline
VkPipeline pipeline ; // Compute pipeline for updating particle positions
2016-08-17 20:32:05 +02:00
struct computeUBO { // Compute shader uniform block object
float deltaT ; // Frame delta time
float destX ; // x position of the attractor
float destY ; // y position of the attractor
int32_t particleCount = PARTICLE_COUNT ;
} ubo ;
2016-08-16 23:06:27 +02:00
} compute ;
2016-08-17 20:32:05 +02:00
// SSBO particle declaration
2016-02-16 15:07:25 +01:00
struct Particle {
2016-08-17 20:32:05 +02:00
glm : : vec2 pos ; // Particle position
glm : : vec2 vel ; // Particle velocity
2020-08-08 18:22:10 +02:00
glm : : vec4 gradientPos ; // Texture coordinates for the gradient ramp map
2016-02-16 15:07:25 +01:00
} ;
2023-12-30 13:15:37 +01:00
VulkanExample ( ) : VulkanExampleBase ( )
2016-02-16 15:07:25 +01:00
{
2017-11-01 14:22:10 +01:00
title = " Compute shader particle system " ;
2016-02-16 15:07:25 +01:00
}
~ VulkanExample ( )
{
2016-08-16 23:06:27 +02:00
// Graphics
vkDestroyPipeline ( device , graphics . pipeline , nullptr ) ;
vkDestroyPipelineLayout ( device , graphics . pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , graphics . descriptorSetLayout , nullptr ) ;
2022-06-01 13:02:33 -04:00
vkDestroySemaphore ( device , graphics . semaphore , nullptr ) ;
2016-02-16 15:07:25 +01:00
2016-08-16 23:06:27 +02:00
// Compute
compute . storageBuffer . destroy ( ) ;
compute . uniformBuffer . destroy ( ) ;
vkDestroyPipelineLayout ( device , compute . pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , compute . descriptorSetLayout , nullptr ) ;
vkDestroyPipeline ( device , compute . pipeline , nullptr ) ;
2020-02-22 14:38:53 +01:00
vkDestroySemaphore ( device , compute . semaphore , nullptr ) ;
vkDestroyCommandPool ( device , compute . commandPool , nullptr ) ;
2016-05-14 23:09:17 +02:00
2017-02-09 21:55:35 +01:00
textures . particle . destroy ( ) ;
textures . gradient . destroy ( ) ;
2016-05-14 23:09:17 +02:00
}
2017-02-09 21:55:35 +01:00
void loadAssets ( )
2016-05-14 23:09:17 +02:00
{
2017-02-09 21:55:35 +01:00
textures . particle . loadFromFile ( getAssetPath ( ) + " textures/particle01_rgba.ktx " , VK_FORMAT_R8G8B8A8_UNORM , vulkanDevice , queue ) ;
textures . gradient . loadFromFile ( getAssetPath ( ) + " textures/particle_gradient_rgba.ktx " , VK_FORMAT_R8G8B8A8_UNORM , vulkanDevice , queue ) ;
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 23:09:17 +02:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
2016-02-16 15:07:25 +01:00
2020-02-22 14:38:53 +01:00
// Acquire barrier
if ( graphics . queueFamilyIndex ! = compute . queueFamilyIndex )
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER ,
nullptr ,
0 ,
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT ,
compute . queueFamilyIndex ,
graphics . queueFamilyIndex ,
compute . storageBuffer . buffer ,
0 ,
compute . storageBuffer . size
} ;
vkCmdPipelineBarrier (
drawCmdBuffers [ i ] ,
2022-06-13 22:53:48 -04:00
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT ,
2020-02-22 14:38:53 +01:00
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2016-05-15 09:14:10 +02:00
2020-02-22 14:38:53 +01:00
// Draw the particle system using the update vertex buffer
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 ) ;
2016-08-16 23:06:27 +02:00
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , graphics . pipeline ) ;
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , graphics . pipelineLayout , 0 , 1 , & graphics . descriptorSet , 0 , NULL ) ;
2016-02-16 15:07:25 +01:00
VkDeviceSize offsets [ 1 ] = { 0 } ;
2024-01-08 20:26:41 +01:00
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , 0 , 1 , & compute . storageBuffer . buffer , offsets ) ;
2016-02-16 15:07:25 +01:00
vkCmdDraw ( drawCmdBuffers [ i ] , PARTICLE_COUNT , 1 , 0 , 0 ) ;
2018-08-30 21:08:02 +02:00
drawUI ( drawCmdBuffers [ i ] ) ;
2016-02-16 15:07:25 +01:00
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
2020-02-22 14:38:53 +01:00
// Release barrier
if ( graphics . queueFamilyIndex ! = compute . queueFamilyIndex )
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER ,
nullptr ,
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT ,
0 ,
graphics . queueFamilyIndex ,
compute . queueFamilyIndex ,
compute . storageBuffer . buffer ,
0 ,
compute . storageBuffer . size
} ;
vkCmdPipelineBarrier (
drawCmdBuffers [ i ] ,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
2022-06-13 22:53:48 -04:00
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT ,
2020-02-22 14:38:53 +01:00
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2016-05-14 23:09:17 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2016-02-16 15:07:25 +01:00
}
}
2016-08-16 23:06:27 +02:00
void buildComputeCommandBuffer ( )
{
2017-02-12 11:12:42 +01:00
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( compute . commandBuffer , & cmdBufInfo ) ) ;
// Compute particle movement
2016-08-17 20:32:05 +02:00
// Add memory barrier to ensure that the (graphics) vertex shader has fetched attributes before compute starts to write to the buffer
2020-02-22 14:38:53 +01:00
if ( graphics . queueFamilyIndex ! = compute . queueFamilyIndex )
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER ,
nullptr ,
0 ,
VK_ACCESS_SHADER_WRITE_BIT ,
graphics . queueFamilyIndex ,
compute . queueFamilyIndex ,
compute . storageBuffer . buffer ,
0 ,
compute . storageBuffer . size
} ;
2016-08-16 23:06:27 +02:00
2020-02-22 14:38:53 +01:00
vkCmdPipelineBarrier (
compute . commandBuffer ,
2022-06-13 22:53:48 -04:00
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT ,
2020-02-22 14:38:53 +01:00
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2016-08-16 23:06:27 +02:00
// Dispatch the compute job
2020-02-22 14:38:53 +01:00
vkCmdBindPipeline ( compute . commandBuffer , VK_PIPELINE_BIND_POINT_COMPUTE , compute . pipeline ) ;
vkCmdBindDescriptorSets ( compute . commandBuffer , VK_PIPELINE_BIND_POINT_COMPUTE , compute . pipelineLayout , 0 , 1 , & compute . descriptorSet , 0 , 0 ) ;
2016-11-29 20:45:38 +01:00
vkCmdDispatch ( compute . commandBuffer , PARTICLE_COUNT / 256 , 1 , 1 ) ;
2016-08-16 23:06:27 +02:00
2020-02-22 14:38:53 +01:00
// Add barrier to ensure that compute shader has finished writing to the buffer
2020-05-21 15:49:28 +01:00
// Without this the (rendering) vertex shader may display incomplete results (partial data from last frame)
2020-02-22 14:38:53 +01:00
if ( graphics . queueFamilyIndex ! = compute . queueFamilyIndex )
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER ,
nullptr ,
VK_ACCESS_SHADER_WRITE_BIT ,
0 ,
compute . queueFamilyIndex ,
graphics . queueFamilyIndex ,
compute . storageBuffer . buffer ,
0 ,
compute . storageBuffer . size
} ;
vkCmdPipelineBarrier (
compute . commandBuffer ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
2022-06-13 22:53:48 -04:00
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT ,
2020-02-22 14:38:53 +01:00
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2016-08-16 23:06:27 +02:00
vkEndCommandBuffer ( compute . commandBuffer ) ;
}
2016-08-17 20:32:05 +02:00
// Setup and fill the compute shader storage buffers containing the particles
2016-02-16 15:07:25 +01:00
void prepareStorageBuffers ( )
{
2018-01-18 21:31:19 +01:00
std : : default_random_engine rndEngine ( benchmark . active ? 0 : ( unsigned ) time ( nullptr ) ) ;
std : : uniform_real_distribution < float > rndDist ( - 1.0f , 1.0f ) ;
2016-02-16 15:07:25 +01:00
// Initial particle positions
2016-04-21 11:21:48 +02:00
std : : vector < Particle > particleBuffer ( PARTICLE_COUNT ) ;
2018-01-18 21:31:19 +01:00
for ( auto & particle : particleBuffer ) {
particle . pos = glm : : vec2 ( rndDist ( rndEngine ) , rndDist ( rndEngine ) ) ;
2016-04-21 22:02:22 +02:00
particle . vel = glm : : vec2 ( 0.0f ) ;
2016-05-14 23:09:17 +02:00
particle . gradientPos . x = particle . pos . x / 2.0f ;
2016-02-16 15:07:25 +01:00
}
2016-08-17 20:32:05 +02:00
VkDeviceSize storageBufferSize = particleBuffer . size ( ) * sizeof ( Particle ) ;
2016-02-16 15:07:25 +01:00
2016-04-21 21:01:18 +02:00
// Staging
2020-05-21 15:49:28 +01:00
// SSBO won't be changed on the host after upload so copy to device local memory
2016-02-16 15:07:25 +01:00
2017-02-12 10:44:51 +01:00
vks : : Buffer stagingBuffer ;
2016-04-21 21:01:18 +02:00
2016-08-16 23:06:27 +02:00
vulkanDevice - > createBuffer (
2016-04-21 21:01:18 +02:00
VK_BUFFER_USAGE_TRANSFER_SRC_BIT ,
2016-08-16 23:06:27 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& stagingBuffer ,
2016-04-21 21:01:18 +02:00
storageBufferSize ,
2016-08-16 23:06:27 +02:00
particleBuffer . data ( ) ) ;
2016-04-21 21:01:18 +02:00
2016-08-16 23:06:27 +02:00
vulkanDevice - > createBuffer (
// The SSBO will be used as a storage buffer for the compute pipeline and as a vertex buffer in the graphics pipeline
2016-08-02 16:03:38 +02:00
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ,
2016-04-21 21:01:18 +02:00
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ,
2016-08-16 23:06:27 +02:00
& compute . storageBuffer ,
storageBufferSize ) ;
2016-04-21 21:01:18 +02:00
2020-02-22 14:38:53 +01:00
// Copy from staging buffer to storage buffer
2020-04-20 22:13:51 +02:00
VkCommandBuffer copyCmd = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
2016-04-21 21:01:18 +02:00
VkBufferCopy copyRegion = { } ;
copyRegion . size = storageBufferSize ;
2016-08-17 20:32:05 +02:00
vkCmdCopyBuffer ( copyCmd , stagingBuffer . buffer , compute . storageBuffer . buffer , 1 , & copyRegion ) ;
2020-02-22 14:38:53 +01:00
// Execute a transfer barrier to the compute queue, if necessary
if ( graphics . queueFamilyIndex ! = compute . queueFamilyIndex )
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER ,
nullptr ,
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT ,
0 ,
graphics . queueFamilyIndex ,
compute . queueFamilyIndex ,
compute . storageBuffer . buffer ,
0 ,
compute . storageBuffer . size
} ;
vkCmdPipelineBarrier (
copyCmd ,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
2022-06-13 22:53:48 -04:00
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT ,
2020-02-22 14:38:53 +01:00
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2020-04-20 22:13:51 +02:00
vulkanDevice - > flushCommandBuffer ( copyCmd , queue , true ) ;
2016-04-21 21:01:18 +02:00
2016-08-16 23:06:27 +02:00
stagingBuffer . destroy ( ) ;
2016-02-16 15:07:25 +01:00
// Binding description
vertices . bindingDescriptions . resize ( 1 ) ;
vertices . bindingDescriptions [ 0 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputBindingDescription (
2024-01-08 20:26:41 +01:00
0 ,
2016-02-16 15:07:25 +01:00
sizeof ( Particle ) ,
VK_VERTEX_INPUT_RATE_VERTEX ) ;
// Attribute descriptions
// Describes memory layout and shader positions
2016-05-14 23:09:17 +02:00
vertices . attributeDescriptions . resize ( 2 ) ;
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 (
2024-01-08 20:26:41 +01:00
0 ,
2016-02-16 15:07:25 +01:00
0 ,
2016-04-21 22:02:22 +02:00
VK_FORMAT_R32G32_SFLOAT ,
2016-08-16 23:06:27 +02:00
offsetof ( Particle , pos ) ) ;
2016-05-14 23:09:17 +02:00
// Location 1 : Gradient position
vertices . attributeDescriptions [ 1 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2024-01-08 20:26:41 +01:00
0 ,
2016-05-14 23:09:17 +02:00
1 ,
VK_FORMAT_R32G32B32A32_SFLOAT ,
2016-08-16 23:06:27 +02:00
offsetof ( Particle , gradientPos ) ) ;
2016-02-16 15:07:25 +01:00
// Assign to vertex buffer
2017-02-12 11:12:42 +01:00
vertices . inputState = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
2016-08-17 20:32:05 +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-08-17 20:32:05 +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 ( )
{
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_STORAGE_BUFFER , 1 ) ,
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 2 )
2016-02-16 15:07:25 +01:00
} ;
VkDescriptorPoolCreateInfo descriptorPoolInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolCreateInfo (
2016-08-17 20:32:05 +02:00
static_cast < uint32_t > ( poolSizes . size ( ) ) ,
2016-02-16 15:07:25 +01:00
poolSizes . data ( ) ,
2016-04-21 11:21:48 +02:00
2 ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 23:09:17 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSetLayout ( )
{
2016-05-14 23:09:17 +02:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings ;
// Binding 0 : Particle color map
2017-02-12 11:12:42 +01:00
setLayoutBindings . push_back ( vks : : initializers : : descriptorSetLayoutBinding (
2016-05-14 23:09:17 +02:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
VK_SHADER_STAGE_FRAGMENT_BIT ,
0 ) ) ;
// Binding 1 : Particle gradient ramp
2017-02-12 11:12:42 +01:00
setLayoutBindings . push_back ( vks : : initializers : : descriptorSetLayoutBinding (
2016-05-14 23:09:17 +02:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
VK_SHADER_STAGE_FRAGMENT_BIT ,
1 ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 23:09:17 +02:00
VkDescriptorSetLayoutCreateInfo descriptorLayout =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutCreateInfo (
2016-05-14 23:09:17 +02:00
setLayoutBindings . data ( ) ,
2016-08-17 20:32:05 +02:00
static_cast < uint32_t > ( setLayoutBindings . size ( ) ) ) ;
2016-02-16 15:07:25 +01:00
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & graphics . descriptorSetLayout ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 23:09:17 +02:00
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineLayoutCreateInfo (
2016-08-16 23:06:27 +02:00
& graphics . descriptorSetLayout ,
2016-05-14 23:09:17 +02:00
1 ) ;
2016-02-16 15:07:25 +01:00
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCreateInfo , nullptr , & graphics . pipelineLayout ) ) ;
2016-05-14 23:09:17 +02:00
}
void setupDescriptorSet ( )
{
VkDescriptorSetAllocateInfo allocInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetAllocateInfo (
2016-05-14 23:09:17 +02:00
descriptorPool ,
2016-08-16 23:06:27 +02:00
& graphics . descriptorSetLayout ,
2016-05-14 23:09:17 +02:00
1 ) ;
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & graphics . descriptorSet ) ) ;
2016-05-14 23:09:17 +02:00
std : : vector < VkWriteDescriptorSet > writeDescriptorSets ;
// Binding 0 : Particle color map
2017-02-12 11:12:42 +01:00
writeDescriptorSets . push_back ( vks : : initializers : : writeDescriptorSet (
2016-08-16 23:06:27 +02:00
graphics . descriptorSet ,
2016-05-14 23:09:17 +02:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
0 ,
2016-08-17 20:32:05 +02:00
& textures . particle . descriptor ) ) ;
2016-05-14 23:09:17 +02:00
// Binding 1 : Particle gradient ramp
2017-02-12 11:12:42 +01:00
writeDescriptorSets . push_back ( vks : : initializers : : writeDescriptorSet (
2016-08-16 23:06:27 +02:00
graphics . descriptorSet ,
2016-05-14 23:09:17 +02:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
1 ,
2016-08-17 20:32:05 +02:00
& textures . gradient . descriptor ) ) ;
2016-05-14 23:09:17 +02:00
2016-08-17 20:32:05 +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_POINT_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-04-21 11:21:48 +02:00
VK_FALSE ,
VK_FALSE ,
VK_COMPARE_OP_ALWAYS ) ;
2016-02-16 15:07:25 +01:00
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-04-21 21:14:34 +02:00
VK_SAMPLE_COUNT_1_BIT ,
2016-02-16 15:07:25 +01:00
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-08-17 20:32:05 +02:00
static_cast < uint32_t > ( dynamicStateEnables . size ( ) ) ,
2016-02-16 15:07:25 +01:00
0 ) ;
// Rendering pipeline
// Load shaders
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2020-05-29 16:08:53 +01:00
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " computeparticles/particle.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " computeparticles/particle.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-08-16 23:06:27 +02:00
graphics . pipelineLayout ,
2016-02-16 15:07:25 +01:00
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-08-17 20:32:05 +02:00
pipelineCreateInfo . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
2016-02-16 15:07:25 +01:00
pipelineCreateInfo . pStages = shaderStages . data ( ) ;
pipelineCreateInfo . renderPass = renderPass ;
// Additive blending
blendAttachmentState . colorWriteMask = 0xF ;
blendAttachmentState . blendEnable = VK_TRUE ;
blendAttachmentState . colorBlendOp = VK_BLEND_OP_ADD ;
blendAttachmentState . srcColorBlendFactor = VK_BLEND_FACTOR_ONE ;
blendAttachmentState . dstColorBlendFactor = VK_BLEND_FACTOR_ONE ;
blendAttachmentState . alphaBlendOp = VK_BLEND_OP_ADD ;
blendAttachmentState . srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA ;
blendAttachmentState . dstAlphaBlendFactor = VK_BLEND_FACTOR_DST_ALPHA ;
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & graphics . pipeline ) ) ;
2016-02-16 15:07:25 +01:00
}
2020-02-22 14:38:53 +01:00
void prepareGraphics ( )
{
prepareStorageBuffers ( ) ;
prepareUniformBuffers ( ) ;
setupDescriptorSetLayout ( ) ;
preparePipelines ( ) ;
setupDescriptorSet ( ) ;
// Semaphore for compute & graphics sync
VkSemaphoreCreateInfo semaphoreCreateInfo = vks : : initializers : : semaphoreCreateInfo ( ) ;
VK_CHECK_RESULT ( vkCreateSemaphore ( device , & semaphoreCreateInfo , nullptr , & graphics . semaphore ) ) ;
2022-06-01 13:02:33 -04:00
// Signal the semaphore
VkSubmitInfo submitInfo = vks : : initializers : : submitInfo ( ) ;
submitInfo . signalSemaphoreCount = 1 ;
submitInfo . pSignalSemaphores = & graphics . semaphore ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VK_CHECK_RESULT ( vkQueueWaitIdle ( queue ) ) ;
2020-02-22 14:38:53 +01:00
}
2016-02-16 15:07:25 +01:00
void prepareCompute ( )
{
2016-08-16 23:06:27 +02:00
// Create a compute capable device queue
2016-08-17 20:32:05 +02:00
// The VulkanDevice::createLogicalDevice functions finds a compute capable queue and prefers queue families that only support compute
// Depending on the implementation this may result in different queue family indices for graphics and computes,
2020-02-22 14:38:53 +01:00
// requiring proper synchronization (see the memory and pipeline barriers)
vkGetDeviceQueue ( device , compute . queueFamilyIndex , 0 , & compute . queue ) ;
2016-08-16 23:06:27 +02:00
2016-02-16 15:07:25 +01:00
// Create compute pipeline
2016-08-16 23:06:27 +02:00
// Compute pipelines are created separate from graphics pipelines even if they use the same queue (family index)
2016-02-16 15:07:25 +01:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
// Binding 0 : Particle position storage buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2016-02-16 15:07:25 +01:00
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ,
VK_SHADER_STAGE_COMPUTE_BIT ,
0 ) ,
// Binding 1 : 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_COMPUTE_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-08-17 20:32:05 +02:00
static_cast < uint32_t > ( setLayoutBindings . size ( ) ) ) ;
2016-02-16 15:07:25 +01:00
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & compute . descriptorSetLayout ) ) ;
2016-02-16 15:07:25 +01:00
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineLayoutCreateInfo (
2016-08-16 23:06:27 +02:00
& compute . descriptorSetLayout ,
2016-02-16 15:07:25 +01:00
1 ) ;
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & compute . pipelineLayout ) ) ;
2016-02-16 15:07:25 +01:00
VkDescriptorSetAllocateInfo allocInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetAllocateInfo (
2016-02-16 15:07:25 +01:00
descriptorPool ,
2016-08-16 23:06:27 +02:00
& compute . descriptorSetLayout ,
2016-02-16 15:07:25 +01:00
1 ) ;
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & compute . descriptorSet ) ) ;
2016-02-16 15:07:25 +01:00
std : : vector < VkWriteDescriptorSet > computeWriteDescriptorSets =
{
// Binding 0 : Particle position storage buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-08-16 23:06:27 +02:00
compute . descriptorSet ,
2016-02-16 15:07:25 +01:00
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ,
0 ,
2016-08-16 23:06:27 +02:00
& compute . storageBuffer . descriptor ) ,
2016-02-16 15:07:25 +01:00
// Binding 1 : Uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-08-16 23:06:27 +02:00
compute . descriptorSet ,
2016-02-16 15:07:25 +01:00
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
1 ,
2016-08-16 23:06:27 +02:00
& compute . uniformBuffer . descriptor )
2016-02-16 15:07:25 +01:00
} ;
2016-08-17 20:32:05 +02:00
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( computeWriteDescriptorSets . size ( ) ) , computeWriteDescriptorSets . data ( ) , 0 , NULL ) ;
2016-02-16 15:07:25 +01:00
2020-05-21 15:49:28 +01:00
// Create pipeline
2017-02-12 11:12:42 +01:00
VkComputePipelineCreateInfo computePipelineCreateInfo = vks : : initializers : : computePipelineCreateInfo ( compute . pipelineLayout , 0 ) ;
2020-05-29 16:08:53 +01:00
computePipelineCreateInfo . stage = loadShader ( getShadersPath ( ) + " computeparticles/particle.comp.spv " , VK_SHADER_STAGE_COMPUTE_BIT ) ;
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( vkCreateComputePipelines ( device , pipelineCache , 1 , & computePipelineCreateInfo , nullptr , & compute . pipeline ) ) ;
// Separate command pool as queue family for compute may be different than graphics
VkCommandPoolCreateInfo cmdPoolInfo = { } ;
cmdPoolInfo . sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO ;
2020-02-22 14:38:53 +01:00
cmdPoolInfo . queueFamilyIndex = compute . queueFamilyIndex ;
2016-08-16 23:06:27 +02:00
cmdPoolInfo . flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT ;
VK_CHECK_RESULT ( vkCreateCommandPool ( device , & cmdPoolInfo , nullptr , & compute . commandPool ) ) ;
2016-08-17 20:32:05 +02:00
// Create a command buffer for compute operations
2020-02-22 14:38:53 +01:00
compute . commandBuffer = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , compute . commandPool ) ;
2016-08-16 23:06:27 +02:00
2020-02-22 14:38:53 +01:00
// Semaphore for compute & graphics sync
VkSemaphoreCreateInfo semaphoreCreateInfo = vks : : initializers : : semaphoreCreateInfo ( ) ;
VK_CHECK_RESULT ( vkCreateSemaphore ( device , & semaphoreCreateInfo , nullptr , & compute . semaphore ) ) ;
2016-08-16 23:06:27 +02:00
2016-08-17 20:32:05 +02:00
// Build a single command buffer containing the compute dispatch commands
2016-08-16 23:06:27 +02:00
buildComputeCommandBuffer ( ) ;
2020-02-22 14:38:53 +01:00
2022-06-13 22:53:48 -04:00
// SRS - By reordering compute and graphics within draw(), the following code is no longer needed:
2020-02-22 14:38:53 +01:00
// If graphics and compute queue family indices differ, acquire and immediately release the storage buffer, so that the initial acquire from the graphics command buffers are matched up properly
2022-06-13 22:53:48 -04:00
/*
2020-02-22 14:38:53 +01:00
if ( graphics . queueFamilyIndex ! = compute . queueFamilyIndex )
{
// Create a transient command buffer for setting up the initial buffer transfer state
VkCommandBuffer transferCmd = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , compute . commandPool , true ) ;
VkBufferMemoryBarrier acquire_buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER ,
nullptr ,
0 ,
VK_ACCESS_SHADER_WRITE_BIT ,
graphics . queueFamilyIndex ,
compute . queueFamilyIndex ,
compute . storageBuffer . buffer ,
0 ,
compute . storageBuffer . size
} ;
vkCmdPipelineBarrier (
transferCmd ,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
0 ,
0 , nullptr ,
1 , & acquire_buffer_barrier ,
0 , nullptr ) ;
VkBufferMemoryBarrier release_buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER ,
nullptr ,
VK_ACCESS_SHADER_WRITE_BIT ,
0 ,
compute . queueFamilyIndex ,
graphics . queueFamilyIndex ,
compute . storageBuffer . buffer ,
0 ,
compute . storageBuffer . size
} ;
vkCmdPipelineBarrier (
transferCmd ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
0 ,
0 , nullptr ,
1 , & release_buffer_barrier ,
0 , nullptr ) ;
vulkanDevice - > flushCommandBuffer ( transferCmd , compute . queue , compute . commandPool ) ;
}
2022-06-13 22:53:48 -04:00
*/
2016-02-16 15:07:25 +01:00
}
// Prepare and initialize uniform buffer containing shader uniforms
void prepareUniformBuffers ( )
{
// Compute shader uniform buffer block
2016-08-16 23:06:27 +02:00
vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-05-26 19:13:14 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-08-16 23:06:27 +02:00
& compute . uniformBuffer ,
2016-08-17 20:32:05 +02:00
sizeof ( compute . ubo ) ) ;
2016-04-21 21:01:18 +02:00
// Map for host access
2016-08-16 23:06:27 +02:00
VK_CHECK_RESULT ( compute . uniformBuffer . map ( ) ) ;
2016-02-16 15:07:25 +01:00
updateUniformBuffers ( ) ;
}
void updateUniformBuffers ( )
{
2022-06-01 13:02:33 -04:00
compute . ubo . deltaT = paused ? 0.0f : frameTimer * 2.5f ;
2020-02-22 14:38:53 +01:00
if ( ! attachToCursor )
2016-04-21 11:21:48 +02:00
{
2016-08-17 20:32:05 +02:00
compute . ubo . destX = sin ( glm : : radians ( timer * 360.0f ) ) * 0.75f ;
compute . ubo . destY = 0.0f ;
2016-04-21 11:21:48 +02:00
}
else
{
float normalizedMx = ( mousePos . x - static_cast < float > ( width / 2 ) ) / static_cast < float > ( width / 2 ) ;
float normalizedMy = ( mousePos . y - static_cast < float > ( height / 2 ) ) / static_cast < float > ( height / 2 ) ;
2016-08-17 20:32:05 +02:00
compute . ubo . destX = normalizedMx ;
compute . ubo . destY = normalizedMy ;
2016-04-21 11:21:48 +02:00
}
2016-08-17 20:32:05 +02:00
memcpy ( compute . uniformBuffer . mapped , & compute . ubo , sizeof ( compute . ubo ) ) ;
2016-02-16 15:07:25 +01:00
}
2016-05-26 19:13:14 +02:00
void draw ( )
{
2022-06-01 13:02:33 -04:00
// Wait for rendering finished
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ;
// Submit compute commands
VkSubmitInfo computeSubmitInfo = vks : : initializers : : submitInfo ( ) ;
computeSubmitInfo . commandBufferCount = 1 ;
computeSubmitInfo . pCommandBuffers = & compute . commandBuffer ;
computeSubmitInfo . waitSemaphoreCount = 1 ;
computeSubmitInfo . pWaitSemaphores = & graphics . semaphore ;
computeSubmitInfo . pWaitDstStageMask = & waitStageMask ;
computeSubmitInfo . signalSemaphoreCount = 1 ;
computeSubmitInfo . pSignalSemaphores = & compute . semaphore ;
VK_CHECK_RESULT ( vkQueueSubmit ( compute . queue , 1 , & computeSubmitInfo , VK_NULL_HANDLE ) ) ;
2020-02-22 14:38:53 +01:00
VulkanExampleBase : : prepareFrame ( ) ;
2018-04-16 11:11:55 +02:00
2020-02-22 14:38:53 +01:00
VkPipelineStageFlags graphicsWaitStageMasks [ ] = { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT , VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT } ;
VkSemaphore graphicsWaitSemaphores [ ] = { compute . semaphore , semaphores . presentComplete } ;
VkSemaphore graphicsSignalSemaphores [ ] = { graphics . semaphore , semaphores . renderComplete } ;
2018-04-16 11:11:55 +02:00
2016-08-17 20:32:05 +02:00
// Submit graphics commands
2016-05-26 19:13:14 +02:00
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
2020-02-22 14:38:53 +01:00
submitInfo . waitSemaphoreCount = 2 ;
submitInfo . pWaitSemaphores = graphicsWaitSemaphores ;
submitInfo . pWaitDstStageMask = graphicsWaitStageMasks ;
submitInfo . signalSemaphoreCount = 2 ;
submitInfo . pSignalSemaphores = graphicsSignalSemaphores ;
2016-05-26 19:13:14 +02:00
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
}
2016-02-16 15:07:25 +01:00
void prepare ( )
2020-05-21 15:49:28 +01:00
{
2016-02-16 15:07:25 +01:00
VulkanExampleBase : : prepare ( ) ;
2020-02-22 14:38:53 +01:00
// We will be using the queue family indices to check if graphics and compute queue families differ
// If that's the case, we need additional barriers for acquiring and releasing resources
graphics . queueFamilyIndex = vulkanDevice - > queueFamilyIndices . graphics ;
compute . queueFamilyIndex = vulkanDevice - > queueFamilyIndices . compute ;
2017-02-09 21:55:35 +01:00
loadAssets ( ) ;
2016-02-16 15:07:25 +01:00
setupDescriptorPool ( ) ;
2020-02-22 14:38:53 +01:00
prepareGraphics ( ) ;
2016-02-16 15:07:25 +01:00
prepareCompute ( ) ;
2016-05-14 23:09:17 +02:00
buildCommandBuffers ( ) ;
2016-02-16 15:07:25 +01:00
prepared = true ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
2016-04-21 11:21:48 +02:00
2020-02-22 14:38:53 +01:00
if ( ! attachToCursor )
2016-02-16 15:07:25 +01:00
{
2016-04-21 11:21:48 +02:00
if ( animStart > 0.0f )
{
animStart - = frameTimer * 5.0f ;
}
else if ( animStart < = 0.0f )
2016-02-16 15:07:25 +01:00
{
2016-04-21 11:21:48 +02:00
timer + = frameTimer * 0.04f ;
if ( timer > 1.f )
timer = 0.f ;
2016-02-16 15:07:25 +01:00
}
}
2020-05-21 15:49:28 +01:00
2016-02-16 15:07:25 +01:00
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 " ) ) {
2020-02-22 14:38:53 +01:00
overlay - > checkBox ( " Attach attractor to cursor " , & attachToCursor ) ;
2016-02-16 15:07:25 +01:00
}
}
2016-08-16 23:06:27 +02:00
} ;
2016-02-16 15:07:25 +01:00
2020-03-15 11:04:13 -04:00
VULKAN_EXAMPLE_MAIN ( )