Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project 6: Kaixiang Miao #18

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,32 @@ Vulkan Flocking: compute and shading in one pipeline!

**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 6**

* (TODO) YOUR NAME HERE
Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab)
* Kaixiang Miao
* Tested on: Windows 7, i7-3630QM @ 2.40GHz 8GB, GTX 660M 2GB (Lenovo Y580 laptop, personal computer)

### (TODO: Your README)
### ScreenShots

![](img/72.gif)


### Analysis

* Why do you think Vulkan expects explicit descriptors for things like generating pipelines and commands?

Vulkan is a explicit low-level graphics API. It uses command buffer pool, which stores the pre-allocated command buffers. Thus, in order to use these buffers correctly, descriptors are needed to be bound to them so that GPU knows which buffer to use and what the memory layout is.

* Describe a situation besides flip-flop buffers in which you may need multiple descriptor sets to fit one descriptor layout.

For example, we can use different descriptor sets to describe different texture buffers. Thus we can bind the texture we want into the pipeline.

* What are some problems to keep in mind when using multiple Vulkan queues?

When using multiple Vulkan queues, synchronization is important. Race-condition occurs when different queues are requesting the same memory. In this situation, one queue must wait for the other one until it stop occupying the buffers. Programmers has to deal with these issues correctly and it's the thing we should keep in mind.

* What is one advantage of using compute commands that can share data with a rendering pipeline?

Save time spent on I/O since you can reuse the data.

Include screenshots, analysis, etc. (Remember, this is public, so don't put
anything here that you don't want to share with the world.)

### Credits

Expand Down
1 change: 1 addition & 0 deletions data/shaders/computeparticles/generate-spirv.bat
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
glslangvalidator -V particle.frag -o particle.frag.spv
glslangvalidator -V particle.vert -o particle.vert.spv
glslangvalidator -V particle.comp -o particle.comp.spv
pause


52 changes: 51 additions & 1 deletion data/shaders/computeparticles/particle.comp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,58 @@ void main()
vec2 vPos = particlesA[index].pos.xy;
vec2 vVel = particlesA[index].vel.xy;

vec2 v1 = vec2(0.0, 0.0);
vec2 v2 = vec2(0.0, 0.0);
vec2 v3 = vec2(0.0, 0.0);
int counter1 = 0;
int counter3 = 0;
float test = 0.0;
float ttt;
for (int i = 0; i < ubo.particleCount; i++)
{
if (i != index)
{
float distance = length(particlesA[i].pos.xy - vPos.xy);
if (distance < ubo.rule1Distance)
{
v1 += particlesA[i].pos.xy;
test += 1.0;
counter1++;
}

if (distance < ubo.rule2Distance)
{
v2 -= particlesA[i].pos.xy - vPos.xy;
}

if (distance < ubo.rule3Distance)
{
v3 += particlesA[i].vel.xy;
counter3++;
}
ttt = distance;
}
}
if (counter1 != 0)
{
v1 /= counter1;
v1 = (v1 - vPos) * ubo.rule1Scale;
}

v2 *= ubo.rule2Scale;

if (counter3 != 0)
{
v3 /= counter3;
v3 = (v3 - vVel) * ubo.rule3Scale;
}

vVel = v1 + v2 + v3;
//vVel = vec2(test/ 1000.0, 0.0);
//vVel = v3;

// clamp velocity for a more pleasing simulation.
vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1);
vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.5);

// kinematic update
vPos += vVel * ubo.deltaT;
Expand Down
Binary file modified data/shaders/computeparticles/particle.comp.spv
Binary file not shown.
Binary file added img/72.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 29 additions & 8 deletions vulkanBoids/vulkanBoids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
#define RULE1DISTANCE 0.1f // cohesion
#define RULE2DISTANCE 0.05f // separation
#define RULE3DISTANCE 0.05f // alignment
#define RULE1SCALE 0.02f
#define RULE2SCALE 0.05f
#define RULE3SCALE 0.01f
#define RULE1SCALE 2.0f
#define RULE2SCALE 0.1f
#define RULE3SCALE 0.9f

class VulkanExample : public VulkanExampleBase
{
Expand Down Expand Up @@ -157,6 +157,7 @@ class VulkanExample : public VulkanExampleBase
for (auto& particle : particleBuffer)
{
particle.pos = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator));
particle.vel = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator));
// TODO: add randomized velocities with a slight scale here, something like 0.1f.
}

Expand Down Expand Up @@ -244,7 +245,7 @@ class VulkanExample : public VulkanExampleBase
VERTEX_BUFFER_BIND_ID,
1,
VK_FORMAT_R32G32_SFLOAT,
offsetof(Particle, pos)); // TODO: change this so that we can color the particles based on velocity.
offsetof(Particle, vel)); // TODO: change this so that we can color the particles based on velocity.

// vertices.inputState encapsulates everything we need for these particular buffers to
// interface with the graphics pipeline.
Expand All @@ -254,7 +255,7 @@ class VulkanExample : public VulkanExampleBase
vertices.inputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertices.attributeDescriptions.size());
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
}

// Prepare and initialize uniform buffer containing shader uniforms for compute
void prepareUniformBuffers()
{
Expand Down Expand Up @@ -517,7 +518,7 @@ class VulkanExample : public VulkanExampleBase
{
// LOOK
// WriteDescriptorSet writes each of these descriptors into the specified descriptorSet.
// THese first few are written into compute.descriptorSet[0].
// These first few are written into compute.descriptorSet[0].
// Each of these corresponds to a layout binding in the descriptor set layout,
// which in turn corresponds with something like `layout(std140, binding = 0)` in `particle.comp`.

Expand All @@ -540,8 +541,27 @@ class VulkanExample : public VulkanExampleBase
compute.descriptorSets[0],
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
2,
&compute.uniformBuffer.descriptor)
&compute.uniformBuffer.descriptor),

vkTools::initializers::writeDescriptorSet(
compute.descriptorSets[1], // LOOK: which descriptor set to write to?
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
0, // LOOK: which binding in the descriptor set Layout?
&compute.storageBufferB.descriptor), // LOOK: which SSBO?

// Binding 1 : Particle position storage buffer
vkTools::initializers::writeDescriptorSet(
compute.descriptorSets[1],
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
1,
&compute.storageBufferA.descriptor),

// Binding 2 : Uniform buffer
vkTools::initializers::writeDescriptorSet(
compute.descriptorSets[1],
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
2,
&compute.uniformBuffer.descriptor)
// TODO: write the second descriptorSet, using the top for reference.
// We want the descriptorSets to be used for flip-flopping:
// on one frame, we use one descriptorSet with the compute pass,
Expand Down Expand Up @@ -590,6 +610,7 @@ class VulkanExample : public VulkanExampleBase
// We also want to flip what SSBO we draw with in the next
// pass through the graphics pipeline.
// Feel free to use std::swap here. You should need it twice.
std::swap(compute.descriptorSets[0], compute.descriptorSets[1]);
}

// Record command buffers for drawing using the graphics pipeline
Expand Down Expand Up @@ -639,7 +660,7 @@ class VulkanExample : public VulkanExampleBase
// How does this influence flip-flopping in draw()?
// Try drawing with storageBufferA instead of storageBufferB. What happens? Why?
VkDeviceSize offsets[1] = { 0 };
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &compute.storageBufferB.buffer, offsets);
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &compute.storageBufferA.buffer, offsets);
vkCmdDraw(drawCmdBuffers[i], PARTICLE_COUNT, 1, 0, 0);

vkCmdEndRenderPass(drawCmdBuffers[i]);
Expand Down