2016-11-26 13:52:22 +01:00
/*
* Vulkan Example - Compute shader N - body simulation using two passes and shared compute shader memory
*
2019-10-23 20:45:54 +02:00
* Copyright ( C ) by Sascha Willems - www . saschawillems . de
2016-11-26 13:52:22 +01:00
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
# include "vulkanexamplebase.h"
# define VERTEX_BUFFER_BIND_ID 0
# define ENABLE_VALIDATION false
# if defined(__ANDROID__)
// Lower particle count on Android for performance reasons
2016-11-27 13:44:10 +01:00
# define PARTICLES_PER_ATTRACTOR 3 * 1024
2016-11-26 13:52:22 +01:00
# else
2016-11-26 14:43:24 +01:00
# define PARTICLES_PER_ATTRACTOR 4 * 1024
2016-11-26 13:52:22 +01:00
# endif
class VulkanExample : public VulkanExampleBase
{
public :
uint32_t numParticles ;
struct {
2017-02-09 21:55:35 +01:00
vks : : Texture2D particle ;
vks : : Texture2D gradient ;
2016-11-26 13:52:22 +01:00
} textures ;
struct {
VkPipelineVertexInputStateCreateInfo inputState ;
std : : vector < VkVertexInputBindingDescription > bindingDescriptions ;
std : : vector < VkVertexInputAttributeDescription > attributeDescriptions ;
} vertices ;
// Resources for the graphics part of the example
struct {
2020-02-22 12:20:30 +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 uniformBuffer ; // Contains scene matrices
2016-11-26 13:52:22 +01: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
2019-06-17 19:31:00 +08:00
VkSemaphore semaphore ; // Execution dependency between compute & graphic submission
2016-11-26 13:52:22 +01:00
struct {
glm : : mat4 projection ;
glm : : mat4 view ;
2016-11-26 14:43:24 +01:00
glm : : vec2 screenDim ;
2016-11-26 13:52:22 +01:00
} ubo ;
} graphics ;
// Resources for the compute part of the example
struct {
2020-02-22 12:20:30 +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-11-26 13:52:22 +01: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
2019-06-17 19:31:00 +08:00
VkSemaphore semaphore ; // Execution dependency between compute & graphic submission
2016-11-26 13:52:22 +01:00
VkDescriptorSetLayout descriptorSetLayout ; // Compute shader binding layout
VkDescriptorSet descriptorSet ; // Compute shader bindings
VkPipelineLayout pipelineLayout ; // Layout of the compute pipeline
VkPipeline pipelineCalculate ; // Compute pipeline for N-Body velocity calculation (1st pass)
VkPipeline pipelineIntegrate ; // Compute pipeline for euler integration (2nd pass)
VkPipeline blur ;
VkPipelineLayout pipelineLayoutBlur ;
VkDescriptorSetLayout descriptorSetLayoutBlur ;
VkDescriptorSet descriptorSetBlur ;
struct computeUBO { // Compute shader uniform block object
float deltaT ; // Frame delta time
int32_t particleCount ;
} ubo ;
} compute ;
// SSBO particle declaration
struct Particle {
glm : : vec4 pos ; // xyz = position, w = mass
glm : : vec4 vel ; // xyz = velocity, w = gradient texture position
} ;
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
{
2017-11-01 14:22:10 +01:00
title = " Compute shader N-body system " ;
2016-11-26 13:52:22 +01:00
camera . type = Camera : : CameraType : : lookat ;
camera . setPerspective ( 60.0f , ( float ) width / ( float ) height , 0.1f , 512.0f ) ;
camera . setRotation ( glm : : vec3 ( - 26.0f , 75.0f , 0.0f ) ) ;
camera . setTranslation ( glm : : vec3 ( 0.0f , 0.0f , - 14.0f ) ) ;
camera . movementSpeed = 2.5f ;
}
~ VulkanExample ( )
{
// Graphics
2017-02-07 20:49:22 +01:00
graphics . uniformBuffer . destroy ( ) ;
2016-11-26 13:52:22 +01:00
vkDestroyPipeline ( device , graphics . pipeline , nullptr ) ;
vkDestroyPipelineLayout ( device , graphics . pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , graphics . descriptorSetLayout , nullptr ) ;
2019-06-17 19:31:00 +08:00
vkDestroySemaphore ( device , graphics . semaphore , nullptr ) ;
2016-11-26 13:52:22 +01:00
// Compute
compute . storageBuffer . destroy ( ) ;
compute . uniformBuffer . destroy ( ) ;
vkDestroyPipelineLayout ( device , compute . pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , compute . descriptorSetLayout , nullptr ) ;
vkDestroyPipeline ( device , compute . pipelineCalculate , nullptr ) ;
vkDestroyPipeline ( device , compute . pipelineIntegrate , nullptr ) ;
2019-06-17 19:31:00 +08:00
vkDestroySemaphore ( device , compute . semaphore , nullptr ) ;
2016-11-26 13:52:22 +01:00
vkDestroyCommandPool ( device , compute . commandPool , nullptr ) ;
2017-02-09 21:55:35 +01:00
textures . particle . destroy ( ) ;
textures . gradient . destroy ( ) ;
2016-11-26 13:52:22 +01:00
}
2017-02-09 21:55:35 +01:00
void loadAssets ( )
2016-11-26 13:52:22 +01: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-11-26 13:52:22 +01:00
}
void buildCommandBuffers ( )
{
2017-02-12 11:12:42 +01:00
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
2016-11-26 13:52:22 +01:00
VkClearValue clearValues [ 2 ] ;
clearValues [ 0 ] . color = { { 0.0f , 0.0f , 0.0f , 1.0f } } ;
clearValues [ 1 ] . depthStencil = { 1.0f , 0 } ;
2017-02-12 11:12:42 +01:00
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
2016-11-26 13:52:22 +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 ] ;
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
2020-02-22 12:20:30 +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 ,
2020-05-29 16:08:53 +01:00
compute . storageBuffer . size
2020-02-22 12:20:30 +01:00
} ;
vkCmdPipelineBarrier (
drawCmdBuffers [ i ] ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2016-11-26 13:52:22 +01:00
2020-02-22 12:20:30 +01:00
// Draw the particle system using the update vertex buffer
2016-11-26 13:52:22 +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-11-26 13:52:22 +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-11-26 13:52:22 +01:00
vkCmdSetScissor ( drawCmdBuffers [ i ] , 0 , 1 , & scissor ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , graphics . pipeline ) ;
2020-02-22 12:20:30 +01:00
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , graphics . pipelineLayout , 0 , 1 , & graphics . descriptorSet , 0 , nullptr ) ;
2016-11-26 13:52:22 +01:00
VkDeviceSize offsets [ 1 ] = { 0 } ;
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , VERTEX_BUFFER_BIND_ID , 1 , & compute . storageBuffer . buffer , offsets ) ;
vkCmdDraw ( drawCmdBuffers [ i ] , numParticles , 1 , 0 , 0 ) ;
2020-05-29 16:08:53 +01:00
2018-08-30 21:08:02 +02:00
drawUI ( drawCmdBuffers [ i ] ) ;
2016-11-26 13:52:22 +01:00
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
2019-10-13 09:40:31 +02:00
2020-02-22 12:20:30 +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 ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2016-11-26 13:52:22 +01:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
}
}
void buildComputeCommandBuffer ( )
{
2017-02-12 11:12:42 +01:00
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
2016-11-26 13:52:22 +01:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( compute . commandBuffer , & cmdBufInfo ) ) ;
2020-02-22 12:20:30 +01:00
// Acquire barrier
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 ,
2020-05-29 16:08:53 +01:00
compute . storageBuffer . size
2020-02-22 12:20:30 +01:00
} ;
vkCmdPipelineBarrier (
compute . commandBuffer ,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2016-11-26 13:52:22 +01:00
// First pass: Calculate particle movement
// -------------------------------------------------------------------------------------------------------
2019-10-13 09:40:31 +02:00
vkCmdBindPipeline ( compute . commandBuffer , VK_PIPELINE_BIND_POINT_COMPUTE , compute . pipelineCalculate ) ;
vkCmdBindDescriptorSets ( compute . commandBuffer , VK_PIPELINE_BIND_POINT_COMPUTE , compute . pipelineLayout , 0 , 1 , & compute . descriptorSet , 0 , 0 ) ;
2016-11-26 13:52:22 +01:00
vkCmdDispatch ( compute . commandBuffer , numParticles / 256 , 1 , 1 ) ;
2019-10-13 09:40:31 +02:00
// Add memory barrier to ensure that the computer shader has finished writing to the buffer
VkBufferMemoryBarrier bufferBarrier = vks : : initializers : : bufferMemoryBarrier ( ) ;
2016-11-26 13:52:22 +01:00
bufferBarrier . buffer = compute . storageBuffer . buffer ;
bufferBarrier . size = compute . storageBuffer . descriptor . range ;
2019-10-13 09:40:31 +02:00
bufferBarrier . srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT ;
bufferBarrier . dstAccessMask = VK_ACCESS_SHADER_READ_BIT ;
2020-08-08 18:22:10 +02:00
// Transfer ownership if compute and graphics queue family indices differ
2019-10-13 09:40:31 +02:00
bufferBarrier . srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED ;
2016-11-26 13:52:22 +01:00
bufferBarrier . dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED ;
vkCmdPipelineBarrier (
compute . commandBuffer ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
VK_FLAGS_NONE ,
0 , nullptr ,
1 , & bufferBarrier ,
0 , nullptr ) ;
// Second pass: Integrate particles
// -------------------------------------------------------------------------------------------------------
vkCmdBindPipeline ( compute . commandBuffer , VK_PIPELINE_BIND_POINT_COMPUTE , compute . pipelineIntegrate ) ;
vkCmdDispatch ( compute . commandBuffer , numParticles / 256 , 1 , 1 ) ;
2020-02-22 12:20:30 +01:00
// Release barrier
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 ,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2016-11-26 13:52:22 +01:00
vkEndCommandBuffer ( compute . commandBuffer ) ;
}
// Setup and fill the compute shader storage buffers containing the particles
void prepareStorageBuffers ( )
{
#if 0
std : : vector < glm : : vec3 > attractors = {
glm : : vec3 ( 2.5f , 1.5f , 0.0f ) ,
glm : : vec3 ( - 2.5f , - 1.5f , 0.0f ) ,
} ;
# else
std : : vector < glm : : vec3 > attractors = {
glm : : vec3 ( 5.0f , 0.0f , 0.0f ) ,
glm : : vec3 ( - 5.0f , 0.0f , 0.0f ) ,
glm : : vec3 ( 0.0f , 0.0f , 5.0f ) ,
glm : : vec3 ( 0.0f , 0.0f , - 5.0f ) ,
glm : : vec3 ( 0.0f , 4.0f , 0.0f ) ,
glm : : vec3 ( 0.0f , - 8.0f , 0.0f ) ,
} ;
# endif
numParticles = static_cast < uint32_t > ( attractors . size ( ) ) * PARTICLES_PER_ATTRACTOR ;
// Initial particle positions
std : : vector < Particle > particleBuffer ( numParticles ) ;
2018-01-18 21:31:19 +01:00
std : : default_random_engine rndEngine ( benchmark . active ? 0 : ( unsigned ) time ( nullptr ) ) ;
2016-11-26 13:52:22 +01:00
std : : normal_distribution < float > rndDist ( 0.0f , 1.0f ) ;
for ( uint32_t i = 0 ; i < static_cast < uint32_t > ( attractors . size ( ) ) ; i + + )
{
for ( uint32_t j = 0 ; j < PARTICLES_PER_ATTRACTOR ; j + + )
{
Particle & particle = particleBuffer [ i * PARTICLES_PER_ATTRACTOR + j ] ;
// First particle in group as heavy center of gravity
if ( j = = 0 )
{
particle . pos = glm : : vec4 ( attractors [ i ] * 1.5f , 90000.0f ) ;
particle . vel = glm : : vec4 ( glm : : vec4 ( 0.0f ) ) ;
}
else
{
2020-05-29 16:08:53 +01:00
// Position
2018-01-18 21:31:19 +01:00
glm : : vec3 position ( attractors [ i ] + glm : : vec3 ( rndDist ( rndEngine ) , rndDist ( rndEngine ) , rndDist ( rndEngine ) ) * 0.75f ) ;
2016-11-26 13:52:22 +01:00
float len = glm : : length ( glm : : normalize ( position - attractors [ i ] ) ) ;
position . y * = 2.0f - ( len * len ) ;
// Velocity
glm : : vec3 angular = glm : : vec3 ( 0.5f , 1.5f , 0.5f ) * ( ( ( i % 2 ) = = 0 ) ? 1.0f : - 1.0f ) ;
2018-01-18 21:31:19 +01:00
glm : : vec3 velocity = glm : : cross ( ( position - attractors [ i ] ) , angular ) + glm : : vec3 ( rndDist ( rndEngine ) , rndDist ( rndEngine ) , rndDist ( rndEngine ) * 0.025f ) ;
2016-11-26 13:52:22 +01:00
2018-01-18 21:31:19 +01:00
float mass = ( rndDist ( rndEngine ) * 0.5f + 0.5f ) * 75.0f ;
2016-11-26 13:52:22 +01:00
particle . pos = glm : : vec4 ( position , mass ) ;
particle . vel = glm : : vec4 ( velocity , 0.0f ) ;
}
// Color gradient offset
particle . vel . w = ( float ) i * 1.0f / static_cast < uint32_t > ( attractors . size ( ) ) ;
}
}
compute . ubo . particleCount = numParticles ;
VkDeviceSize storageBufferSize = particleBuffer . size ( ) * sizeof ( Particle ) ;
// Staging
2020-05-29 16:08:53 +01:00
// SSBO won't be changed on the host after upload so copy to device local memory
2016-11-26 13:52:22 +01:00
2017-02-12 10:44:51 +01:00
vks : : Buffer stagingBuffer ;
2016-11-26 13:52:22 +01:00
vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_TRANSFER_SRC_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& stagingBuffer ,
storageBufferSize ,
particleBuffer . data ( ) ) ;
vulkanDevice - > createBuffer (
// The SSBO will be used as a storage buffer for the compute pipeline and as a vertex buffer in the graphics pipeline
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ,
& compute . storageBuffer ,
storageBufferSize ) ;
2020-02-22 12:20:30 +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-11-26 13:52:22 +01:00
VkBufferCopy copyRegion = { } ;
copyRegion . size = storageBufferSize ;
vkCmdCopyBuffer ( copyCmd , stagingBuffer . buffer , compute . storageBuffer . buffer , 1 , & copyRegion ) ;
2020-02-22 12:20:30 +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 ,
2020-05-29 16:08:53 +01:00
compute . storageBuffer . size
2020-02-22 12:20:30 +01:00
} ;
vkCmdPipelineBarrier (
copyCmd ,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ,
0 ,
0 , nullptr ,
1 , & buffer_barrier ,
0 , nullptr ) ;
}
2020-04-20 22:13:51 +02:00
vulkanDevice - > flushCommandBuffer ( copyCmd , queue , true ) ;
2016-11-26 13:52:22 +01:00
stagingBuffer . destroy ( ) ;
// Binding description
vertices . bindingDescriptions . resize ( 1 ) ;
vertices . bindingDescriptions [ 0 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputBindingDescription (
2016-11-26 13:52:22 +01:00
VERTEX_BUFFER_BIND_ID ,
sizeof ( Particle ) ,
VK_VERTEX_INPUT_RATE_VERTEX ) ;
// Attribute descriptions
// Describes memory layout and shader positions
vertices . attributeDescriptions . resize ( 2 ) ;
// Location 0 : Position
vertices . attributeDescriptions [ 0 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-11-26 13:52:22 +01:00
VERTEX_BUFFER_BIND_ID ,
0 ,
2016-11-26 14:43:24 +01:00
VK_FORMAT_R32G32B32A32_SFLOAT ,
2016-11-26 13:52:22 +01:00
offsetof ( Particle , pos ) ) ;
// Location 1 : Velocity (used for gradient lookup)
vertices . attributeDescriptions [ 1 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-11-26 13:52:22 +01:00
VERTEX_BUFFER_BIND_ID ,
1 ,
VK_FORMAT_R32G32B32A32_SFLOAT ,
offsetof ( Particle , vel ) ) ;
// Assign to vertex buffer
2017-02-12 11:12:42 +01:00
vertices . inputState = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
2016-11-26 13:52:22 +01:00
vertices . inputState . vertexBindingDescriptionCount = static_cast < uint32_t > ( vertices . bindingDescriptions . size ( ) ) ;
vertices . inputState . pVertexBindingDescriptions = vertices . bindingDescriptions . data ( ) ;
vertices . inputState . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertices . attributeDescriptions . size ( ) ) ;
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 , 2 ) ,
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_STORAGE_BUFFER , 1 ) ,
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 2 )
2016-11-26 13:52:22 +01:00
} ;
VkDescriptorPoolCreateInfo descriptorPoolInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolCreateInfo (
2016-11-26 13:52:22 +01:00
static_cast < uint32_t > ( poolSizes . size ( ) ) ,
poolSizes . data ( ) ,
2 ) ;
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
}
void setupDescriptorSetLayout ( )
{
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings ;
setLayoutBindings = {
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 0 ) ,
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 1 ) ,
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_VERTEX_BIT , 2 ) ,
2016-11-26 13:52:22 +01:00
} ;
VkDescriptorSetLayoutCreateInfo descriptorLayout =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutCreateInfo (
2016-11-26 13:52:22 +01:00
setLayoutBindings . data ( ) ,
static_cast < uint32_t > ( setLayoutBindings . size ( ) ) ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & graphics . descriptorSetLayout ) ) ;
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineLayoutCreateInfo (
2016-11-26 13:52:22 +01:00
& graphics . descriptorSetLayout ,
1 ) ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCreateInfo , nullptr , & graphics . pipelineLayout ) ) ;
}
void setupDescriptorSet ( )
{
VkDescriptorSetAllocateInfo allocInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetAllocateInfo (
2016-11-26 13:52:22 +01:00
descriptorPool ,
& graphics . descriptorSetLayout ,
1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & graphics . descriptorSet ) ) ;
std : : vector < VkWriteDescriptorSet > writeDescriptorSets ;
writeDescriptorSets = {
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet ( graphics . descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 0 , & textures . particle . descriptor ) ,
vks : : initializers : : writeDescriptorSet ( graphics . descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , & textures . gradient . descriptor ) ,
vks : : initializers : : writeDescriptorSet ( graphics . descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 2 , & graphics . uniformBuffer . descriptor ) ,
2016-11-26 13:52:22 +01:00
} ;
2020-02-22 12:20:30 +01:00
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , nullptr ) ;
2016-11-26 13:52:22 +01:00
}
void preparePipelines ( )
{
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineInputAssemblyStateCreateInfo (
2016-11-26 13:52:22 +01:00
VK_PRIMITIVE_TOPOLOGY_POINT_LIST ,
0 ,
VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineRasterizationStateCreateInfo (
2016-11-26 13:52:22 +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-11-26 13:52:22 +01:00
0xf ,
VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineColorBlendStateCreateInfo (
2016-11-26 13:52:22 +01:00
1 ,
& blendAttachmentState ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineDepthStencilStateCreateInfo (
2016-11-26 13:52:22 +01:00
VK_FALSE ,
VK_FALSE ,
VK_COMPARE_OP_ALWAYS ) ;
VkPipelineViewportStateCreateInfo viewportState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 , 0 ) ;
2016-11-26 13:52:22 +01:00
VkPipelineMultisampleStateCreateInfo multisampleState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineMultisampleStateCreateInfo (
2016-11-26 13:52:22 +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-11-26 13:52:22 +01:00
dynamicStateEnables . data ( ) ,
static_cast < uint32_t > ( dynamicStateEnables . size ( ) ) ,
0 ) ;
// Rendering pipeline
// Load shaders
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2020-05-29 16:08:53 +01:00
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " computenbody/particle.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " computenbody/particle.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2016-11-26 13:52:22 +01:00
VkGraphicsPipelineCreateInfo pipelineCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineCreateInfo (
2016-11-26 13:52:22 +01:00
graphics . 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 ;
pipelineCreateInfo . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
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 ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & graphics . pipeline ) ) ;
}
2019-06-17 19:31:00 +08: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 ) ) ;
}
2016-11-26 13:52:22 +01:00
void prepareCompute ( )
{
// Create a compute capable device queue
// 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,
// requiring proper synchronization (see the memory barriers in buildComputeCommandBuffer)
2020-02-22 12:20:30 +01:00
vkGetDeviceQueue ( device , compute . queueFamilyIndex , 0 , & compute . queue ) ;
2016-11-26 13:52:22 +01:00
// Create compute pipeline
// Compute pipelines are created separate from graphics pipelines even if they use the same queue (family index)
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
// Binding 0 : Particle position storage buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2016-11-26 13:52:22 +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-11-26 13:52:22 +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-11-26 13:52:22 +01:00
setLayoutBindings . data ( ) ,
static_cast < uint32_t > ( setLayoutBindings . size ( ) ) ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & compute . descriptorSetLayout ) ) ;
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineLayoutCreateInfo (
2016-11-26 13:52:22 +01:00
& compute . descriptorSetLayout ,
1 ) ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & compute . pipelineLayout ) ) ;
VkDescriptorSetAllocateInfo allocInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetAllocateInfo (
2016-11-26 13:52:22 +01:00
descriptorPool ,
& compute . descriptorSetLayout ,
1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & compute . descriptorSet ) ) ;
std : : vector < VkWriteDescriptorSet > computeWriteDescriptorSets =
{
// Binding 0 : Particle position storage buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-11-26 13:52:22 +01:00
compute . descriptorSet ,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ,
0 ,
& compute . storageBuffer . descriptor ) ,
// Binding 1 : Uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-11-26 13:52:22 +01:00
compute . descriptorSet ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
1 ,
& compute . uniformBuffer . descriptor )
} ;
2020-02-22 12:20:30 +01:00
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( computeWriteDescriptorSets . size ( ) ) , computeWriteDescriptorSets . data ( ) , 0 , nullptr ) ;
2016-11-26 13:52:22 +01:00
// Create pipelines
2017-02-12 11:12:42 +01:00
VkComputePipelineCreateInfo computePipelineCreateInfo = vks : : initializers : : computePipelineCreateInfo ( compute . pipelineLayout , 0 ) ;
2016-11-26 13:52:22 +01:00
// 1st pass
2020-05-29 16:08:53 +01:00
computePipelineCreateInfo . stage = loadShader ( getShadersPath ( ) + " computenbody/particle_calculate.comp.spv " , VK_SHADER_STAGE_COMPUTE_BIT ) ;
2016-11-26 13:52:22 +01:00
// Set shader parameters via specialization constants
struct SpecializationData {
uint32_t sharedDataSize ;
float gravity ;
float power ;
float soften ;
} specializationData ;
std : : vector < VkSpecializationMapEntry > specializationMapEntries ;
2017-02-12 11:12:42 +01:00
specializationMapEntries . push_back ( vks : : initializers : : specializationMapEntry ( 0 , offsetof ( SpecializationData , sharedDataSize ) , sizeof ( uint32_t ) ) ) ;
specializationMapEntries . push_back ( vks : : initializers : : specializationMapEntry ( 1 , offsetof ( SpecializationData , gravity ) , sizeof ( float ) ) ) ;
specializationMapEntries . push_back ( vks : : initializers : : specializationMapEntry ( 2 , offsetof ( SpecializationData , power ) , sizeof ( float ) ) ) ;
specializationMapEntries . push_back ( vks : : initializers : : specializationMapEntry ( 3 , offsetof ( SpecializationData , soften ) , sizeof ( float ) ) ) ;
2016-11-26 13:52:22 +01:00
2016-11-27 13:27:11 +01:00
specializationData . sharedDataSize = std : : min ( ( uint32_t ) 1024 , ( uint32_t ) ( vulkanDevice - > properties . limits . maxComputeSharedMemorySize / sizeof ( glm : : vec4 ) ) ) ;
2016-11-26 13:56:17 +01:00
specializationData . gravity = 0.002f ;
specializationData . power = 0.75f ;
specializationData . soften = 0.05f ;
2016-11-26 13:52:22 +01:00
2020-05-29 16:08:53 +01:00
VkSpecializationInfo specializationInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : specializationInfo ( static_cast < uint32_t > ( specializationMapEntries . size ( ) ) , specializationMapEntries . data ( ) , sizeof ( specializationData ) , & specializationData ) ;
2016-11-26 13:52:22 +01:00
computePipelineCreateInfo . stage . pSpecializationInfo = & specializationInfo ;
VK_CHECK_RESULT ( vkCreateComputePipelines ( device , pipelineCache , 1 , & computePipelineCreateInfo , nullptr , & compute . pipelineCalculate ) ) ;
// 2nd pass
2020-05-29 16:08:53 +01:00
computePipelineCreateInfo . stage = loadShader ( getShadersPath ( ) + " computenbody/particle_integrate.comp.spv " , VK_SHADER_STAGE_COMPUTE_BIT ) ;
2016-11-26 13:52:22 +01:00
VK_CHECK_RESULT ( vkCreateComputePipelines ( device , pipelineCache , 1 , & computePipelineCreateInfo , nullptr , & compute . pipelineIntegrate ) ) ;
// 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 12:20:30 +01:00
cmdPoolInfo . queueFamilyIndex = compute . queueFamilyIndex ;
2016-11-26 13:52:22 +01:00
cmdPoolInfo . flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT ;
VK_CHECK_RESULT ( vkCreateCommandPool ( device , & cmdPoolInfo , nullptr , & compute . commandPool ) ) ;
// Create a command buffer for compute operations
2020-02-22 12:32:17 +01:00
compute . commandBuffer = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , compute . commandPool ) ;
2016-11-26 13:52:22 +01:00
2019-06-17 19:31:00 +08:00
// Semaphore for compute & graphics sync
VkSemaphoreCreateInfo semaphoreCreateInfo = vks : : initializers : : semaphoreCreateInfo ( ) ;
VK_CHECK_RESULT ( vkCreateSemaphore ( device , & semaphoreCreateInfo , nullptr , & compute . semaphore ) ) ;
// Signal the semaphore
2020-02-22 14:38:53 +01:00
VkSubmitInfo submitInfo = vks : : initializers : : submitInfo ( ) ;
2019-06-17 19:31:00 +08:00
submitInfo . signalSemaphoreCount = 1 ;
submitInfo . pSignalSemaphores = & compute . semaphore ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VK_CHECK_RESULT ( vkQueueWaitIdle ( queue ) ) ;
2016-11-26 13:52:22 +01:00
// Build a single command buffer containing the compute dispatch commands
buildComputeCommandBuffer ( ) ;
2020-02-22 12:20:30 +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
if ( graphics . queueFamilyIndex ! = compute . queueFamilyIndex )
2020-05-29 16:08:53 +01:00
{
2020-02-22 12:20:30 +01:00
// 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 ) ;
}
2016-11-26 13:52:22 +01:00
}
// Prepare and initialize uniform buffer containing shader uniforms
void prepareUniformBuffers ( )
{
// Compute shader uniform buffer block
vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& compute . uniformBuffer ,
sizeof ( compute . ubo ) ) ;
// Map for host access
VK_CHECK_RESULT ( compute . uniformBuffer . map ( ) ) ;
// Vertex shader uniform buffer block
vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& graphics . uniformBuffer ,
sizeof ( graphics . ubo ) ) ;
// Map for host access
VK_CHECK_RESULT ( graphics . uniformBuffer . map ( ) ) ;
2019-02-28 19:41:13 +01:00
updateComputeUniformBuffers ( ) ;
2016-11-26 13:52:22 +01:00
updateGraphicsUniformBuffers ( ) ;
}
2019-02-28 19:41:13 +01:00
void updateComputeUniformBuffers ( )
2016-11-26 13:52:22 +01:00
{
compute . ubo . deltaT = paused ? 0.0f : frameTimer * 0.05f ;
memcpy ( compute . uniformBuffer . mapped , & compute . ubo , sizeof ( compute . ubo ) ) ;
}
void updateGraphicsUniformBuffers ( )
{
graphics . ubo . projection = camera . matrices . perspective ;
graphics . ubo . view = camera . matrices . view ;
2016-11-26 14:43:24 +01:00
graphics . ubo . screenDim = glm : : vec2 ( ( float ) width , ( float ) height ) ;
2016-11-26 13:52:22 +01:00
memcpy ( graphics . uniformBuffer . mapped , & graphics . ubo , sizeof ( graphics . ubo ) ) ;
}
void draw ( )
{
VulkanExampleBase : : prepareFrame ( ) ;
2019-06-17 19:31:00 +08: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 } ;
// Submit graphics commands
2016-11-26 13:52:22 +01:00
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
2019-06-17 19:31:00 +08:00
submitInfo . waitSemaphoreCount = 2 ;
submitInfo . pWaitSemaphores = graphicsWaitSemaphores ;
submitInfo . pWaitDstStageMask = graphicsWaitStageMasks ;
submitInfo . signalSemaphoreCount = 2 ;
submitInfo . pSignalSemaphores = graphicsSignalSemaphores ;
2016-11-26 13:52:22 +01:00
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
2019-06-17 19:31:00 +08:00
// Wait for rendering finished
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ;
2016-11-26 13:52:22 +01:00
2019-06-17 19:31:00 +08:00
// Submit compute commands
2017-02-12 11:12:42 +01:00
VkSubmitInfo computeSubmitInfo = vks : : initializers : : submitInfo ( ) ;
2016-11-26 13:52:22 +01:00
computeSubmitInfo . commandBufferCount = 1 ;
computeSubmitInfo . pCommandBuffers = & compute . commandBuffer ;
2019-06-17 19:31:00 +08:00
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 ) ) ;
2016-11-26 13:52:22 +01:00
}
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2020-02-22 12:20:30 +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-11-26 13:52:22 +01:00
setupDescriptorPool ( ) ;
2019-06-17 19:31:00 +08:00
prepareGraphics ( ) ;
2016-11-26 13:52:22 +01:00
prepareCompute ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
2019-02-28 19:41:13 +01:00
updateComputeUniformBuffers ( ) ;
if ( camera . updated ) {
updateGraphicsUniformBuffers ( ) ;
}
2016-11-26 13:52:22 +01:00
}
} ;
VULKAN_EXAMPLE_MAIN ( )