double buffered vertex buffer in two threads with two different queues if possible

feature/softbody-runtime-control
Benjamin Kraft 3 months ago
parent 8be5d3059f
commit 9e4333b9fb
  1. 16
      include/application.hpp
  2. 8
      include/vulkan/command_pool.hpp
  3. 48
      include/vulkan/instance.hpp
  4. 10
      shaders/pbd.comp
  5. 199
      src/application.cpp
  6. 6
      src/vulkan/buffer.cpp
  7. 19
      src/vulkan/command_pool.cpp
  8. 53
      src/vulkan/instance.cpp
  9. 11
      src/vulkan/swapchain.cpp

@ -44,9 +44,12 @@ private:
void createSyncObjects(); void createSyncObjects();
unique_ptr<Semaphore> imageAvailable; unique_ptr<Semaphore> imageAvailable;
unique_ptr<Semaphore> renderFinished; unique_ptr<Semaphore> renderFinished;
unique_ptr<Semaphore> computeFinished; unique_ptr<Semaphore> computeSemaphore;
unique_ptr<Fence> renderInFlight; unique_ptr<Semaphore> transferFinished;
unique_ptr<Fence> computeInFlight; unique_ptr<Fence> renderFence;
unique_ptr<Fence> computeFence;
unique_ptr<Fence> transferFence;
std::mutex submitMutex;
unique_ptr<Swapchain> swapchain; unique_ptr<Swapchain> swapchain;
unique_ptr<DescriptorPool> descriptorPool; unique_ptr<DescriptorPool> descriptorPool;
@ -56,7 +59,8 @@ private:
unique_ptr<Camera> camera; unique_ptr<Camera> camera;
void createMeshBuffers(); void createMeshBuffers();
unique_ptr<Buffer> vertexBuffer; size_t currentDrawVertexBuffer = 0;
unique_ptr<Buffer> vertexBuffers[2];
unique_ptr<Buffer> faceBuffer; unique_ptr<Buffer> faceBuffer;
unique_ptr<Buffer> edgeBuffer; unique_ptr<Buffer> edgeBuffer;
unique_ptr<Buffer> triangleBuffer; unique_ptr<Buffer> triangleBuffer;
@ -75,6 +79,7 @@ private:
struct Properties { struct Properties {
glm::vec3 gravity; glm::vec3 gravity;
// Delta time in seconds
float dt; float dt;
uint32_t k; uint32_t k;
}; };
@ -86,8 +91,7 @@ private:
unique_ptr<ComputePipeline> normalPipeline; unique_ptr<ComputePipeline> normalPipeline;
void updateUniformBuffer(); void updateUniformBuffer();
void recordGraphicsCommandBuffer(uint32_t imageIndex); void recordDrawCommands(VkCommandBuffer cmdBuffer);
void recordDrawCommands();
void drawFrame(); void drawFrame();
void recordComputeCommands(VkCommandBuffer cmdBuffer); void recordComputeCommands(VkCommandBuffer cmdBuffer);

@ -7,12 +7,10 @@ class Instance;
class CommandPool { class CommandPool {
public: public:
explicit CommandPool(VkSurfaceKHR surface); explicit CommandPool(uint32_t queueFamilyIndex, uint32_t bufferCount);
~CommandPool(); ~CommandPool();
VkCommandBuffer graphicsBuffer = VK_NULL_HANDLE;
VkCommandBuffer computeBuffer = VK_NULL_HANDLE;
VkCommandPool handle = VK_NULL_HANDLE; VkCommandPool handle = VK_NULL_HANDLE;
std::vector<VkCommandBuffer> buffers;
private: private:
void allocateBuffers(uint32_t count);
void createBuffers();
}; };

@ -4,8 +4,11 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <optional> #include <optional>
#include <set> #include <set>
#include <vector>
#include "vk_mem_alloc.h" #include "vk_mem_alloc.h"
using std::optional, std::vector;
class CommandPool; class CommandPool;
class Instance { class Instance {
@ -14,35 +17,37 @@ public:
~Instance(); ~Instance();
GLFWwindow *window = nullptr; GLFWwindow *window = nullptr;
VkQueue graphicsQueue = VK_NULL_HANDLE; VkQueue graphicsAndPresentQueue = VK_NULL_HANDLE;
VkQueue presentQueue = VK_NULL_HANDLE; VkQueue computeAndTransferQueue = VK_NULL_HANDLE;
VkQueue computeQueue = VK_NULL_HANDLE;
bool windowResized = false; bool windowResized = false;
CommandPool* commandPool = nullptr; CommandPool* renderingCommandPool = nullptr;
CommandPool* computeCommandPool = nullptr;
struct QueueFamilyIndices { struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily; vector<uint32_t> graphicsAndPresent;
std::optional<uint32_t> computeFamily; vector<uint32_t> computeAndTransfer;
std::optional<uint32_t> presentFamily;
std::optional<uint32_t> graphicsAndComputeFamily;
bool isComplete() const {
return graphicsFamily.has_value() &&
computeFamily.has_value() &&
presentFamily.has_value() &&
graphicsAndComputeFamily.has_value();
}
std::set<uint32_t> uniqueQueueFamilies(){ std::set<uint32_t> uniqueQueueFamilies(){
return { std::set<uint32_t> unique;
graphicsFamily.value(), unique.insert(graphicsAndPresent.begin(), graphicsAndPresent.end());
presentFamily.value(), unique.insert(computeAndTransfer.begin(), computeAndTransfer.end());
computeFamily.value(), return unique;
graphicsAndComputeFamily.value() }
}; uint32_t tryComputeAndTransferDedicated(){
for (uint32_t family : computeAndTransfer){
if (std::find(graphicsAndPresent.begin(), graphicsAndPresent.end(), family) == graphicsAndPresent.end()){
return family;
}
}
return computeAndTransfer[0];
}
bool isEnough(){
return !graphicsAndPresent.empty() && !computeAndTransfer.empty();
} }
}; };
static QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface); QueueFamilyIndices indices {};
static Instance* instance; static Instance* instance;
static VkDevice GetDevice(); static VkDevice GetDevice();
@ -67,5 +72,6 @@ private:
bool isDeviceSuitable(VkPhysicalDevice potentialPhysicalDevice); bool isDeviceSuitable(VkPhysicalDevice potentialPhysicalDevice);
static bool checkDeviceExtensionSupport(VkPhysicalDevice device); static bool checkDeviceExtensionSupport(VkPhysicalDevice device);
static QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface);
}; };

@ -68,8 +68,8 @@ void preSolve(uint vID){
if (vertices[vID].w == 0){ if (vertices[vID].w == 0){
return; return;
} }
vertices[vID].velocity += dt * gravity; vertices[vID].velocity += dt / k * gravity;
vertices[vID].position += dt * vertices[vID].velocity; vertices[vID].position += dt / k * vertices[vID].velocity;
float dist = vertices[vID].position.y + 5; float dist = vertices[vID].position.y + 5;
if (dist < 0){ if (dist < 0){
@ -102,7 +102,7 @@ void solveEdge(uint eID){
vec3 diff = v1.position - v2.position; vec3 diff = v1.position - v2.position;
float currentLength = length(diff); float currentLength = length(diff);
float alpha = edge.compliance / dt / dt; float alpha = edge.compliance / (dt / k) / (dt / k);
float s = -(currentLength - edge.restLength) / (v1.w + v2.w + alpha); float s = -(currentLength - edge.restLength) / (v1.w + v2.w + alpha);
@ -144,7 +144,7 @@ void solveTetrahedron(uint tetID){
if (w == 0) return; if (w == 0) return;
float alpha = tetrahedron.compliance / dt / dt; float alpha = tetrahedron.compliance / (dt / k) / (dt / k);
float s = -volumeError / (w + alpha); float s = -volumeError / (w + alpha);
@ -163,7 +163,7 @@ void postSolve(uint vID){
if (vertices[vID].w == 0){ if (vertices[vID].w == 0){
return; return;
} }
vertices[vID].velocity = (vertices[vID].position - vertices[vID].prevPosition) / dt; vertices[vID].velocity = (vertices[vID].position - vertices[vID].prevPosition) / (dt / k);
} }
void main() { void main() {

@ -12,6 +12,7 @@
#include "soft_body.hpp" #include "soft_body.hpp"
#include "mesh.hpp" #include "mesh.hpp"
#include "constraints.hpp" #include "constraints.hpp"
#include "timer.hpp"
Application::Application() { Application::Application() {
createSyncObjects(); createSyncObjects();
@ -34,7 +35,7 @@ Application::Application() {
createMeshBuffers(); createMeshBuffers();
SizeInformation sizeInformation {}; SizeInformation sizeInformation {};
sizeInformation.vertexCount = vertexBuffer->size / sizeof(Vertex); sizeInformation.vertexCount = vertexBuffers[0]->size / sizeof(Vertex);
sizeInformation.faceCount = faceBuffer->size / sizeof(Face); sizeInformation.faceCount = faceBuffer->size / sizeof(Face);
sizeInformationBuffer = make_unique<Buffer>( sizeInformationBuffer = make_unique<Buffer>(
@ -44,14 +45,14 @@ Application::Application() {
properties.gravity = {0, -9.81, 0}; properties.gravity = {0, -9.81, 0};
properties.k = 10; properties.k = 10;
properties.dt = 1.f / 60.f / static_cast<float>(properties.k); properties.dt = 1.f / 60.f;
propertiesBuffer = make_unique<Buffer>( propertiesBuffer = make_unique<Buffer>(
sizeof(Properties), &properties, sizeof(properties), sizeof(Properties), &properties, sizeof(properties),
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
descriptorPool->bindBuffer(*vertexBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0); descriptorPool->bindBuffer(*vertexBuffers[1 - currentDrawVertexBuffer], VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0);
descriptorPool->bindBuffer(*faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1); descriptorPool->bindBuffer(*faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1);
descriptorPool->bindBuffer(*edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2); descriptorPool->bindBuffer(*edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2);
descriptorPool->bindBuffer(*triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3); descriptorPool->bindBuffer(*triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3);
@ -68,12 +69,32 @@ Application::Application() {
vmaFreeStatsString(Instance::GetAllocator(), stats); vmaFreeStatsString(Instance::GetAllocator(), stats);
} }
#include <future>
#include <chrono>
using namespace std::chrono;
void Application::mainLoop() { void Application::mainLoop() {
std::future compute = std::async(std::launch::async, [this](){
while (!glfwWindowShouldClose(Instance::instance->window)){ while (!glfwWindowShouldClose(Instance::instance->window)){
glfwPollEvents(); Timer timer;
auto t1 = system_clock::now();
update(); update();
auto t2 = system_clock::now();
microseconds updateDuration = duration_cast<microseconds>(t2 - t1);
microseconds sleepDuration(static_cast<int64_t>(properties.dt * 1000 * 1000));
std::this_thread::sleep_for(sleepDuration - updateDuration);
}
});
while (!glfwWindowShouldClose(Instance::instance->window)){
glfwPollEvents();
drawFrame(); drawFrame();
} }
compute.wait();
vkDeviceWaitIdle(Instance::GetDevice()); vkDeviceWaitIdle(Instance::GetDevice());
} }
@ -84,9 +105,11 @@ Application::~Application() {
void Application::createSyncObjects() { void Application::createSyncObjects() {
imageAvailable = make_unique<Semaphore>(); imageAvailable = make_unique<Semaphore>();
renderFinished = make_unique<Semaphore>(); renderFinished = make_unique<Semaphore>();
computeFinished = make_unique<Semaphore>(); computeSemaphore = make_unique<Semaphore>();
renderInFlight = make_unique<Fence>(true); transferFinished = make_unique<Semaphore>();
computeInFlight = make_unique<Fence>(true); renderFence = make_unique<Fence>(true);
computeFence = make_unique<Fence>(true);
transferFence = make_unique<Fence>(true);
} }
void Application::createMeshBuffers() { void Application::createMeshBuffers() {
@ -102,7 +125,7 @@ void Application::createMeshBuffers() {
} }
body = std::make_unique<SoftBody>(&bunny, 1.f / 3); body = std::make_unique<SoftBody>(&bunny, 1.f / 3);
for (size_t i = 0; i < 5; i++){ for (size_t i = 0; i < 10; i++){
auto copy = std::make_unique<SoftBody>(*body.get()); auto copy = std::make_unique<SoftBody>(*body.get());
copy->applyVertexOffset({i * 2, 0, 2}); copy->applyVertexOffset({i * 2, 0, 2});
softBodies.push_back(std::move(copy)); softBodies.push_back(std::move(copy));
@ -196,7 +219,10 @@ void Application::createMeshBuffers() {
: Buffer(size, data, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | additionalUsageFlags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0) {} : Buffer(size, data, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | additionalUsageFlags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0) {}
}; };
vertexBuffer = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); vertexBuffers[0] = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
vertexBuffers[1] = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
faceBuffer = make_unique<SimulationBuffer>(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT); faceBuffer = make_unique<SimulationBuffer>(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
edgeBuffer = make_unique<SimulationBuffer>(constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge)); edgeBuffer = make_unique<SimulationBuffer>(constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge));
triangleBuffer = make_unique<SimulationBuffer>(constraintData.triangles.data(), constraintData.triangles.size() * sizeof(Triangle)); triangleBuffer = make_unique<SimulationBuffer>(constraintData.triangles.data(), constraintData.triangles.size() * sizeof(Triangle));
@ -246,24 +272,70 @@ void Application::updateUniformBuffer() {
ubo.projection[1][1] *= -1; ubo.projection[1][1] *= -1;
memcpy(uniformBuffer->allocationInfo.pMappedData, &ubo, sizeof(UniformBufferObject)); memcpy(uniformBuffer->allocationInfo.pMappedData, &ubo, sizeof(UniformBufferObject));
VkMappedMemoryRange mappedMemoryRange {};
mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedMemoryRange.offset = uniformBuffer->allocationInfo.offset;
mappedMemoryRange.size = uniformBuffer->allocationInfo.size;
mappedMemoryRange.memory = uniformBuffer->allocationInfo.deviceMemory;
vkFlushMappedMemoryRanges(Instance::GetDevice(), 1, &mappedMemoryRange);
} }
void Application::recordGraphicsCommandBuffer(uint32_t imageIndex) { void Application::drawFrame() {
VkCommandBuffer cmdBuffer = Instance::instance->commandPool->graphicsBuffer; vkWaitForFences(Instance::GetDevice(), 1, &renderFence->handle, VK_TRUE, UINT64_MAX);
VkCommandBufferBeginInfo beginInfo {}; uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(Instance::GetDevice(), swapchain->handle, UINT64_MAX, imageAvailable->handle, VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR){
swapchain->recreateSwapchain();
return;
}
vkResetFences(Instance::GetDevice(), 1, &renderFence->handle);
camera->update(0.017);
updateUniformBuffer();
VkCommandBuffer cmdBuffer = Instance::instance->renderingCommandPool->buffers[0];
{
vkResetCommandBuffer(cmdBuffer, 0);
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vkBeginCommandBuffer(cmdBuffer, &beginInfo); vkBeginCommandBuffer(cmdBuffer, &beginInfo);
VkRenderPassBeginInfo renderPassInfo {}; VkBufferMemoryBarrier vertexBufferBarrier{};
vertexBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
vertexBufferBarrier.size = vertexBuffers[currentDrawVertexBuffer]->size;
vertexBufferBarrier.offset = 0;
vertexBufferBarrier.buffer = vertexBuffers[currentDrawVertexBuffer]->handle;
vertexBufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
vertexBufferBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0,
nullptr, 1, &vertexBufferBarrier, 0, nullptr);
VkBufferMemoryBarrier uniformBufferBarrier {};
uniformBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
uniformBufferBarrier.size = uniformBuffer->size;
uniformBufferBarrier.offset = 0;
uniformBufferBarrier.buffer = uniformBuffer->handle;
uniformBufferBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
uniformBufferBarrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT;
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr, 1, &uniformBufferBarrier, 0, nullptr);
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = swapchain->renderPass; renderPassInfo.renderPass = swapchain->renderPass;
renderPassInfo.framebuffer = swapchain->frameBuffers[imageIndex]; renderPassInfo.framebuffer = swapchain->frameBuffers[imageIndex];
renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = swapchain->extent; renderPassInfo.renderArea.extent = swapchain->extent;
VkClearValue clearValues[2] {}; VkClearValue clearValues[2]{};
clearValues[0].color = {{0, 0, 0, 1}}; clearValues[0].color = {{0, 0, 0, 1}};
clearValues[1].depthStencil = {1.0f, 0}; clearValues[1].depthStencil = {1.0f, 0};
@ -272,7 +344,7 @@ void Application::recordGraphicsCommandBuffer(uint32_t imageIndex) {
vkCmdBeginRenderPass(cmdBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(cmdBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport {}; VkViewport viewport{};
viewport.x = 0; viewport.x = 0;
viewport.y = 0; viewport.y = 0;
viewport.width = static_cast<float>(swapchain->extent.width); viewport.width = static_cast<float>(swapchain->extent.width);
@ -281,51 +353,35 @@ void Application::recordGraphicsCommandBuffer(uint32_t imageIndex) {
viewport.maxDepth = 1; viewport.maxDepth = 1;
vkCmdSetViewport(cmdBuffer, 0, 1, &viewport); vkCmdSetViewport(cmdBuffer, 0, 1, &viewport);
VkRect2D scissor {}; VkRect2D scissor{};
scissor.offset = {0, 0}; scissor.offset = {0, 0};
scissor.extent = swapchain->extent; scissor.extent = swapchain->extent;
vkCmdSetScissor(cmdBuffer, 0, 1, &scissor); vkCmdSetScissor(cmdBuffer, 0, 1, &scissor);
recordDrawCommands(); recordDrawCommands(cmdBuffer);
vkCmdEndRenderPass(cmdBuffer); vkCmdEndRenderPass(cmdBuffer);
vkEndCommandBuffer(cmdBuffer); vkEndCommandBuffer(cmdBuffer);
}
void Application::drawFrame() {
vkWaitForFences(Instance::GetDevice(), 1, &renderInFlight->handle, VK_TRUE, UINT64_MAX);
uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(Instance::GetDevice(), swapchain->handle, UINT64_MAX, imageAvailable->handle, VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR){
swapchain->recreateSwapchain();
return;
} }
vkResetFences(Instance::GetDevice(), 1, &renderInFlight->handle);
vkResetCommandBuffer(Instance::instance->commandPool->graphicsBuffer, 0);
recordGraphicsCommandBuffer(imageIndex);
camera->update(0.017);
updateUniformBuffer();
VkSubmitInfo submitInfo {}; VkSubmitInfo submitInfo {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {imageAvailable->handle, computeFinished->handle}; VkSemaphore waitSemaphores[] = {imageAvailable->handle};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT}; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 2; submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores; submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages; submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &Instance::instance->commandPool->graphicsBuffer; submitInfo.pCommandBuffers = &cmdBuffer;
VkSemaphore signalSemaphores[] = {renderFinished->handle}; VkSemaphore signalSemaphores[] = {renderFinished->handle};
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores; submitInfo.pSignalSemaphores = signalSemaphores;
vkQueueSubmit(Instance::instance->graphicsQueue, 1, &submitInfo, renderInFlight->handle); submitMutex.lock();
vkQueueSubmit(Instance::instance->graphicsAndPresentQueue, 1, &submitInfo, renderFence->handle);
submitMutex.unlock();
VkPresentInfoKHR presentInfo {}; VkPresentInfoKHR presentInfo {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
@ -337,7 +393,10 @@ void Application::drawFrame() {
presentInfo.pSwapchains = swapchains; presentInfo.pSwapchains = swapchains;
presentInfo.pImageIndices = &imageIndex; presentInfo.pImageIndices = &imageIndex;
result = vkQueuePresentKHR(Instance::instance->presentQueue, &presentInfo); submitMutex.lock();
result = vkQueuePresentKHR(Instance::instance->graphicsAndPresentQueue, &presentInfo);
submitMutex.unlock();
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || Instance::instance->windowResized){ if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || Instance::instance->windowResized){
Instance::instance->windowResized = false; Instance::instance->windowResized = false;
swapchain->recreateSwapchain(); swapchain->recreateSwapchain();
@ -345,17 +404,19 @@ void Application::drawFrame() {
} }
void Application::update() { void Application::update() {
vkWaitForFences(Instance::GetDevice(), 1, &computeInFlight->handle, VK_TRUE, UINT64_MAX); vkWaitForFences(Instance::GetDevice(), 1, &transferFence->handle, VK_TRUE, UINT64_MAX);
vkResetFences(Instance::GetDevice(), 1, &computeInFlight->handle); vkResetFences(Instance::GetDevice(), 1, &transferFence->handle);
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer;
VkCommandBuffer cmdBuffer = Instance::instance->commandPool->computeBuffer; descriptorPool->bindBuffer(*vertexBuffers[1 - currentDrawVertexBuffer], VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0);
vkResetCommandBuffer(cmdBuffer, 0);
VkCommandBufferBeginInfo beginInfo {}; VkCommandBufferBeginInfo beginInfo {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = 0; beginInfo.flags = 0;
VkCommandBuffer cmdBuffer = Instance::instance->computeCommandPool->buffers[0];
{
vkResetCommandBuffer(cmdBuffer, 0);
vkBeginCommandBuffer(cmdBuffer, &beginInfo); vkBeginCommandBuffer(cmdBuffer, &beginInfo);
recordComputeCommands(cmdBuffer); recordComputeCommands(cmdBuffer);
vkEndCommandBuffer(cmdBuffer); vkEndCommandBuffer(cmdBuffer);
@ -363,19 +424,49 @@ void Application::update() {
VkSubmitInfo submit {}; VkSubmitInfo submit {};
submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit.commandBufferCount = 1; submit.commandBufferCount = 1;
submit.pCommandBuffers = &Instance::instance->commandPool->computeBuffer; submit.pCommandBuffers = &cmdBuffer;
submit.signalSemaphoreCount = 1; submit.signalSemaphoreCount = 1;
submit.pSignalSemaphores = &computeFinished->handle; submit.pSignalSemaphores = &computeSemaphore->handle;
vkQueueSubmit(Instance::instance->computeQueue, 1, &submit, computeInFlight->handle); submitMutex.lock();
} vkQueueSubmit(Instance::instance->computeAndTransferQueue, 1, &submit, nullptr);
submitMutex.unlock();
}
cmdBuffer = Instance::instance->computeCommandPool->buffers[1];
vkResetCommandBuffer(cmdBuffer, 0);
{
vkBeginCommandBuffer(cmdBuffer, &beginInfo);
VkBufferCopy copyRegion {};
copyRegion.size = vertexBuffers[0]->size;
copyRegion.srcOffset = 0;
copyRegion.dstOffset = 0;
vkCmdCopyBuffer(cmdBuffer, vertexBuffers[1 - currentDrawVertexBuffer]->handle, vertexBuffers[currentDrawVertexBuffer]->handle, 1, &copyRegion);
void Application::recordDrawCommands() { vkEndCommandBuffer(cmdBuffer);
VkCommandBuffer cmdBuffer = Instance::instance->commandPool->graphicsBuffer;
VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
VkSubmitInfo submit {};
submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit.commandBufferCount = 1;
submit.pCommandBuffers = &cmdBuffer;
submit.waitSemaphoreCount = 1;
submit.pWaitSemaphores = &computeSemaphore->handle;
submit.pWaitDstStageMask = &waitStage;
submitMutex.lock();
vkQueueSubmit(Instance::instance->computeAndTransferQueue, 1, &submit, transferFence->handle);
submitMutex.unlock();
}
}
void Application::recordDrawCommands(VkCommandBuffer cmdBuffer) {
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->handle); vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->handle);
VkBuffer buffers[] = {vertexBuffer->handle}; VkBuffer buffers[] = {vertexBuffers[currentDrawVertexBuffer]->handle};
VkDeviceSize offsets[] = {0}; VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(cmdBuffer, 0, 1, buffers, offsets); vkCmdBindVertexBuffers(cmdBuffer, 0, 1, buffers, offsets);
vkCmdBindIndexBuffer(cmdBuffer, faceBuffer->handle, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuffer, faceBuffer->handle, 0, VK_INDEX_TYPE_UINT32);
@ -393,7 +484,7 @@ void Application::recordComputeCommands(VkCommandBuffer cmdBuffer) {
return (threads - 1) / blockSize + 1; return (threads - 1) / blockSize + 1;
}; };
uint32_t vertexGroupCount = getGroupCount(vertexBuffer->size / sizeof(Vertex), BlOCK_SIZE); uint32_t vertexGroupCount = getGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BlOCK_SIZE);
uint32_t faceGroupCount = getGroupCount(faceBuffer->size / sizeof(Face), BlOCK_SIZE); uint32_t faceGroupCount = getGroupCount(faceBuffer->size / sizeof(Face), BlOCK_SIZE);
VkMemoryBarrier barrier {}; VkMemoryBarrier barrier {};

@ -43,7 +43,7 @@ void Buffer::copyTo(Buffer *dst) {
VkCommandBufferAllocateInfo allocateInfo {}; VkCommandBufferAllocateInfo allocateInfo {};
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocateInfo.commandPool = Instance::instance->commandPool->handle; allocateInfo.commandPool = Instance::instance->renderingCommandPool->handle;
allocateInfo.commandBufferCount = 1; allocateInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer; VkCommandBuffer commandBuffer;
@ -64,8 +64,8 @@ void Buffer::copyTo(Buffer *dst) {
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer; submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(Instance::instance->graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); vkQueueSubmit(Instance::instance->graphicsAndPresentQueue, 1, &submitInfo, VK_NULL_HANDLE);
vkDeviceWaitIdle(Instance::GetDevice()); vkDeviceWaitIdle(Instance::GetDevice());
vkFreeCommandBuffers(Instance::GetDevice(), Instance::instance->commandPool->handle, 1, &commandBuffer); vkFreeCommandBuffers(Instance::GetDevice(), Instance::instance->renderingCommandPool->handle, 1, &commandBuffer);
} }

@ -2,32 +2,29 @@
#include "application.hpp" #include "application.hpp"
#include "vulkan/instance.hpp" #include "vulkan/instance.hpp"
CommandPool::CommandPool(VkSurfaceKHR surface) { CommandPool::CommandPool(uint32_t queueFamilyIndex, uint32_t bufferCount) {
Instance::QueueFamilyIndices indices = Instance::findQueueFamilies(Instance::GetPhysicalDevice(), surface);
VkCommandPoolCreateInfo poolInfo {}; VkCommandPoolCreateInfo poolInfo {};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = indices.graphicsAndComputeFamily.value(); poolInfo.queueFamilyIndex = queueFamilyIndex;
vkCreateCommandPool(Instance::GetDevice(), &poolInfo, nullptr, &handle); vkCreateCommandPool(Instance::GetDevice(), &poolInfo, nullptr, &handle);
createBuffers(); allocateBuffers(bufferCount);
} }
void CommandPool::createBuffers() { void CommandPool::allocateBuffers(uint32_t count) {
VkCommandBufferAllocateInfo allocateInfo {}; VkCommandBufferAllocateInfo allocateInfo {};
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocateInfo.commandPool = handle; allocateInfo.commandPool = handle;
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocateInfo.commandBufferCount = 1; allocateInfo.commandBufferCount = count;
vkAllocateCommandBuffers(Instance::GetDevice(), &allocateInfo, &graphicsBuffer); buffers.resize(count);
vkAllocateCommandBuffers(Instance::GetDevice(), &allocateInfo, &computeBuffer); vkAllocateCommandBuffers(Instance::GetDevice(), &allocateInfo, buffers.data());
} }
CommandPool::~CommandPool() { CommandPool::~CommandPool() {
vkFreeCommandBuffers(Instance::GetDevice(), handle, 1, &graphicsBuffer); vkFreeCommandBuffers(Instance::GetDevice(), handle, buffers.size(), buffers.data());
vkFreeCommandBuffers(Instance::GetDevice(), handle, 1, &computeBuffer);
vkDestroyCommandPool(Instance::GetDevice(), handle, nullptr); vkDestroyCommandPool(Instance::GetDevice(), handle, nullptr);
} }

@ -59,7 +59,8 @@ Instance::Instance() {
pickPhysicalDevice(); pickPhysicalDevice();
createLogicalDevice(); createLogicalDevice();
createAllocator(); createAllocator();
commandPool = new CommandPool(surface); renderingCommandPool = new CommandPool(indices.graphicsAndPresent[0], 1);
computeCommandPool = new CommandPool(indices.tryComputeAndTransferDedicated(), 2);
} }
void Instance::initWindow() { void Instance::initWindow() {
@ -118,9 +119,10 @@ void Instance::pickPhysicalDevice() {
std::vector<VkPhysicalDevice> devices(deviceCount); std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(handle, &deviceCount, devices.data()); vkEnumeratePhysicalDevices(handle, &deviceCount, devices.data());
for (const VkPhysicalDevice &device : devices){ for (const VkPhysicalDevice &potentialPhysicalDevice : devices){
if (isDeviceSuitable(device)){ if (isDeviceSuitable(potentialPhysicalDevice)){
physicalDevice = device; physicalDevice = potentialPhysicalDevice;
indices = findQueueFamilies(physicalDevice, surface);
break; break;
} }
} }
@ -135,8 +137,6 @@ void Instance::pickPhysicalDevice() {
} }
void Instance::createLogicalDevice() { void Instance::createLogicalDevice() {
QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos; std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
float queuePriority = 1.0f; float queuePriority = 1.0f;
@ -167,9 +167,8 @@ void Instance::createLogicalDevice() {
vkCreateDevice(physicalDevice, &createInfo, nullptr, &device); vkCreateDevice(physicalDevice, &createInfo, nullptr, &device);
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue); vkGetDeviceQueue(device, indices.graphicsAndPresent[0], 0, &graphicsAndPresentQueue);
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); vkGetDeviceQueue(device, indices.tryComputeAndTransferDedicated(), 0, &computeAndTransferQueue);
vkGetDeviceQueue(device, indices.graphicsAndComputeFamily.value(), 0, &computeQueue);
} }
void Instance::createAllocator() { void Instance::createAllocator() {
@ -196,23 +195,18 @@ Instance::QueueFamilyIndices Instance::findQueueFamilies(VkPhysicalDevice device
uint32_t i = 0; uint32_t i = 0;
for (const VkQueueFamilyProperties& queueFamilyProperties : queueFamilies){ for (const VkQueueFamilyProperties& queueFamilyProperties : queueFamilies){
if (queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT){ VkBool32 present = false;
indices.graphicsFamily = i; vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &present);
}
if (queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT){ bool graphics = queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT;
indices.computeFamily = i; bool compute = queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT;
} bool transfer = queueFamilyProperties.queueFlags & VK_QUEUE_TRANSFER_BIT;
if (indices.graphicsFamily == i && indices.computeFamily == i){
indices.graphicsAndComputeFamily = i; if (graphics && present)
} indices.graphicsAndPresent.push_back(i);
VkBool32 presentSupport = false; if (compute && transfer)
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); indices.computeAndTransfer.push_back(i);
if (presentSupport){
indices.presentFamily = i;
}
if (indices.isComplete()){
break;
}
i++; i++;
} }
return indices; return indices;
@ -225,7 +219,7 @@ bool Instance::isDeviceSuitable(VkPhysicalDevice potentialPhysicalDevice) {
VkPhysicalDeviceFeatures deviceFeatures; VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceFeatures(potentialPhysicalDevice, &deviceFeatures); vkGetPhysicalDeviceFeatures(potentialPhysicalDevice, &deviceFeatures);
QueueFamilyIndices indices = findQueueFamilies(potentialPhysicalDevice, surface); QueueFamilyIndices potentialIndices = findQueueFamilies(potentialPhysicalDevice, surface);
bool extensionsSupported = checkDeviceExtensionSupport(potentialPhysicalDevice); bool extensionsSupported = checkDeviceExtensionSupport(potentialPhysicalDevice);
@ -235,7 +229,7 @@ bool Instance::isDeviceSuitable(VkPhysicalDevice potentialPhysicalDevice) {
swapChainAdequate = !details.formats.empty() && !details.presentModes.empty(); swapChainAdequate = !details.formats.empty() && !details.presentModes.empty();
} }
return indices.isComplete() && extensionsSupported && swapChainAdequate; return potentialIndices.isEnough() && extensionsSupported && swapChainAdequate;
} }
bool Instance::checkDeviceExtensionSupport(VkPhysicalDevice device) { bool Instance::checkDeviceExtensionSupport(VkPhysicalDevice device) {
@ -271,7 +265,8 @@ VkSurfaceKHR Instance::GetSurface() {
} }
Instance::~Instance() { Instance::~Instance() {
delete commandPool; delete renderingCommandPool;
delete computeCommandPool;
vmaDestroyAllocator(allocator); vmaDestroyAllocator(allocator);
vkDestroyDevice(device, nullptr); vkDestroyDevice(device, nullptr);
vkDestroySurfaceKHR(handle, surface, nullptr); vkDestroySurfaceKHR(handle, surface, nullptr);

@ -80,16 +80,7 @@ void Swapchain::createSwapchain() {
createInfo.imageArrayLayers = 1; createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
Instance::QueueFamilyIndices indices = Instance::findQueueFamilies(Instance::GetPhysicalDevice(), Instance::GetSurface());
uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
if (indices.graphicsFamily != indices.presentFamily){
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
} else {
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
}
createInfo.preTransform = swapchainSupport.capabilities.currentTransform; createInfo.preTransform = swapchainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
@ -118,7 +109,7 @@ void Swapchain::cleanupSwapchain() {
} }
void Swapchain::recreateSwapchain() { void Swapchain::recreateSwapchain() {
vkDeviceWaitIdle(Instance::GetDevice()); vkQueueWaitIdle(Instance::instance->graphicsAndPresentQueue);
cleanupSwapchain(); cleanupSwapchain();

Loading…
Cancel
Save