Skip to content
Snippets Groups Projects
Commit 6291921a authored by Tobias Frisch's avatar Tobias Frisch
Browse files

Merge branch '39-command-submit-interface' into 'develop'

Resolve "Command Submit Interface"

Closes #39

See merge request !31
parents e7f75019 a49c1c0c
No related branches found
No related tags found
1 merge request!31Resolve "Command Submit Interface"
Pipeline #25064 passed
#pragma once #pragma once
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <unordered_set>
#include "QueueManager.hpp"
namespace vkcv { namespace vkcv {
struct CommandResources { struct CommandResources {
vk::CommandPool commandPool; std::vector<vk::CommandPool> cmdPoolPerQueueFamily;
vk::CommandBuffer commandBuffer;
}; };
CommandResources createDefaultCommandResources(const vk::Device& device, const int graphicFamilyIndex); std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager& queueManager);
void destroyCommandResources(const vk::Device& device, const CommandResources& resources); CommandResources createCommandResources(const vk::Device& device, const std::unordered_set<int> &familyIndexSet);
void destroyCommandResources(const vk::Device& device, const CommandResources& resources);
vk::CommandBuffer allocateCommandBuffer(const vk::Device& device, const vk::CommandPool cmdPool);
vk::CommandPool chooseCmdPool(const Queue &queue, const CommandResources &cmdResources);
Queue getQueueForSubmit(const QueueType type, const QueueManager &queueManager);
void beginCommandBuffer(const vk::CommandBuffer cmdBuffer, const vk::CommandBufferUsageFlags flags);
void submitCommandBufferToQueue(
const vk::Queue queue,
const vk::CommandBuffer cmdBuffer,
const vk::Fence fence,
const std::vector<vk::Semaphore>& waitSemaphores,
const std::vector<vk::Semaphore>& signalSemaphores);
} }
\ No newline at end of file
...@@ -24,6 +24,15 @@ namespace vkcv ...@@ -24,6 +24,15 @@ namespace vkcv
class PassManager; class PassManager;
class PipelineManager; class PipelineManager;
struct SubmitInfo {
QueueType queueType;
std::vector<vk::Semaphore> waitSemaphores;
std::vector<vk::Semaphore> signalSemaphores;
};
typedef std::function<void(const vk::CommandBuffer& cmdBuffer)> RecordCommandFunction;
typedef std::function<void(void)> FinishCommandFunction;
class Core final class Core final
{ {
private: private:
...@@ -172,5 +181,16 @@ namespace vkcv ...@@ -172,5 +181,16 @@ namespace vkcv
void endFrame(); void endFrame();
vk::Format getSwapchainImageFormat(); vk::Format getSwapchainImageFormat();
/**
* Submit a command buffer to any queue of selected type. The recording can be customized by a
* custom record-command-function. If the command submission has finished, an optional finish-function
* will be called.
*
* @param submitInfo Submit information
* @param record Record-command-function
* @param finish Finish-command-function or nullptr
*/
void submitCommands(const SubmitInfo &submitInfo, const RecordCommandFunction& record, const FinishCommandFunction& finish);
}; };
} }
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
namespace vkcv { namespace vkcv {
enum class QueueType { Compute, Transfer, Graphics, Present };
struct Queue { struct Queue {
int familyIndex; int familyIndex;
int queueIndex; int queueIndex;
......
...@@ -3,11 +3,13 @@ ...@@ -3,11 +3,13 @@
namespace vkcv { namespace vkcv {
struct SyncResources { struct SyncResources {
vk::Semaphore renderFinished; vk::Semaphore renderFinished;
vk::Fence swapchainImageAcquired; vk::Semaphore swapchainImageAcquired;
vk::Fence presentFinished; vk::Fence presentFinished;
}; };
SyncResources createDefaultSyncResources(const vk::Device& device); SyncResources createSyncResources(const vk::Device &device);
void destroySyncResources(const vk::Device& device, const SyncResources& resources); void destroySyncResources(const vk::Device &device, const SyncResources &resources);
vk::Fence createFence(const vk::Device &device);
void waitForFence(const vk::Device& device, const vk::Fence fence);
} }
\ No newline at end of file
...@@ -16,30 +16,6 @@ int main(int argc, const char** argv) { ...@@ -16,30 +16,6 @@ int main(int argc, const char** argv) {
false false
); );
// showing basic usage lambda events of window
window.e_mouseMove.add([&](double x, double y){
std::cout << "movement: " << x << " , " << y << std::endl;
});
window.e_key.add([&](int key, int scancode, int action, int mods){
switch (key) {
case GLFW_KEY_W:
std::cout << "Move forward" << std::endl;
break;
case GLFW_KEY_A:
std::cout << "Move left" << std::endl;
break;
case GLFW_KEY_S:
std::cout << "Move backward" << std::endl;
break;
case GLFW_KEY_D:
std::cout << "Move right" << std::endl;
break;
default:
std::cout << "this key is not supported yet: " << std::endl;
}
});
window.initEvents(); window.initEvents();
vkcv::Core core = vkcv::Core::create( vkcv::Core core = vkcv::Core::create(
......
#include "vkcv/CommandResources.hpp" #include "vkcv/CommandResources.hpp"
#include <iostream>
namespace vkcv { namespace vkcv {
CommandResources createDefaultCommandResources(const vk::Device& device, const int graphicFamilyIndex) {
std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager &queueManager) {
std::unordered_set<int> indexSet;
for (const auto& queue : queueManager.getGraphicsQueues()) {
indexSet.insert(queue.familyIndex);
}
for (const auto& queue : queueManager.getComputeQueues()) {
indexSet.insert(queue.familyIndex);
}
for (const auto& queue : queueManager.getTransferQueues()) {
indexSet.insert(queue.familyIndex);
}
indexSet.insert(queueManager.getPresentQueue().familyIndex);
return indexSet;
}
CommandResources createCommandResources(const vk::Device& device, const std::unordered_set<int>& familyIndexSet) {
CommandResources resources; CommandResources resources;
vk::CommandPoolCreateFlags flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer; const size_t queueFamiliesCount = familyIndexSet.size();
vk::CommandPoolCreateInfo poolCreateInfo(flags, graphicFamilyIndex); resources.cmdPoolPerQueueFamily.resize(queueFamiliesCount);
resources.commandPool = device.createCommandPool(poolCreateInfo, nullptr, {});
const int commandPoolCount = 1; const vk::CommandPoolCreateFlags poolFlags = vk::CommandPoolCreateFlagBits::eTransient;
vk::CommandBufferAllocateInfo allocateInfo(resources.commandPool, vk::CommandBufferLevel::ePrimary, commandPoolCount); for (const int familyIndex : familyIndexSet) {
const std::vector<vk::CommandBuffer> createdBuffers = device.allocateCommandBuffers(allocateInfo, {}); const vk::CommandPoolCreateInfo poolCreateInfo(poolFlags, familyIndex);
assert(createdBuffers.size() == 1); resources.cmdPoolPerQueueFamily[familyIndex] = device.createCommandPool(poolCreateInfo, nullptr, {});
resources.commandBuffer = createdBuffers[0]; }
return resources; return resources;
} }
void destroyCommandResources(const vk::Device& device, const CommandResources& resources) { void destroyCommandResources(const vk::Device& device, const CommandResources& resources) {
device.freeCommandBuffers(resources.commandPool, resources.commandBuffer, {}); for (const vk::CommandPool &pool : resources.cmdPoolPerQueueFamily) {
device.destroyCommandPool(resources.commandPool, {}); device.destroyCommandPool(pool);
}
}
vk::CommandBuffer allocateCommandBuffer(const vk::Device& device, const vk::CommandPool cmdPool) {
const vk::CommandBufferAllocateInfo info(cmdPool, vk::CommandBufferLevel::ePrimary, 1);
return device.allocateCommandBuffers(info).front();
}
vk::CommandPool chooseCmdPool(const Queue& queue, const CommandResources& cmdResources) {
return cmdResources.cmdPoolPerQueueFamily[queue.familyIndex];
}
Queue getQueueForSubmit(const QueueType type, const QueueManager& queueManager) {
if (type == QueueType::Graphics) {
return queueManager.getGraphicsQueues().front();
}
else if (type == QueueType::Compute) {
return queueManager.getComputeQueues().front();
}
else if (type == QueueType::Transfer) {
return queueManager.getTransferQueues().front();
}
else if (type == QueueType::Present) {
return queueManager.getPresentQueue();
}
else {
std::cerr << "getQueueForSubmit error: unknown queue type" << std::endl;
return queueManager.getGraphicsQueues().front(); // graphics is the most general queue
}
}
void beginCommandBuffer(const vk::CommandBuffer cmdBuffer, const vk::CommandBufferUsageFlags flags) {
const vk::CommandBufferBeginInfo beginInfo(flags);
cmdBuffer.begin(beginInfo);
}
void submitCommandBufferToQueue(
const vk::Queue queue,
const vk::CommandBuffer cmdBuffer,
const vk::Fence fence,
const std::vector<vk::Semaphore>& waitSemaphores,
const std::vector<vk::Semaphore>& signalSemaphores) {
const std::vector<vk::PipelineStageFlags> waitDstStageMasks(waitSemaphores.size(), vk::PipelineStageFlagBits::eAllCommands);
const vk::SubmitInfo queueSubmitInfo(waitSemaphores, waitDstStageMasks, cmdBuffer, signalSemaphores);
queue.submit(queueSubmitInfo, fence);
} }
} }
\ No newline at end of file
...@@ -66,15 +66,16 @@ namespace vkcv ...@@ -66,15 +66,16 @@ namespace vkcv
const auto& queueManager = context.getQueueManager(); const auto& queueManager = context.getQueueManager();
const int graphicQueueFamilyIndex = queueManager.getGraphicsQueues()[0].familyIndex; const int graphicQueueFamilyIndex = queueManager.getGraphicsQueues()[0].familyIndex;
const auto defaultCommandResources = createDefaultCommandResources(context.getDevice(), graphicQueueFamilyIndex); const std::unordered_set<int> queueFamilySet = generateQueueFamilyIndexSet(queueManager);
const auto defaultSyncResources = createDefaultSyncResources(context.getDevice()); const auto commandResources = createCommandResources(context.getDevice(), queueFamilySet);
const auto defaultSyncResources = createSyncResources(context.getDevice());
window.e_resize.add([&](int width, int height){ window.e_resize.add([&](int width, int height){
recreateSwapchain(width,height); recreateSwapchain(width,height);
}); });
return Core(std::move(context) , window, swapChain, imageViews, defaultCommandResources, defaultSyncResources); return Core(std::move(context) , window, swapChain, imageViews, commandResources, defaultSyncResources);
} }
const Context &Core::getContext() const const Context &Core::getContext() const
...@@ -124,25 +125,17 @@ namespace vkcv ...@@ -124,25 +125,17 @@ namespace vkcv
uint32_t imageIndex; uint32_t imageIndex;
const auto& acquireResult = m_Context.getDevice().acquireNextImageKHR( const auto& acquireResult = m_Context.getDevice().acquireNextImageKHR(
m_swapchain.getSwapchain(), std::numeric_limits<uint64_t>::max(), nullptr, m_swapchain.getSwapchain(),
m_SyncResources.swapchainImageAcquired, &imageIndex, {} std::numeric_limits<uint64_t>::max(),
m_SyncResources.swapchainImageAcquired,
nullptr,
&imageIndex, {}
); );
if (acquireResult != vk::Result::eSuccess) { if (acquireResult != vk::Result::eSuccess) {
return Result::ERROR; return Result::ERROR;
} }
const auto& result = m_Context.getDevice().waitForFences(
m_SyncResources.swapchainImageAcquired, true,
std::numeric_limits<uint64_t>::max()
);
m_Context.getDevice().resetFences(m_SyncResources.swapchainImageAcquired);
if (result != vk::Result::eSuccess) {
return Result::ERROR;
}
m_currentSwapchainImageIndex = imageIndex; m_currentSwapchainImageIndex = imageIndex;
return Result::SUCCESS; return Result::SUCCESS;
} }
...@@ -161,9 +154,6 @@ namespace vkcv ...@@ -161,9 +154,6 @@ namespace vkcv
m_window.pollEvents(); m_window.pollEvents();
m_Context.getDevice().waitIdle(); // FIMXE: this is a sin against graphics programming, but its getting late - Alex m_Context.getDevice().waitIdle(); // FIMXE: this is a sin against graphics programming, but its getting late - Alex
destroyTemporaryFramebuffers(); destroyTemporaryFramebuffers();
const vk::CommandBufferUsageFlags beginFlags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
const vk::CommandBufferBeginInfo beginInfos(beginFlags);
m_CommandResources.commandBuffer.begin(beginInfos);
} }
void Core::renderTriangle(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, void Core::renderTriangle(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle,
...@@ -171,22 +161,31 @@ namespace vkcv ...@@ -171,22 +161,31 @@ namespace vkcv
if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
return; return;
} }
const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle);
const std::array<float, 4> clearColor = { 0.f, 0.f, 0.f, 1.f }; const vk::ImageView imageView = m_swapchainImageViews[m_currentSwapchainImageIndex];
const vk::ClearValue clearValues(clearColor); const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle);
const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height));
const vk::ImageView imageView = m_swapchainImageViews[m_currentSwapchainImageIndex];
const vk::Framebuffer framebuffer = createFramebuffer(m_Context.getDevice(), renderpass, width, height, imageView); const vk::Framebuffer framebuffer = createFramebuffer(m_Context.getDevice(), renderpass, width, height, imageView);
m_TemporaryFramebuffers.push_back(framebuffer); m_TemporaryFramebuffers.push_back(framebuffer);
const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, 1, &clearValues);
const vk::SubpassContents subpassContents = {}; SubmitInfo submitInfo;
m_CommandResources.commandBuffer.beginRenderPass(beginInfo, subpassContents, {}); submitInfo.queueType = QueueType::Graphics;
submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline](const vk::CommandBuffer& cmdBuffer) {
m_CommandResources.commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
m_CommandResources.commandBuffer.draw(3, 1, 0, 0, {}); const std::array<float, 4> clearColor = { 0.f, 0.f, 0.f, 1.f };
m_CommandResources.commandBuffer.endRenderPass(); const vk::ClearValue clearValues(clearColor);
const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, 1, &clearValues);
const vk::SubpassContents subpassContents = {};
cmdBuffer.beginRenderPass(beginInfo, subpassContents, {});
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
cmdBuffer.draw(3, 1, 0, 0, {});
cmdBuffer.endRenderPass();
}, nullptr);
} }
void Core::endFrame() { void Core::endFrame() {
...@@ -196,18 +195,19 @@ namespace vkcv ...@@ -196,18 +195,19 @@ namespace vkcv
const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain());
const vk::Image presentImage = swapchainImages[m_currentSwapchainImageIndex]; const vk::Image presentImage = swapchainImages[m_currentSwapchainImageIndex];
m_CommandResources.commandBuffer.end();
const auto& queueManager = m_Context.getQueueManager(); const auto& queueManager = m_Context.getQueueManager();
std::array<vk::Semaphore, 2> waitSemaphores{
const vk::SubmitInfo submitInfo(0, nullptr, 0, 1, &(m_CommandResources.commandBuffer), 1, &m_SyncResources.renderFinished); m_SyncResources.renderFinished,
queueManager.getGraphicsQueues()[0].handle.submit(submitInfo); m_SyncResources.swapchainImageAcquired };
vk::Result presentResult; vk::Result presentResult;
const vk::SwapchainKHR& swapchain = m_swapchain.getSwapchain(); const vk::SwapchainKHR& swapchain = m_swapchain.getSwapchain();
const vk::PresentInfoKHR presentInfo(1, &m_SyncResources.renderFinished, 1, &swapchain, const vk::PresentInfoKHR presentInfo(
&m_currentSwapchainImageIndex, &presentResult); waitSemaphores,
swapchain,
m_currentSwapchainImageIndex,
presentResult);
queueManager.getPresentQueue().handle.presentKHR(presentInfo); queueManager.getPresentQueue().handle.presentKHR(presentInfo);
if (presentResult != vk::Result::eSuccess) { if (presentResult != vk::Result::eSuccess) {
std::cout << "Error: swapchain present failed" << std::endl; std::cout << "Error: swapchain present failed" << std::endl;
...@@ -222,4 +222,28 @@ namespace vkcv ...@@ -222,4 +222,28 @@ namespace vkcv
/* boilerplate for #34 */ /* boilerplate for #34 */
std::cout << "Resized to : " << width << " , " << height << std::endl; std::cout << "Resized to : " << width << " , " << height << std::endl;
} }
void Core::submitCommands(const SubmitInfo &submitInfo, const RecordCommandFunction& record, const FinishCommandFunction& finish)
{
const vk::Device& device = m_Context.getDevice();
const vkcv::Queue queue = getQueueForSubmit(submitInfo.queueType, m_Context.getQueueManager());
const vk::CommandPool cmdPool = chooseCmdPool(queue, m_CommandResources);
const vk::CommandBuffer cmdBuffer = allocateCommandBuffer(device, cmdPool);
beginCommandBuffer(cmdBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
record(cmdBuffer);
cmdBuffer.end();
const vk::Fence waitFence = createFence(device);
submitCommandBufferToQueue(queue.handle, cmdBuffer, waitFence, submitInfo.waitSemaphores, submitInfo.signalSemaphores);
waitForFence(device, waitFence);
device.destroyFence(waitFence);
device.freeCommandBuffers(cmdPool, cmdBuffer);
if (finish) {
finish();
}
}
} }
#include "vkcv/SyncResources.hpp" #include "vkcv/SyncResources.hpp"
namespace vkcv { namespace vkcv {
SyncResources createDefaultSyncResources(const vk::Device& device) { SyncResources createSyncResources(const vk::Device& device) {
SyncResources resources; SyncResources resources;
const vk::SemaphoreCreateFlags semaphoreFlags = vk::SemaphoreCreateFlagBits(); const vk::SemaphoreCreateFlags semaphoreFlags = vk::SemaphoreCreateFlagBits();
const vk::SemaphoreCreateInfo semaphoreInfo(semaphoreFlags); const vk::SemaphoreCreateInfo semaphoreInfo(semaphoreFlags);
resources.renderFinished = device.createSemaphore(semaphoreInfo, nullptr, {}); resources.renderFinished = device.createSemaphore(semaphoreInfo, nullptr, {});
resources.swapchainImageAcquired = device.createSemaphore(semaphoreInfo);
const vk::FenceCreateFlags fenceFlags = vk::FenceCreateFlagBits();
vk::FenceCreateInfo fenceInfo(fenceFlags);
resources.presentFinished = device.createFence(fenceInfo, nullptr, {});
resources.swapchainImageAcquired = device.createFence(fenceInfo, nullptr, {});
resources.presentFinished = createFence(device);
return resources; return resources;
} }
void destroySyncResources(const vk::Device& device, const SyncResources& resources) { void destroySyncResources(const vk::Device& device, const SyncResources& resources) {
device.destroySemaphore(resources.renderFinished); device.destroySemaphore(resources.renderFinished);
device.destroySemaphore(resources.swapchainImageAcquired);
device.destroyFence(resources.presentFinished); device.destroyFence(resources.presentFinished);
device.destroyFence(resources.swapchainImageAcquired); }
vk::Fence createFence(const vk::Device& device) {
const vk::FenceCreateFlags fenceFlags = vk::FenceCreateFlagBits();
vk::FenceCreateInfo fenceInfo(fenceFlags);
return device.createFence(fenceInfo, nullptr, {});
}
void waitForFence(const vk::Device& device, const vk::Fence fence) {
const auto result = device.waitForFences(fence, true, UINT64_MAX);
assert(result == vk::Result::eSuccess);
} }
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment