basic compute

main
Benjamin Kraft 2 weeks ago
parent e62723d4ca
commit d3ebdfbd66
  1. 1
      shaders/compile.sh
  2. 16
      shaders/shader.comp
  3. 96
      src/vulkan/application.cpp
  4. 13
      src/vulkan/application.hpp
  5. 8
      src/vulkan/command_pool.cpp
  6. 3
      src/vulkan/command_pool.hpp
  7. 4
      src/vulkan/instance.cpp
  8. 14
      src/vulkan/instance.hpp
  9. 59
      src/vulkan/pipeline.cpp
  10. 13
      src/vulkan/pipeline.hpp
  11. 4
      src/vulkan/vertex.hpp

@ -1,3 +1,4 @@
#!/usr/bin/env bash
glslc shader.vert -o vert.spv
glslc shader.frag -o frag.spv
glslc shader.comp -o comp.spv

@ -0,0 +1,16 @@
#version 450
layout (local_size_x = 1) in;
struct Vertex {
vec3 position;
vec3 color;
};
layout (std140, binding = 0) buffer VertexBuffer {
Vertex vertices[];
};
void main() {
vertices[4].position.z += 0.001;
}

@ -10,10 +10,10 @@
Application::Application() {
new Instance;
swapchain = new Swapchain();
pipeline = new Pipeline(swapchain->renderPass);
graphicsPipeline = new Pipeline(swapchain->renderPass);
auto stagedVertexBuffer = Buffer::createStagedVertexBuffer();
vertexBuffer = new Buffer(stagedVertexBuffer->size,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
auto stagedIndexBuffer = Buffer::createStagedIndexBuffer();
@ -28,7 +28,8 @@ Application::Application() {
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkMapMemory(Instance::instance->device, uniformBuffer->memory, 0, bufferSize, 0, &uniformBufferMapped);
pipeline->createDescriptorSet(uniformBuffer);
graphicsPipeline->createDescriptorSet(uniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
computePipeline = new ComputePipeline(vertexBuffer);
commandPool = new CommandPool();
stagedVertexBuffer->copyTo(vertexBuffer, commandPool);
@ -38,6 +39,8 @@ Application::Application() {
delete stagedIndexBuffer;
createSyncObjects();
recordComputeCommandBuffer();
}
void Application::updateUniformBuffer() {
@ -77,7 +80,7 @@ void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t im
renderPassInfo.pClearValues = clearValues;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->handle);
VkViewport viewport {};
viewport.x = 0;
@ -97,7 +100,7 @@ void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t im
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, buffers, offsets);
vkCmdBindIndexBuffer(commandBuffer, indexBuffer->handle, 0, VK_INDEX_TYPE_UINT32);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->layout, 0, 1, &pipeline->descriptorSet, 0, nullptr);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->layout, 0, 1, &graphicsPipeline->descriptorSet, 0, nullptr);
vkCmdDrawIndexed(commandBuffer, indices.size(), 1, 0, 0, 0);
@ -105,8 +108,32 @@ void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t im
vkEndCommandBuffer(commandBuffer);
}
void Application::createSyncObjects() {
VkSemaphoreCreateInfo semaphoreInfo {};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkFenceCreateInfo fenceInfo {};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
vkCreateSemaphore(Instance::instance->device, &semaphoreInfo, nullptr, &imageAvailableSemaphore);
vkCreateSemaphore(Instance::instance->device, &semaphoreInfo, nullptr, &renderFinishedSemaphore);
vkCreateSemaphore(Instance::instance->device, &semaphoreInfo, nullptr, &computeFinishedSemaphore);
vkCreateFence(Instance::instance->device, &fenceInfo, nullptr, &renderInFlightFence);
vkCreateFence(Instance::instance->device, &fenceInfo, nullptr, &computeInFlightFence);
}
void Application::mainLoop() {
while (!glfwWindowShouldClose(Instance::instance->window)){
glfwPollEvents();
update();
drawFrame();
}
vkDeviceWaitIdle(Instance::instance->device);
}
void Application::drawFrame() {
vkWaitForFences(Instance::instance->device, 1, &inFlightFence, VK_TRUE, UINT64_MAX);
vkWaitForFences(Instance::instance->device, 1, &renderInFlightFence, VK_TRUE, UINT64_MAX);
uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(Instance::instance->device, swapchain->handle, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
@ -115,10 +142,10 @@ void Application::drawFrame() {
return;
}
vkResetFences(Instance::instance->device, 1, &inFlightFence);
vkResetFences(Instance::instance->device, 1, &renderInFlightFence);
vkResetCommandBuffer(commandPool->buffer, 0);
recordCommandBuffer(commandPool->buffer, imageIndex);
vkResetCommandBuffer(commandPool->graphicsBuffer, 0);
recordCommandBuffer(commandPool->graphicsBuffer, imageIndex);
updateUniformBuffer();
@ -131,13 +158,15 @@ void Application::drawFrame() {
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandPool->buffer;
submitInfo.pCommandBuffers = &commandPool->graphicsBuffer;
VkSemaphore signalSemaphores[] = {renderFinishedSemaphore};
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &computeFinishedSemaphore;
vkQueueSubmit(Instance::instance->graphicsQueue, 1, &submitInfo, inFlightFence);
vkQueueSubmit(Instance::instance->graphicsQueue, 1, &submitInfo, renderInFlightFence);
VkPresentInfoKHR presentInfo {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
@ -156,37 +185,48 @@ void Application::drawFrame() {
}
}
void Application::createSyncObjects() {
VkSemaphoreCreateInfo semaphoreInfo {};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
void Application::update() {
vkWaitForFences(Instance::instance->device, 1, &computeInFlightFence, VK_TRUE, UINT64_MAX);
vkResetFences(Instance::instance->device, 1, &computeInFlightFence);
VkFenceCreateInfo fenceInfo {};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
VkSubmitInfo submit {};
submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit.commandBufferCount = 1;
submit.pCommandBuffers = &commandPool->computeBuffer;
submit.signalSemaphoreCount = 1;
submit.pSignalSemaphores = &computeFinishedSemaphore;
vkCreateSemaphore(Instance::instance->device, &semaphoreInfo, nullptr, &imageAvailableSemaphore);
vkCreateSemaphore(Instance::instance->device, &semaphoreInfo, nullptr, &renderFinishedSemaphore);
vkCreateFence(Instance::instance->device, &fenceInfo, nullptr, &inFlightFence);
vkQueueSubmit(Instance::instance->computeQueue, 1, &submit, computeInFlightFence);
}
void Application::mainLoop() {
while (!glfwWindowShouldClose(Instance::instance->window)){
glfwPollEvents();
drawFrame();
}
vkDeviceWaitIdle(Instance::instance->device);
void Application::recordComputeCommandBuffer() {
VkCommandBuffer buffer = commandPool->computeBuffer;
VkCommandBufferBeginInfo beginInfo {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vkBeginCommandBuffer(buffer, &beginInfo);
vkCmdBindPipeline(buffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline->handle);
vkCmdBindDescriptorSets(buffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline->layout,0, 1, &computePipeline->descriptorSet, 0, nullptr);
vkCmdDispatch(buffer, 1, 1, 1);
vkEndCommandBuffer(buffer);
}
Application::~Application() {
delete swapchain;
vkDestroySemaphore(Instance::instance->device, imageAvailableSemaphore, nullptr);
vkDestroySemaphore(Instance::instance->device, renderFinishedSemaphore, nullptr);
vkDestroyFence(Instance::instance->device, inFlightFence, nullptr);
vkDestroySemaphore(Instance::instance->device, computeFinishedSemaphore, nullptr);
vkDestroyFence(Instance::instance->device, renderInFlightFence, nullptr);
vkDestroyFence(Instance::instance->device, computeInFlightFence, nullptr);
delete commandPool;
delete vertexBuffer;
delete indexBuffer;
delete uniformBuffer;
delete pipeline;
delete graphicsPipeline;
delete computePipeline;
delete Instance::instance;
}

@ -20,8 +20,7 @@ class Pipeline;
class Buffer;
class CommandPool;
class Image;
constexpr int MAX_FRAMES_IN_FLIGHT = 1;
class ComputePipeline;
class Timer {
public:
@ -43,22 +42,28 @@ public:
~Application();
private:
Swapchain* swapchain = nullptr;
Pipeline* pipeline = nullptr;
Pipeline* graphicsPipeline = nullptr;
Buffer* vertexBuffer = nullptr;
Buffer* indexBuffer = nullptr;
Buffer* uniformBuffer = nullptr;
CommandPool* commandPool = nullptr;
ComputePipeline* computePipeline = nullptr;
void* uniformBufferMapped = nullptr;
void updateUniformBuffer();
void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex);
void recordComputeCommandBuffer();
VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE;
VkSemaphore renderFinishedSemaphore = VK_NULL_HANDLE;
VkFence inFlightFence = VK_NULL_HANDLE;
VkSemaphore computeFinishedSemaphore = VK_NULL_HANDLE;
VkFence renderInFlightFence = VK_NULL_HANDLE;
VkFence computeInFlightFence = VK_NULL_HANDLE;
void drawFrame();
void update();
void createSyncObjects();
};

@ -8,7 +8,7 @@ CommandPool::CommandPool() {
VkCommandPoolCreateInfo poolInfo {};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = indices.graphicsFamily.value();
poolInfo.queueFamilyIndex = indices.graphicsAndComputeFamily.value();
vkCreateCommandPool(Instance::instance->device, &poolInfo, nullptr, &handle);
@ -22,10 +22,12 @@ void CommandPool::createBuffers() {
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocateInfo.commandBufferCount = 1;
vkAllocateCommandBuffers(Instance::instance->device, &allocateInfo, &buffer);
vkAllocateCommandBuffers(Instance::instance->device, &allocateInfo, &graphicsBuffer);
vkAllocateCommandBuffers(Instance::instance->device, &allocateInfo, &computeBuffer);
}
CommandPool::~CommandPool() {
vkFreeCommandBuffers(Instance::instance->device, handle, 1, &buffer);
vkFreeCommandBuffers(Instance::instance->device, handle, 1, &graphicsBuffer);
vkFreeCommandBuffers(Instance::instance->device, handle, 1, &computeBuffer);
vkDestroyCommandPool(Instance::instance->device, handle, nullptr);
}

@ -9,7 +9,8 @@ class CommandPool {
public:
explicit CommandPool();
~CommandPool();
VkCommandBuffer buffer = VK_NULL_HANDLE;
VkCommandBuffer graphicsBuffer = VK_NULL_HANDLE;
VkCommandBuffer computeBuffer = VK_NULL_HANDLE;
VkCommandPool handle = VK_NULL_HANDLE;
private:

@ -163,6 +163,7 @@ void Instance::createLogicalDevice() {
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
vkGetDeviceQueue(device, indices.graphicsAndComputeFamily.value(), 0, &computeQueue);
}
Instance::QueueFamilyIndices Instance::findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface) {
@ -182,6 +183,9 @@ Instance::QueueFamilyIndices Instance::findQueueFamilies(VkPhysicalDevice device
if (queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT){
indices.computeFamily = i;
}
if (indices.graphicsFamily == i && indices.computeFamily == i){
indices.graphicsAndComputeFamily = i;
}
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
if (presentSupport){

@ -16,16 +16,26 @@ public:
VkDevice device = VK_NULL_HANDLE;
VkQueue graphicsQueue = VK_NULL_HANDLE;
VkQueue presentQueue = VK_NULL_HANDLE;
VkQueue computeQueue = VK_NULL_HANDLE;
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> computeFamily;
std::optional<uint32_t> presentFamily;
std::optional<uint32_t> graphicsAndComputeFamily;
bool isComplete() const {
return graphicsFamily.has_value() && computeFamily.has_value() && presentFamily.has_value();
return graphicsFamily.has_value() &&
computeFamily.has_value() &&
presentFamily.has_value() &&
graphicsAndComputeFamily.has_value();
}
std::set<uint32_t> uniqueQueueFamilies(){
return {graphicsFamily.value(), presentFamily.value(), computeFamily.value()};
return {
graphicsFamily.value(),
presentFamily.value(),
computeFamily.value(),
graphicsAndComputeFamily.value()
};
}
};
static QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface);

@ -22,9 +22,13 @@ std::vector<char> readFile(const std::string& fileName){
return buffer;
}
Pipeline::Pipeline() {
}
Pipeline::Pipeline(VkRenderPass renderPass) {
createDescriptorSetLayout();
createDescriptorPool();
createDescriptorPool(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
auto vertShaderCode = readFile("shaders/vert.spv");
auto fragShaderCode = readFile("shaders/frag.spv");
@ -178,10 +182,10 @@ void Pipeline::createDescriptorSetLayout() {
vkCreateDescriptorSetLayout(Instance::instance->device, &layoutCreateInfo, nullptr, &descriptorSetLayout);
}
void Pipeline::createDescriptorPool() {
void Pipeline::createDescriptorPool(VkDescriptorType type) {
VkDescriptorPoolSize poolSize {};
poolSize.descriptorCount = 1;
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSize.type = type;
VkDescriptorPoolCreateInfo poolInfo {};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
@ -192,7 +196,7 @@ void Pipeline::createDescriptorPool() {
vkCreateDescriptorPool(Instance::instance->device, &poolInfo, nullptr, &descriptorPool);
}
void Pipeline::createDescriptorSet(Buffer *buffer) {
void Pipeline::createDescriptorSet(Buffer *buffer, VkDescriptorType type) {
VkDescriptorSetAllocateInfo allocateInfo {};
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocateInfo.descriptorPool = descriptorPool;
@ -204,17 +208,60 @@ void Pipeline::createDescriptorSet(Buffer *buffer) {
VkDescriptorBufferInfo bufferInfo {};
bufferInfo.buffer = buffer->handle;
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject);
bufferInfo.range = buffer->size;
VkWriteDescriptorSet descriptorWrite {};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSet;
descriptorWrite.dstBinding = 0;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite.descriptorType = type;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(Instance::instance->device, 1, &descriptorWrite, 0, nullptr);
}
ComputePipeline::ComputePipeline(Buffer* buffer) {
{
VkDescriptorSetLayoutBinding layoutBinding {};
layoutBinding.binding = 0;
layoutBinding.descriptorCount = 1;
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
layoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo {};
descriptorSetLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutInfo.bindingCount = 1;
descriptorSetLayoutInfo.pBindings = &layoutBinding;
vkCreateDescriptorSetLayout(Instance::instance->device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout);
createDescriptorPool(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
createDescriptorSet(buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
}
VkShaderModule module = createShaderModule(readFile("shaders/comp.spv"));
VkPipelineShaderStageCreateInfo stageInfo {};
stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
stageInfo.pName = "main";
stageInfo.module = module;
VkPipelineLayoutCreateInfo layoutInfo {};
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layoutInfo.setLayoutCount = 1;
layoutInfo.pSetLayouts = &descriptorSetLayout;
vkCreatePipelineLayout(Instance::instance->device, &layoutInfo, nullptr, &layout);
VkComputePipelineCreateInfo pipelineInfo {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
pipelineInfo.layout = layout;
pipelineInfo.stage = stageInfo;
vkCreateComputePipelines(Instance::instance->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &handle);
vkDestroyShaderModule(Instance::instance->device, module, nullptr);
}

@ -15,19 +15,26 @@ struct UniformBufferObject {
class Pipeline {
public:
explicit Pipeline();
explicit Pipeline(VkRenderPass renderPass);
~Pipeline();
VkPipeline handle = VK_NULL_HANDLE;
VkPipelineLayout layout = VK_NULL_HANDLE;
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
void createDescriptorSet(Buffer* buffer);
private:
void createDescriptorSet(Buffer* buffer, VkDescriptorType type);
protected:
VkShaderModule createShaderModule(const std::vector<char> &code);
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
void createDescriptorSetLayout();
void createDescriptorPool();
void createDescriptorPool(VkDescriptorType type);
};
class ComputePipeline : public Pipeline {
public:
explicit ComputePipeline(Buffer* buffer);
};

@ -5,8 +5,8 @@
#include <array>
struct Vertex {
glm::vec3 pos;
glm::vec3 color;
alignas(16) glm::vec3 pos;
alignas(16) glm::vec3 color;
static VkVertexInputBindingDescription getBindingDescription();

Loading…
Cancel
Save