Visual Update for computeparticles
Instead of using a small amount of large textured particles, use a large amount of small monochrome particles. Which uses a new vulkanexamplebase functionality of creating and updating a only device visible buffer via a temporary staging buffer.
This commit is contained in:
parent
eb428db92d
commit
5d7014b221
9 changed files with 203 additions and 209 deletions
|
|
@ -283,6 +283,97 @@ VkPipelineShaderStageCreateInfo VulkanExampleBase::loadShader(std::string fileNa
|
||||||
return shaderStage;
|
return shaderStage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkBool32 VulkanExampleBase::createDeviceBuffer(
|
||||||
|
const VkBufferUsageFlags usage,
|
||||||
|
const VkDeviceSize size,
|
||||||
|
VkBuffer& buffer,
|
||||||
|
VkDeviceMemory& memory,
|
||||||
|
VkDescriptorBufferInfo& descriptor)
|
||||||
|
{
|
||||||
|
VkMemoryRequirements memReqs;
|
||||||
|
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
||||||
|
VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT, size);
|
||||||
|
|
||||||
|
VkResult err = vkCreateBuffer(device, &bufferCreateInfo, nullptr, &buffer);
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
vkGetBufferMemoryRequirements(device, buffer, &memReqs);
|
||||||
|
memAlloc.allocationSize = memReqs.size;
|
||||||
|
|
||||||
|
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex);
|
||||||
|
|
||||||
|
err = vkAllocateMemory(device, &memAlloc, nullptr, &memory);
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
err = vkBindBufferMemory(device, buffer, memory, 0);
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
descriptor.offset = 0;
|
||||||
|
descriptor.buffer = buffer;
|
||||||
|
descriptor.range = size;
|
||||||
|
|
||||||
|
return VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBool32 VulkanExampleBase::updateDeviceBuffer(
|
||||||
|
const VkDeviceSize size,
|
||||||
|
VkBuffer& deviceBuffer,
|
||||||
|
void* data)
|
||||||
|
{
|
||||||
|
//todo check that size is not larger than memory size
|
||||||
|
|
||||||
|
// create staging buffer and copy data to it
|
||||||
|
VkMemoryRequirements memReqs;
|
||||||
|
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
||||||
|
VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, size);
|
||||||
|
VkBuffer stagingBuffer;
|
||||||
|
VkDeviceMemory stagingMemory;
|
||||||
|
|
||||||
|
VkResult err = vkCreateBuffer(device, &bufferCreateInfo, nullptr, &stagingBuffer);
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs);
|
||||||
|
memAlloc.allocationSize = memReqs.size;
|
||||||
|
|
||||||
|
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex);
|
||||||
|
|
||||||
|
err = vkAllocateMemory(device, &memAlloc, nullptr, &stagingMemory);
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
if (data != nullptr)
|
||||||
|
{
|
||||||
|
void* mapped;
|
||||||
|
err = vkMapMemory(device, stagingMemory, 0, size, 0, &mapped);
|
||||||
|
assert(!err);
|
||||||
|
memcpy(mapped, data, size);
|
||||||
|
vkUnmapMemory(device, stagingMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0);
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
// create cmdbuffer to copy staging buffer to device local buffer
|
||||||
|
createSetupCommandBuffer();
|
||||||
|
|
||||||
|
VkBufferCopy copyRegion = {};
|
||||||
|
copyRegion.size = size;
|
||||||
|
|
||||||
|
vkCmdCopyBuffer(
|
||||||
|
setupCmdBuffer,
|
||||||
|
stagingBuffer,
|
||||||
|
deviceBuffer,
|
||||||
|
1,
|
||||||
|
©Region);
|
||||||
|
|
||||||
|
flushSetupCommandBuffer();
|
||||||
|
|
||||||
|
// free staging memory
|
||||||
|
vkDestroyBuffer(device, stagingBuffer, nullptr);
|
||||||
|
vkFreeMemory(device, stagingMemory, nullptr);
|
||||||
|
|
||||||
|
return VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
VkBool32 VulkanExampleBase::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, void * data, VkBuffer * buffer, VkDeviceMemory * memory)
|
VkBool32 VulkanExampleBase::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, void * data, VkBuffer * buffer, VkDeviceMemory * memory)
|
||||||
{
|
{
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs;
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,20 @@ public:
|
||||||
// Load a SPIR-V shader
|
// Load a SPIR-V shader
|
||||||
VkPipelineShaderStageCreateInfo loadShader(std::string fileName, VkShaderStageFlagBits stage);
|
VkPipelineShaderStageCreateInfo loadShader(std::string fileName, VkShaderStageFlagBits stage);
|
||||||
|
|
||||||
|
// create device local buffer and use staging to access
|
||||||
|
VkBool32 createDeviceBuffer(
|
||||||
|
const VkBufferUsageFlags usage,
|
||||||
|
const VkDeviceSize size,
|
||||||
|
VkBuffer& buffer,
|
||||||
|
VkDeviceMemory& memory,
|
||||||
|
VkDescriptorBufferInfo& descriptor);
|
||||||
|
|
||||||
|
// update loacal buffer memory by creating a host visible staging buffer
|
||||||
|
VkBool32 updateDeviceBuffer(
|
||||||
|
const VkDeviceSize size,
|
||||||
|
VkBuffer& deviceBuffer,
|
||||||
|
void* data);
|
||||||
|
|
||||||
// Create a buffer, fill it with data (if != NULL) and bind buffer memory
|
// Create a buffer, fill it with data (if != NULL) and bind buffer memory
|
||||||
VkBool32 createBuffer(
|
VkBool32 createBuffer(
|
||||||
VkBufferUsageFlags usageFlags,
|
VkBufferUsageFlags usageFlags,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#define GLM_FORCE_RADIANS
|
#define GLM_FORCE_RADIANS
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
|
@ -22,15 +23,15 @@
|
||||||
|
|
||||||
#define VERTEX_BUFFER_BIND_ID 0
|
#define VERTEX_BUFFER_BIND_ID 0
|
||||||
#define ENABLE_VALIDATION false
|
#define ENABLE_VALIDATION false
|
||||||
#define PARTICLE_COUNT 8 * 1024
|
#define PARTICLE_COUNT 3000 * 1024
|
||||||
|
|
||||||
class VulkanExample : public VulkanExampleBase
|
class VulkanExample : public VulkanExampleBase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
vkTools::VulkanTexture textureColorMap;
|
vkTools::VulkanTexture textureColorMap;
|
||||||
public:
|
public:
|
||||||
float timer = 0.0f;
|
float timer = 0.f;
|
||||||
float animStart = 50.0f;
|
float animStart = 20.0f;
|
||||||
bool animate = true;
|
bool animate = true;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -68,13 +69,11 @@ public:
|
||||||
} uniformData;
|
} uniformData;
|
||||||
|
|
||||||
struct Particle {
|
struct Particle {
|
||||||
glm::vec4 pos;
|
glm::vec2 pos;
|
||||||
glm::vec4 col;
|
glm::vec2 vel;
|
||||||
glm::vec4 vel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VkPipelineLayout pipelineLayout;
|
VkPipelineLayout pipelineLayout;
|
||||||
VkDescriptorSet descriptorSetPostCompute;
|
|
||||||
VkDescriptorSetLayout descriptorSetLayout;
|
VkDescriptorSetLayout descriptorSetLayout;
|
||||||
|
|
||||||
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||||
|
|
@ -103,17 +102,6 @@ public:
|
||||||
vkDestroyPipelineLayout(device, computePipelineLayout, nullptr);
|
vkDestroyPipelineLayout(device, computePipelineLayout, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, nullptr);
|
vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, nullptr);
|
||||||
vkDestroyPipeline(device, pipelines.compute, nullptr);
|
vkDestroyPipeline(device, pipelines.compute, nullptr);
|
||||||
|
|
||||||
textureLoader->destroyTexture(textureColorMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadTextures()
|
|
||||||
{
|
|
||||||
textureLoader->loadTexture(
|
|
||||||
getAssetPath() + "textures/particle01_rgba.ktx",
|
|
||||||
VK_FORMAT_R8G8B8A8_UNORM,
|
|
||||||
&textureColorMap,
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildCommandBuffers()
|
void buildCommandBuffers()
|
||||||
|
|
@ -151,7 +139,7 @@ public:
|
||||||
assert(!err);
|
assert(!err);
|
||||||
|
|
||||||
// Buffer memory barrier to make sure that compute shader
|
// Buffer memory barrier to make sure that compute shader
|
||||||
// writes are finished before using the storage buffer
|
// writes are finished before using the storage buffer
|
||||||
// in the vertex shader
|
// in the vertex shader
|
||||||
VkBufferMemoryBarrier bufferBarrier = vkTools::initializers::bufferMemoryBarrier();
|
VkBufferMemoryBarrier bufferBarrier = vkTools::initializers::bufferMemoryBarrier();
|
||||||
// Source access : Compute shader buffer write
|
// Source access : Compute shader buffer write
|
||||||
|
|
@ -191,7 +179,6 @@ public:
|
||||||
);
|
);
|
||||||
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
|
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
|
||||||
|
|
||||||
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSetPostCompute, 0, NULL);
|
|
||||||
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.postCompute);
|
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.postCompute);
|
||||||
|
|
||||||
VkDeviceSize offsets[1] = { 0 };
|
VkDeviceSize offsets[1] = { 0 };
|
||||||
|
|
@ -243,9 +230,6 @@ public:
|
||||||
err = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete);
|
err = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete);
|
||||||
assert(!err);
|
assert(!err);
|
||||||
|
|
||||||
err = vkQueueWaitIdle(queue);
|
|
||||||
assert(!err);
|
|
||||||
|
|
||||||
// Compute
|
// Compute
|
||||||
VkSubmitInfo computeSubmitInfo = vkTools::initializers::submitInfo();
|
VkSubmitInfo computeSubmitInfo = vkTools::initializers::submitInfo();
|
||||||
computeSubmitInfo.commandBufferCount = 1;
|
computeSubmitInfo.commandBufferCount = 1;
|
||||||
|
|
@ -254,6 +238,9 @@ public:
|
||||||
err = vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE);
|
err = vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE);
|
||||||
assert(!err);
|
assert(!err);
|
||||||
|
|
||||||
|
err = vkQueueWaitIdle(queue);
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
err = vkQueueWaitIdle(computeQueue);
|
err = vkQueueWaitIdle(computeQueue);
|
||||||
assert(!err);
|
assert(!err);
|
||||||
}
|
}
|
||||||
|
|
@ -262,93 +249,25 @@ public:
|
||||||
// vertex positions and velocities
|
// vertex positions and velocities
|
||||||
void prepareStorageBuffers()
|
void prepareStorageBuffers()
|
||||||
{
|
{
|
||||||
float destPosX = 0.0f;
|
|
||||||
float destPosY = 0.0f;
|
std::mt19937 rGenerator;
|
||||||
|
std::uniform_real_distribution<float> rDistribution(-1.f, 1.f);
|
||||||
|
|
||||||
// Initial particle positions
|
// Initial particle positions
|
||||||
std::vector<Particle> particleBuffer;
|
std::vector<Particle> particleBuffer(PARTICLE_COUNT);
|
||||||
for (int i = 0; i < PARTICLE_COUNT; ++i)
|
for (auto& element : particleBuffer)
|
||||||
{
|
{
|
||||||
// Position
|
element.pos = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator));
|
||||||
float aspectRatio = (float)height / (float)width;
|
element.vel = glm::vec2(0.f);
|
||||||
float rndVal = (float)rand() / (float)(RAND_MAX / (360.0f * 3.14f * 2.0f));
|
|
||||||
float rndRad = (float)rand() / (float)(RAND_MAX) * 0.5f;
|
|
||||||
Particle p;
|
|
||||||
p.pos = glm::vec4(
|
|
||||||
destPosX + cos(rndVal) * rndRad * aspectRatio,
|
|
||||||
destPosY + sin(rndVal) * rndRad,
|
|
||||||
0.0f,
|
|
||||||
1.0f);
|
|
||||||
p.col = glm::vec4(
|
|
||||||
(float)(rand() % 255) / 255.0f,
|
|
||||||
(float)(rand() % 255) / 255.0f,
|
|
||||||
(float)(rand() % 255) / 255.0f,
|
|
||||||
1.0f);
|
|
||||||
p.vel = glm::vec4(0.0f);
|
|
||||||
particleBuffer.push_back(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer size is the same for all storage buffers
|
// Buffer size is the same for all storage buffers
|
||||||
uint32_t storageBufferSize = particleBuffer.size() * sizeof(Particle);
|
uint32_t storageBufferSize = particleBuffer.size() * sizeof(Particle);
|
||||||
|
|
||||||
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
createDeviceBuffer(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, storageBufferSize, computeStorageBuffer.buffer,
|
||||||
VkMemoryRequirements memReqs;
|
computeStorageBuffer.memory, computeStorageBuffer.descriptor);
|
||||||
|
|
||||||
VkResult err;
|
updateDeviceBuffer(storageBufferSize, computeStorageBuffer.buffer, particleBuffer.data());
|
||||||
void *data;
|
|
||||||
|
|
||||||
struct StagingBuffer {
|
|
||||||
VkDeviceMemory memory;
|
|
||||||
VkBuffer buffer;
|
|
||||||
} stagingBuffer;
|
|
||||||
|
|
||||||
// Allocate and fill host-visible staging storage buffer object
|
|
||||||
|
|
||||||
// Allocate and fill storage buffer object
|
|
||||||
VkBufferCreateInfo vBufferInfo =
|
|
||||||
vkTools::initializers::bufferCreateInfo(
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
||||||
storageBufferSize);
|
|
||||||
vkTools::checkResult(vkCreateBuffer(device, &vBufferInfo, nullptr, &stagingBuffer.buffer));
|
|
||||||
vkGetBufferMemoryRequirements(device, stagingBuffer.buffer, &memReqs);
|
|
||||||
memAlloc.allocationSize = memReqs.size;
|
|
||||||
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex);
|
|
||||||
vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, &stagingBuffer.memory));
|
|
||||||
vkTools::checkResult(vkMapMemory(device, stagingBuffer.memory, 0, storageBufferSize, 0, &data));
|
|
||||||
memcpy(data, particleBuffer.data(), storageBufferSize);
|
|
||||||
vkUnmapMemory(device, stagingBuffer.memory);
|
|
||||||
vkTools::checkResult(vkBindBufferMemory(device, stagingBuffer.buffer, stagingBuffer.memory, 0));
|
|
||||||
|
|
||||||
// Allocate device local storage buffer ojbect
|
|
||||||
vBufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
|
||||||
vkTools::checkResult(vkCreateBuffer(device, &vBufferInfo, nullptr, &computeStorageBuffer.buffer));
|
|
||||||
vkGetBufferMemoryRequirements(device, computeStorageBuffer.buffer, &memReqs);
|
|
||||||
memAlloc.allocationSize = memReqs.size;
|
|
||||||
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex);
|
|
||||||
vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, &computeStorageBuffer.memory));
|
|
||||||
vkTools::checkResult(vkBindBufferMemory(device, computeStorageBuffer.buffer, computeStorageBuffer.memory, 0));
|
|
||||||
|
|
||||||
// Copy from host to device
|
|
||||||
createSetupCommandBuffer();
|
|
||||||
|
|
||||||
VkBufferCopy copyRegion = {};
|
|
||||||
copyRegion.size = storageBufferSize;
|
|
||||||
vkCmdCopyBuffer(
|
|
||||||
setupCmdBuffer,
|
|
||||||
stagingBuffer.buffer,
|
|
||||||
computeStorageBuffer.buffer,
|
|
||||||
1,
|
|
||||||
©Region);
|
|
||||||
|
|
||||||
flushSetupCommandBuffer();
|
|
||||||
|
|
||||||
// Destroy staging buffer
|
|
||||||
vkDestroyBuffer(device, stagingBuffer.buffer, nullptr);
|
|
||||||
vkFreeMemory(device, stagingBuffer.memory, nullptr);
|
|
||||||
|
|
||||||
computeStorageBuffer.descriptor.buffer = computeStorageBuffer.buffer;
|
|
||||||
computeStorageBuffer.descriptor.offset = 0;
|
|
||||||
computeStorageBuffer.descriptor.range = storageBufferSize;
|
|
||||||
|
|
||||||
// Binding description
|
// Binding description
|
||||||
vertices.bindingDescriptions.resize(1);
|
vertices.bindingDescriptions.resize(1);
|
||||||
|
|
@ -360,7 +279,7 @@ public:
|
||||||
|
|
||||||
// Attribute descriptions
|
// Attribute descriptions
|
||||||
// Describes memory layout and shader positions
|
// Describes memory layout and shader positions
|
||||||
vertices.attributeDescriptions.resize(2);
|
vertices.attributeDescriptions.resize(1);
|
||||||
// Location 0 : Position
|
// Location 0 : Position
|
||||||
vertices.attributeDescriptions[0] =
|
vertices.attributeDescriptions[0] =
|
||||||
vkTools::initializers::vertexInputAttributeDescription(
|
vkTools::initializers::vertexInputAttributeDescription(
|
||||||
|
|
@ -368,13 +287,6 @@ public:
|
||||||
0,
|
0,
|
||||||
VK_FORMAT_R32G32B32A32_SFLOAT,
|
VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||||
0);
|
0);
|
||||||
// Location 1 : Color
|
|
||||||
vertices.attributeDescriptions[1] =
|
|
||||||
vkTools::initializers::vertexInputAttributeDescription(
|
|
||||||
VERTEX_BUFFER_BIND_ID,
|
|
||||||
1,
|
|
||||||
VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
||||||
sizeof(float) * 4);
|
|
||||||
|
|
||||||
// Assign to vertex buffer
|
// Assign to vertex buffer
|
||||||
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
|
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
|
||||||
|
|
@ -389,15 +301,14 @@ public:
|
||||||
std::vector<VkDescriptorPoolSize> poolSizes =
|
std::vector<VkDescriptorPoolSize> poolSizes =
|
||||||
{
|
{
|
||||||
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
||||||
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1),
|
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1)
|
||||||
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VkDescriptorPoolCreateInfo descriptorPoolInfo =
|
VkDescriptorPoolCreateInfo descriptorPoolInfo =
|
||||||
vkTools::initializers::descriptorPoolCreateInfo(
|
vkTools::initializers::descriptorPoolCreateInfo(
|
||||||
poolSizes.size(),
|
poolSizes.size(),
|
||||||
poolSizes.data(),
|
poolSizes.data(),
|
||||||
3);
|
2);
|
||||||
|
|
||||||
VkResult vkRes = vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool);
|
VkResult vkRes = vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool);
|
||||||
assert(!vkRes);
|
assert(!vkRes);
|
||||||
|
|
@ -405,63 +316,26 @@ public:
|
||||||
|
|
||||||
void setupDescriptorSetLayout()
|
void setupDescriptorSetLayout()
|
||||||
{
|
{
|
||||||
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings =
|
|
||||||
{
|
|
||||||
// Binding 0 : Fragment shader image sampler
|
|
||||||
vkTools::initializers::descriptorSetLayoutBinding(
|
|
||||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
||||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
||||||
0)
|
|
||||||
};
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutCreateInfo descriptorLayout =
|
VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo;
|
||||||
vkTools::initializers::descriptorSetLayoutCreateInfo(
|
descriptorLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
setLayoutBindings.data(),
|
descriptorLayoutInfo.pNext = NULL;
|
||||||
setLayoutBindings.size());
|
descriptorLayoutInfo.flags = 0;
|
||||||
|
descriptorLayoutInfo.bindingCount = 0;
|
||||||
|
descriptorLayoutInfo.pBindings = nullptr;
|
||||||
|
|
||||||
VkResult err = vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout);
|
VkResult err = vkCreateDescriptorSetLayout(device, &descriptorLayoutInfo, nullptr, &descriptorSetLayout);
|
||||||
assert(!err);
|
assert(!err);
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
|
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
|
||||||
vkTools::initializers::pipelineLayoutCreateInfo(
|
vkTools::initializers::pipelineLayoutCreateInfo(
|
||||||
&descriptorSetLayout,
|
&descriptorSetLayout,
|
||||||
1);
|
0);
|
||||||
|
|
||||||
err = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout);
|
err = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout);
|
||||||
assert(!err);
|
assert(!err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupDescriptorSet()
|
|
||||||
{
|
|
||||||
VkDescriptorSetAllocateInfo allocInfo =
|
|
||||||
vkTools::initializers::descriptorSetAllocateInfo(
|
|
||||||
descriptorPool,
|
|
||||||
&descriptorSetLayout,
|
|
||||||
1);
|
|
||||||
|
|
||||||
VkResult vkRes = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSetPostCompute);
|
|
||||||
assert(!vkRes);
|
|
||||||
|
|
||||||
// Image descriptor for the color map texture
|
|
||||||
VkDescriptorImageInfo texDescriptor =
|
|
||||||
vkTools::initializers::descriptorImageInfo(
|
|
||||||
textureColorMap.sampler,
|
|
||||||
textureColorMap.view,
|
|
||||||
VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
|
|
||||||
std::vector<VkWriteDescriptorSet> writeDescriptorSets =
|
|
||||||
{
|
|
||||||
// Binding 1 : Fragment shader image sampler
|
|
||||||
vkTools::initializers::writeDescriptorSet(
|
|
||||||
descriptorSetPostCompute,
|
|
||||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
||||||
0,
|
|
||||||
&texDescriptor)
|
|
||||||
};
|
|
||||||
|
|
||||||
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a separate command buffer for compute commands
|
// Create a separate command buffer for compute commands
|
||||||
void createComputeCommandBuffer()
|
void createComputeCommandBuffer()
|
||||||
{
|
{
|
||||||
|
|
@ -504,16 +378,16 @@ public:
|
||||||
|
|
||||||
VkPipelineDepthStencilStateCreateInfo depthStencilState =
|
VkPipelineDepthStencilStateCreateInfo depthStencilState =
|
||||||
vkTools::initializers::pipelineDepthStencilStateCreateInfo(
|
vkTools::initializers::pipelineDepthStencilStateCreateInfo(
|
||||||
VK_TRUE,
|
VK_FALSE,
|
||||||
VK_TRUE,
|
VK_FALSE,
|
||||||
VK_COMPARE_OP_LESS_OR_EQUAL);
|
VK_COMPARE_OP_ALWAYS);
|
||||||
|
|
||||||
VkPipelineViewportStateCreateInfo viewportState =
|
VkPipelineViewportStateCreateInfo viewportState =
|
||||||
vkTools::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
|
vkTools::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
|
||||||
|
|
||||||
VkPipelineMultisampleStateCreateInfo multisampleState =
|
VkPipelineMultisampleStateCreateInfo multisampleState =
|
||||||
vkTools::initializers::pipelineMultisampleStateCreateInfo(
|
vkTools::initializers::pipelineMultisampleStateCreateInfo(
|
||||||
VK_SAMPLE_COUNT_1_BIT,
|
VK_SAMPLE_COUNT_4_BIT,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
std::vector<VkDynamicState> dynamicStateEnables = {
|
std::vector<VkDynamicState> dynamicStateEnables = {
|
||||||
|
|
@ -650,27 +524,34 @@ public:
|
||||||
void prepareUniformBuffers()
|
void prepareUniformBuffers()
|
||||||
{
|
{
|
||||||
// Compute shader uniform buffer block
|
// Compute shader uniform buffer block
|
||||||
createBuffer(
|
createDeviceBuffer(
|
||||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
sizeof(computeUbo),
|
sizeof(computeUbo),
|
||||||
&computeUbo,
|
uniformData.computeShader.ubo.buffer,
|
||||||
&uniformData.computeShader.ubo.buffer,
|
uniformData.computeShader.ubo.memory,
|
||||||
&uniformData.computeShader.ubo.memory,
|
uniformData.computeShader.ubo.descriptor);
|
||||||
&uniformData.computeShader.ubo.descriptor);
|
updateDeviceBuffer(sizeof(computeUbo), uniformData.computeShader.ubo.buffer, &computeUbo);
|
||||||
|
|
||||||
updateUniformBuffers();
|
updateUniformBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateUniformBuffers()
|
void updateUniformBuffers()
|
||||||
{
|
{
|
||||||
computeUbo.deltaT = frameTimer * 5.0f;
|
computeUbo.deltaT = frameTimer * 4.0f;
|
||||||
computeUbo.destX = sin(glm::radians(timer*360.0)) * 0.75f;
|
if (animate) // tmp
|
||||||
computeUbo.destY = 0;
|
{
|
||||||
uint8_t *pData;
|
computeUbo.destX = sin(glm::radians(timer*360.0)) * 0.75f;
|
||||||
VkResult err = vkMapMemory(device, uniformData.computeShader.ubo.memory, 0, sizeof(computeUbo), 0, (void **)&pData);
|
computeUbo.destY = 0.f;
|
||||||
assert(!err);
|
}
|
||||||
memcpy(pData, &computeUbo, sizeof(computeUbo));
|
else
|
||||||
vkUnmapMemory(device, uniformData.computeShader.ubo.memory);
|
{
|
||||||
|
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);
|
||||||
|
computeUbo.destX = normalizedMx;
|
||||||
|
computeUbo.destY = normalizedMy;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDeviceBuffer(sizeof(computeUbo), uniformData.computeShader.ubo.buffer, &computeUbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find and create a compute capable device queue
|
// Find and create a compute capable device queue
|
||||||
|
|
@ -693,6 +574,8 @@ public:
|
||||||
assert(queueIndex < queueCount);
|
assert(queueIndex < queueCount);
|
||||||
|
|
||||||
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
||||||
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
queueCreateInfo.pNext = NULL;
|
||||||
queueCreateInfo.queueFamilyIndex = queueIndex;
|
queueCreateInfo.queueFamilyIndex = queueIndex;
|
||||||
queueCreateInfo.queueCount = 1;
|
queueCreateInfo.queueCount = 1;
|
||||||
vkGetDeviceQueue(device, queueIndex, 0, &computeQueue);
|
vkGetDeviceQueue(device, queueIndex, 0, &computeQueue);
|
||||||
|
|
@ -701,7 +584,6 @@ public:
|
||||||
void prepare()
|
void prepare()
|
||||||
{
|
{
|
||||||
VulkanExampleBase::prepare();
|
VulkanExampleBase::prepare();
|
||||||
loadTextures();
|
|
||||||
getComputeQueue();
|
getComputeQueue();
|
||||||
createComputeCommandBuffer();
|
createComputeCommandBuffer();
|
||||||
prepareStorageBuffers();
|
prepareStorageBuffers();
|
||||||
|
|
@ -709,7 +591,6 @@ public:
|
||||||
setupDescriptorSetLayout();
|
setupDescriptorSetLayout();
|
||||||
preparePipelines();
|
preparePipelines();
|
||||||
setupDescriptorPool();
|
setupDescriptorPool();
|
||||||
setupDescriptorSet();
|
|
||||||
prepareCompute();
|
prepareCompute();
|
||||||
buildCommandBuffers();
|
buildCommandBuffers();
|
||||||
buildComputeCommandBuffer();
|
buildComputeCommandBuffer();
|
||||||
|
|
@ -723,16 +604,18 @@ public:
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
draw();
|
draw();
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
if (animStart > 0.0f)
|
|
||||||
|
if (animate)
|
||||||
{
|
{
|
||||||
animStart -= frameTimer * 5.0f;
|
if (animStart > 0.0f)
|
||||||
}
|
|
||||||
if ((animate) & (animStart <= 0.0f))
|
|
||||||
{
|
|
||||||
timer += frameTimer * 0.1f;
|
|
||||||
if (timer > 1.0)
|
|
||||||
{
|
{
|
||||||
timer -= 1.0f;
|
animStart -= frameTimer * 5.0f;
|
||||||
|
}
|
||||||
|
else if (animStart <= 0.0f)
|
||||||
|
{
|
||||||
|
timer += frameTimer * 0.04f;
|
||||||
|
if (timer > 1.f)
|
||||||
|
timer = 0.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateUniformBuffers();
|
updateUniformBuffers();
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,8 @@
|
||||||
|
|
||||||
struct Particle
|
struct Particle
|
||||||
{
|
{
|
||||||
vec4 pos;
|
vec2 pos;
|
||||||
vec4 col;
|
vec2 vel;
|
||||||
vec4 vel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Binding 0 : Position storage buffer
|
// Binding 0 : Position storage buffer
|
||||||
|
|
@ -26,14 +25,21 @@ layout (binding = 1) uniform UBO
|
||||||
int particleCount;
|
int particleCount;
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
vec3 attraction(vec3 pos, vec3 attractPos)
|
vec2 attraction(vec2 pos, vec2 attractPos)
|
||||||
{
|
{
|
||||||
vec3 delta = attractPos - pos;
|
vec2 delta = attractPos - pos;
|
||||||
const float damp = 0.5;
|
const float damp = 0.5;
|
||||||
float dDampedDot = dot(delta, delta) + damp;
|
float dDampedDot = dot(delta, delta) + damp;
|
||||||
float invDist = 1.0f / sqrt(dDampedDot);
|
float invDist = 1.0f / sqrt(dDampedDot);
|
||||||
float invDistCubed = invDist*invDist*invDist;
|
float invDistCubed = invDist*invDist*invDist;
|
||||||
return delta * invDistCubed * 0.00035;
|
return delta * invDistCubed * 0.0035;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 repulsion(vec2 pos, vec2 attractPos)
|
||||||
|
{
|
||||||
|
vec2 delta = attractPos - pos;
|
||||||
|
float targetDistance = sqrt(dot(delta, delta));
|
||||||
|
return delta * (1.0 / (targetDistance * targetDistance * targetDistance)) * -0.000035;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
|
|
@ -45,22 +51,25 @@ void main()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Read position and velocity
|
// Read position and velocity
|
||||||
vec3 vPos = particles[index].pos.xyz;
|
vec2 vVel = particles[index].vel.xy;
|
||||||
vec3 vVel = particles[index].vel.xyz;
|
vec2 vPos = particles[index].pos.xy;
|
||||||
|
|
||||||
vec3 destPos = vec3(ubo.destX, ubo.destY, 0.0);
|
vec2 destPos = vec2(ubo.destX, ubo.destY);
|
||||||
|
|
||||||
|
vec2 delta = destPos - vPos;
|
||||||
|
float targetDistance = sqrt(dot(delta, delta));
|
||||||
|
vVel += repulsion(vPos, destPos.xy) * 0.05;
|
||||||
|
|
||||||
// Calculate new velocity depending on attraction point
|
|
||||||
vVel += attraction(vPos, destPos.xyz);
|
|
||||||
|
|
||||||
// Move by velocity
|
// Move by velocity
|
||||||
vPos += vVel * ubo.deltaT;
|
vPos += vVel * ubo.deltaT;
|
||||||
|
|
||||||
if ((vPos.x < -1.0) || (vPos.x > 1.0))
|
// collide with boundary
|
||||||
vVel.x -= vVel.x;
|
if ((vPos.x < -1.0) || (vPos.x > 1.0) || (vPos.y < -1.0) || (vPos.y > 1.0))
|
||||||
|
vVel = (-vVel * 0.1) + attraction(vPos, destPos) * 12;
|
||||||
|
else
|
||||||
|
particles[index].pos.xy = vPos;
|
||||||
|
|
||||||
// Write back
|
// Write back
|
||||||
particles[index].pos.xyz = vPos;
|
particles[index].vel.xy = vVel;
|
||||||
particles[index].vel.xyz = vVel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -3,13 +3,11 @@
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
#extension GL_ARB_shading_language_420pack : enable
|
#extension GL_ARB_shading_language_420pack : enable
|
||||||
|
|
||||||
layout (binding = 0) uniform sampler2D sColorMap;
|
|
||||||
|
|
||||||
layout (location = 0) in vec4 inColor;
|
layout (location = 0) in vec4 inColor;
|
||||||
|
|
||||||
layout (location = 0) out vec4 outFragColor;
|
layout (location = 0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main ()
|
void main ()
|
||||||
{
|
{
|
||||||
outFragColor = texture(sColorMap, gl_PointCoord) * inColor;
|
outFragColor = inColor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -4,13 +4,12 @@
|
||||||
#extension GL_ARB_shading_language_420pack : enable
|
#extension GL_ARB_shading_language_420pack : enable
|
||||||
|
|
||||||
layout (location = 0) in vec4 inPos;
|
layout (location = 0) in vec4 inPos;
|
||||||
layout (location = 1) in vec4 inColor;
|
|
||||||
|
|
||||||
layout (location = 0) out vec4 outColor;
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main ()
|
void main ()
|
||||||
{
|
{
|
||||||
gl_PointSize = 32.0;
|
gl_PointSize = 1.0;
|
||||||
outColor = inColor;
|
outColor = vec4(0.035);
|
||||||
gl_Position = vec4(inPos.xyz, 1.0);
|
gl_Position = vec4(inPos.xy, 1.0, 1.0);
|
||||||
}
|
}
|
||||||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue